зеркало из https://github.com/mozilla/FlightDeck.git
Merge pull request #121 from pennyfx/broken_packages_fix
Broken packages fix
This commit is contained in:
Коммит
20db544f7d
|
@ -1536,25 +1536,25 @@ class Package(BaseModel, SearchMixin):
|
|||
return self.save(iteration=iteration, **kwargs)
|
||||
|
||||
# a common error here is "Full Name and Author already exists"
|
||||
elif ('__all__' in err and
|
||||
'Package with this Author and Name already exists.' in err['__all__']):
|
||||
elif ('__all__' in err.message_dict and
|
||||
'Package with this Author and Name already exists.' in err.message_dict['__all__']):
|
||||
log.warning('[save] name conflict (%s), trying again with new name'
|
||||
% self.name)
|
||||
self.full_name = None
|
||||
self.name = None
|
||||
return self.save()
|
||||
else:
|
||||
return self.save()
|
||||
else:
|
||||
log.error('[save] Save package validation error: %s', str(err))
|
||||
raise
|
||||
|
||||
except IntegrityError, err:
|
||||
# if id_number exists we should try again
|
||||
|
||||
|
||||
if 'id_number' in err[1]:
|
||||
self.id_number = str(int(self.id_number) + 1)
|
||||
iteration += 1
|
||||
log.debug('[save] IntegrityError - new id_number %s' % self.id_number)
|
||||
return self.save(iteration=iteration, **kwargs)
|
||||
return self.save(iteration=iteration, **kwargs)
|
||||
else:
|
||||
log.error('[save] Save package IntegrityError error: %s', str(err))
|
||||
raise
|
||||
|
@ -1748,7 +1748,7 @@ class Package(BaseModel, SearchMixin):
|
|||
"""
|
||||
if self.full_name:
|
||||
return
|
||||
|
||||
|
||||
username = self.author.username
|
||||
if self.author.get_profile():
|
||||
username = self.author.get_profile().nickname or username
|
||||
|
|
|
@ -49,9 +49,13 @@ class PackageTest(TestCase):
|
|||
author=self.author,
|
||||
type='a',
|
||||
full_name=package.name)
|
||||
self.assertRaises(ValidationError, Package.objects.create,
|
||||
author=self.author, type='a', full_name=package.name)
|
||||
|
||||
p = Package.objects.create(author=self.author, type='a', full_name=package.name)
|
||||
|
||||
#test package name iteration
|
||||
eq_('john-1', p.name)
|
||||
eq_('john', package.name)
|
||||
|
||||
|
||||
def test_addon_creation_with_nickname(self):
|
||||
"""In production if you log in with an AMO user, the username
|
||||
is set to a number and the nickname on the profile is set to the
|
||||
|
@ -59,32 +63,32 @@ class PackageTest(TestCase):
|
|||
profile = self.author.get_profile()
|
||||
profile.nickname = 'Gordon'
|
||||
profile.save()
|
||||
|
||||
|
||||
package = Package(
|
||||
author=self.author,
|
||||
type='a'
|
||||
)
|
||||
package.save()
|
||||
|
||||
|
||||
eq_(package.full_name, 'Gordon')
|
||||
|
||||
|
||||
def test_library_creation_with_nickname(self):
|
||||
profile = self.author.get_profile()
|
||||
profile.nickname = 'Samuel'
|
||||
profile.save()
|
||||
|
||||
|
||||
package = Package(
|
||||
author=self.author,
|
||||
type='l'
|
||||
)
|
||||
package.save()
|
||||
|
||||
|
||||
eq_(package.full_name, 'Samuel-lib')
|
||||
|
||||
|
||||
def test_package_sanitization(self):
|
||||
bad_text = 'Te$t"><script src="google.com"></script>!#'
|
||||
good_text = 'Te$tscript srcgoogle.com/script!#'
|
||||
|
||||
|
||||
package = Package(
|
||||
author=self.author,
|
||||
type='a',
|
||||
|
@ -93,11 +97,11 @@ class PackageTest(TestCase):
|
|||
version_name=bad_text
|
||||
)
|
||||
package.save()
|
||||
|
||||
|
||||
eq_(package.full_name, good_text)
|
||||
eq_(package.description, good_text)
|
||||
eq_(package.version_name, good_text)
|
||||
|
||||
|
||||
def test_automatic_numbering(self):
|
||||
Package(
|
||||
author=self.author,
|
||||
|
@ -110,7 +114,7 @@ class PackageTest(TestCase):
|
|||
)
|
||||
package.save()
|
||||
self.assertEqual(package.full_name, '%s (1)' % self.author.username)
|
||||
|
||||
|
||||
def test_ordering(self):
|
||||
" Newest is first "
|
||||
addon1 = Package(author=self.author, type='a')
|
||||
|
@ -124,41 +128,41 @@ class PackageTest(TestCase):
|
|||
names = (addon1.full_name, addon2.full_name)
|
||||
self.failUnless('%s (1)' % self.author.username in names)
|
||||
self.failUnless('%s' % self.author.username in names)
|
||||
|
||||
|
||||
def test_manager_filtering(self):
|
||||
Package(author=self.author, type='a').save()
|
||||
Package(author=self.author, type='a').save()
|
||||
Package(author=self.author, type='l').save()
|
||||
|
||||
|
||||
self.assertEqual(Package.objects.addons().count(), 2)
|
||||
self.assertEqual(Package.objects.libraries().count(), 3)
|
||||
|
||||
|
||||
def test_manager_sort_recently_active(self):
|
||||
p1 = Package(author=self.author, type='a')
|
||||
p1.save()
|
||||
p2 = Package(author=self.author, type='a')
|
||||
p2.save()
|
||||
Package(author=self.author, type='l').save()
|
||||
|
||||
|
||||
|
||||
|
||||
p1rev2 = PackageRevision(author=self.author, revision_number=2)
|
||||
p1.revisions.add(p1rev2)
|
||||
p1rev2.created_at = datetime.datetime.now() - datetime.timedelta(60)
|
||||
super(PackageRevision, p1rev2).save()
|
||||
|
||||
|
||||
p2rev = p2.revisions.all()[0]
|
||||
p2rev.save() #makes a new revision
|
||||
|
||||
|
||||
qs = Package.objects.sort_recently_active().filter(type='a')
|
||||
eq_(qs.count(), 2)
|
||||
eq_(p2.id, qs[0].id)
|
||||
eq_(qs[0].rev_count, 2)
|
||||
eq_(qs[1].rev_count, 1)
|
||||
|
||||
|
||||
def test_related_name(self):
|
||||
Package(author=self.author, type='a').save()
|
||||
self.assertEqual(self.author.packages_originated.count(), 1)
|
||||
|
||||
|
||||
def test_create_adddon_from_archive(self):
|
||||
path_addon = os.path.join(
|
||||
settings.ROOT, 'apps/jetpack/tests/sample_addon.zip')
|
||||
|
@ -171,7 +175,7 @@ class PackageTest(TestCase):
|
|||
'main' in [m.filename for m in addon.latest.modules.all()])
|
||||
self.failUnless(('attachment', 'txt') in [(a.filename, a.ext)
|
||||
for a in addon.latest.attachments.all()])
|
||||
|
||||
|
||||
def test_create_library_from_archive(self):
|
||||
path_library = os.path.join(
|
||||
settings.ROOT, 'apps/jetpack/tests/sample_library.zip')
|
||||
|
@ -184,7 +188,7 @@ class PackageTest(TestCase):
|
|||
for m in library.latest.modules.all()])
|
||||
self.failUnless(('attachment', 'txt') in [(a.filename, a.ext)
|
||||
for a in library.latest.attachments.all()])
|
||||
|
||||
|
||||
def test_create_addon_from_xpi(self):
|
||||
path_xpi = os.path.join(
|
||||
settings.ROOT, 'apps/jetpack/tests/sample_addon.xpi')
|
||||
|
@ -197,7 +201,7 @@ class PackageTest(TestCase):
|
|||
'main' in [m.filename for m in addon.latest.modules.all()])
|
||||
self.failUnless(('attachment', 'txt') in [(a.filename, a.ext)
|
||||
for a in addon.latest.attachments.all()])
|
||||
|
||||
|
||||
def test_update_addon_from_xpi(self):
|
||||
path_xpi = os.path.join(
|
||||
settings.ROOT, 'apps/jetpack/tests/sample_addon.xpi')
|
||||
|
@ -205,13 +209,13 @@ class PackageTest(TestCase):
|
|||
addon = create_package_from_xpi(path_xpi, self.author)
|
||||
self.failUnless(addon)
|
||||
eq_(addon.revisions.count(), 2)
|
||||
|
||||
|
||||
def test_create_addon_from_xpi_with_libs(self):
|
||||
libs = ['sample_library']
|
||||
path_xpi = os.path.join(
|
||||
settings.ROOT, 'apps/jetpack/tests/sample_addon_with_libs.xpi')
|
||||
addon = create_package_from_xpi(path_xpi, self.author, libs=libs)
|
||||
|
||||
|
||||
eq_(len(addon.latest.dependencies.all()), 1)
|
||||
lib = addon.latest.dependencies.all()[0]
|
||||
self.failUnless(lib.package.name in libs)
|
||||
|
@ -220,7 +224,7 @@ class PackageTest(TestCase):
|
|||
eq_(('attachment', 'txt'), (att.filename, att.ext))
|
||||
self.failUnless(os.path.isfile(
|
||||
os.path.join(settings.UPLOAD_DIR, att.path)))
|
||||
|
||||
|
||||
def test_disable(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
# disabling addon
|
||||
|
@ -228,13 +232,13 @@ class PackageTest(TestCase):
|
|||
eq_(Package.objects.active().filter(type='a').count(), 0)
|
||||
eq_(Package.objects.active(viewer=self.author).filter(type='a').count(), 1)
|
||||
return addon
|
||||
|
||||
|
||||
def test_enable(self):
|
||||
addon = self.test_disable()
|
||||
|
||||
|
||||
addon.enable()
|
||||
eq_(Package.objects.active().filter(type='a').count(), 1)
|
||||
|
||||
|
||||
def test_delete(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
# deleting addon
|
||||
|
@ -242,7 +246,7 @@ class PackageTest(TestCase):
|
|||
eq_(Package.objects.active().filter(type='a').count(), 0)
|
||||
eq_(Package.objects.active(viewer=self.author).filter(type='a').count(), 0)
|
||||
eq_(PackageRevision.objects.filter(package=addon).count(), 0)
|
||||
|
||||
|
||||
def test_delete_with_a_copy(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
addon_copy = addon.copy(self.author)
|
||||
|
@ -254,7 +258,7 @@ class PackageTest(TestCase):
|
|||
eq_(Package.objects.active(viewer=self.author).addons().count(), 1)
|
||||
eq_(PackageRevision.objects.filter(package=addon).count(), 0)
|
||||
eq_(PackageRevision.objects.filter(package=addon_copy).count(), 1)
|
||||
|
||||
|
||||
def test_delete_with_dependency(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
lib = Package.objects.create(author=self.author, type='l')
|
||||
|
@ -263,70 +267,70 @@ class PackageTest(TestCase):
|
|||
lib.delete()
|
||||
eq_(Package.objects.addons().active().count(), 1)
|
||||
eq_(Package.objects.libraries().active().filter(author=self.author).count(), 0)
|
||||
|
||||
|
||||
def test_get_outdated_dependencies(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
lib = Package.objects.create(author=self.author, type='l')
|
||||
addon.latest.dependency_add(lib.latest)
|
||||
|
||||
|
||||
lib.latest.module_create(author=self.author, filename='test', code='foo')
|
||||
|
||||
|
||||
out_of_date = addon.latest.get_outdated_dependency_versions()
|
||||
eq_(len(out_of_date), 1)
|
||||
|
||||
|
||||
def test_outdated_dependencies_with_conflicts(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
lib = Package.objects.create(author=self.author, type='l')
|
||||
addon.latest.dependency_add(lib.latest)
|
||||
|
||||
|
||||
jan = User.objects.get(username='jan')
|
||||
jan_lib = Package(author=jan, type='l', full_name='janjanjan')
|
||||
jan_lib.save()
|
||||
dupe_lib = Package(author=jan, type='l', full_name=lib.full_name)
|
||||
dupe_lib.save()
|
||||
|
||||
|
||||
addon.latest.dependency_add(jan_lib.latest)
|
||||
|
||||
|
||||
jan_lib.latest.dependency_add(dupe_lib.latest)
|
||||
out_of_date = addon.latest.get_outdated_dependency_versions()
|
||||
|
||||
|
||||
eq_(len(out_of_date), 0)
|
||||
|
||||
|
||||
def test_update_dependency_version(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
lib = Package.objects.create(author=self.author, type='l')
|
||||
addon.latest.dependency_add(lib.latest)
|
||||
|
||||
|
||||
lib.latest.module_create(author=self.author, filename='test', code='foo')
|
||||
|
||||
|
||||
previous_addon = addon.latest.pk
|
||||
addon.latest.dependency_update(lib.latest)
|
||||
|
||||
|
||||
self.assertNotEqual(addon.latest.pk, previous_addon)
|
||||
eq_(addon.latest.dependencies.get(package=lib), lib.latest)
|
||||
|
||||
|
||||
def test_update_invalid_dependency(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
lib = Package.objects.create(author=self.author, type='l')
|
||||
|
||||
|
||||
self.assertRaises(DependencyException,
|
||||
addon.latest.dependency_update,
|
||||
lib.latest)
|
||||
|
||||
|
||||
def test_package_copy(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
addon_copy = addon.copy(author=self.author)
|
||||
assert "(copy 1)" in addon_copy.full_name
|
||||
|
||||
|
||||
addon_copy = addon.copy(author=self.author)
|
||||
assert "(copy 1)" not in addon_copy.full_name
|
||||
assert "(copy 2)" in addon_copy.full_name
|
||||
|
||||
|
||||
addon_copy = addon.copy(author=self.author)
|
||||
assert "(copy 1)" not in addon_copy.full_name
|
||||
assert "(copy 2)" not in addon_copy.full_name
|
||||
assert "(copy 3)" in addon_copy.full_name
|
||||
|
||||
|
||||
def test_create_anew_id_number_if_current_exists(self):
|
||||
full_clean = Package.full_clean
|
||||
Package.full_clean = Mock()
|
||||
|
@ -335,7 +339,7 @@ class PackageTest(TestCase):
|
|||
addon2.id_number = addon.id_number
|
||||
addon2.save()
|
||||
Package.full_clean = full_clean
|
||||
|
||||
|
||||
def test_description_characters(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
description = "abcdefghijklmnoprstuwxyz!@#$%^&*(){}[]:',./?"
|
||||
|
@ -343,43 +347,43 @@ class PackageTest(TestCase):
|
|||
addon.save()
|
||||
addon_saved = Package.objects.get(author=self.author, type='a')
|
||||
eq_(addon_saved.description, description)
|
||||
|
||||
|
||||
def test_activity_rating_calculation_one_year(self):
|
||||
addon = Package.objects.create(author=self.author, type='a')
|
||||
|
||||
|
||||
eq_(0, addon.calc_activity_rating())
|
||||
|
||||
|
||||
now = datetime.datetime.now()
|
||||
|
||||
|
||||
for i in range(1, 366):
|
||||
r = addon.revisions.create(author=self.author, revision_number=i)
|
||||
r.created_at = now-datetime.timedelta(i)
|
||||
super(PackageRevision, r).save()
|
||||
|
||||
|
||||
|
||||
|
||||
#created packages, including initial
|
||||
eq_(366, addon.revisions.count())
|
||||
eq_(Decimal('1'), addon.calc_activity_rating())
|
||||
|
||||
|
||||
def test_activity_rating_calculation_first_week(self):
|
||||
addon = Package.objects.create(type='a', author=self.author)
|
||||
|
||||
|
||||
eq_(0, addon.calc_activity_rating())
|
||||
|
||||
|
||||
now = datetime.datetime.now()
|
||||
|
||||
|
||||
# Create 1 weeks worth of revisions... should equal .30 of score
|
||||
# see models.py def Packages for weights
|
||||
|
||||
|
||||
for i in range(1, 8):
|
||||
r = addon.revisions.create(author=self.author, revision_number=i)
|
||||
r.created_at = now-datetime.timedelta(i)
|
||||
super(PackageRevision, r).save()
|
||||
|
||||
|
||||
eq_(8, addon.revisions.count())
|
||||
|
||||
|
||||
eq_(Decimal('0.300'), addon.calc_activity_rating())
|
||||
|
||||
|
||||
def test_duplicate_packages_integrity_error(self):
|
||||
# duplicate packages are denied on MySQL level
|
||||
author = User.objects.get(username='john')
|
||||
|
@ -394,3 +398,29 @@ class PackageTest(TestCase):
|
|||
author=author, type='a')
|
||||
self.assertRaises(IntegrityError, addon2.save)
|
||||
Package.full_clean = backup
|
||||
|
||||
|
||||
def test_duplicate_packages_name_interation(self):
|
||||
# duplicate packages are denied on MySQL level
|
||||
author = User.objects.get(username='john')
|
||||
addon = Package(
|
||||
full_name='Integrity Error',
|
||||
author=author, type='a')
|
||||
addon.save()
|
||||
eq_(addon.latest.name, 'integrity-error')
|
||||
|
||||
addon2 = Package(
|
||||
full_name='Integrity Error',
|
||||
author=author, type='a')
|
||||
|
||||
addon2.save()
|
||||
eq_(addon2.latest.name, 'john')
|
||||
|
||||
addon3 = Package(
|
||||
full_name='Integrity Error',
|
||||
author=author, type='a')
|
||||
|
||||
addon3.save()
|
||||
eq_(addon3.latest.name, 'john-1')
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE jetpack_package ADD UNIQUE INDEX full_name_author_id (full_name, author_id);
|
Загрузка…
Ссылка в новой задаче