def test_extract_version_and_files(self): version = self.addon.current_version file_factory(version=version, platform=PLATFORM_MAC.id) current_beta_version = version_factory( addon=self.addon, file_kw={ 'status': amo.STATUS_BETA, 'is_webextension': True, 'is_mozilla_signed_extension': True, }) # Give one of the versions some webext permissions to test that. WebextPermission.objects.create( file=current_beta_version.all_files[0], permissions=['bookmarks', 'random permission'] ) unlisted_version = version_factory( addon=self.addon, channel=amo.RELEASE_CHANNEL_UNLISTED) extracted = self._extract() assert extracted['current_version'] assert extracted['current_version']['id'] == version.pk # Because strict_compatibility is False, the max version we record in # the index is an arbitrary super high version. assert extracted['current_version']['compatible_apps'] == { FIREFOX.id: { 'min': 2000000200100L, 'max': 9999000000200100, 'max_human': '4.0', 'min_human': '2.0', } }
def test_only_first_file(self, extract_mock): addon = addon_factory(file_kw={'filename': 'webextension_no_id.xpi'}) version = addon.current_version first_file = version.all_files[0] file_factory(version=version) file_factory(version=version) migrate_webextensions_to_git_storage([addon.pk]) extract_mock.assert_called_once_with( first_file.pk, amo.RELEASE_CHANNEL_LISTED)
def test_version_compatibility_with_strict_compatibility_enabled(self): version = self.addon.current_version file_factory( version=version, platform=PLATFORM_MAC.id, strict_compatibility=True) extracted = self._extract() assert extracted['current_version']['compatible_apps'] == { FIREFOX.id: { 'min': 2000000200100, 'max': 4000000200100, 'max_human': '4.0', 'min_human': '2.0', } }
def test_doesnt_remove_non_empty_directories(self): # Add an extra disabled file. The approved one should move, but not the # other, so the directory should be left intact. self.disabled_file = file_factory( version=self.version, status=amo.STATUS_DISABLED) self.addon.update(status=amo.STATUS_APPROVED) self.file_.update(status=amo.STATUS_APPROVED) with storage.open(self.file_.guarded_file_path, 'wb') as fp: fp.write(b'content') assert not storage.exists(self.file_.file_path) assert storage.exists(self.file_.guarded_file_path) with storage.open(self.disabled_file.guarded_file_path, 'wb') as fp: fp.write(b'disabled content') assert not storage.exists(self.disabled_file.file_path) assert storage.exists(self.disabled_file.guarded_file_path) cron.unhide_disabled_files() assert storage.exists(self.file_.file_path) assert not storage.exists(self.file_.guarded_file_path) # The disabled file shouldn't have moved. assert not storage.exists(self.disabled_file.file_path) assert storage.exists(self.disabled_file.guarded_file_path) # The directory in guarded file path should still exist. assert storage.exists(os.path.dirname(self.file_.guarded_file_path))
def test_versions_queryset(self): addon_factory() file_factory(version=self.addon.current_version) version_factory(addon=self.addon, channel=amo.RELEASE_CHANNEL_UNLISTED) form = self.get_form() assert not form.is_bound assert form.fields['versions'].required is False assert list(form.fields['versions'].queryset) == [] # With post-review permission, the reject_multiple_versions action will # be available, resetting the queryset of allowed choices. self.grant_permission(self.request.user, 'Addons:PostReview') form = self.get_form() assert not form.is_bound assert form.fields['versions'].required is False assert list(form.fields['versions'].queryset) == [ self.addon.current_version]
def test_extract_version_and_files(self): current_beta_version = version_factory( addon=self.addon, file_kw={'status': amo.STATUS_BETA}) version = self.addon.current_version file_factory(version=version, platform=PLATFORM_MAC.id) extracted = self._extract() assert extracted['current_version'] assert extracted['current_version']['id'] == version.pk assert extracted['current_version']['compatible_apps'] == { FIREFOX.id: { 'min': 2000000200100L, 'max': 4000000200100L, 'max_human': '4.0', 'min_human': '2.0', } }
def test_reject_multiple_versions(self): old_version = self.version self.version = version_factory(addon=self.addon, version='3.0') AutoApprovalSummary.objects.create( version=self.version, verdict=amo.AUTO_APPROVED, weight=101) # An extra file should not change anything. file_factory(version=self.version, platform=amo.PLATFORM_LINUX.id) self.setup_data(amo.STATUS_PUBLIC, file_status=amo.STATUS_PUBLIC) # Safeguards. assert isinstance(self.helper.handler, ReviewFiles) assert self.addon.status == amo.STATUS_PUBLIC assert self.file.status == amo.STATUS_PUBLIC assert self.addon.current_version.is_public() data = self.get_data().copy() data['versions'] = self.addon.versions.all() self.helper.set_data(data) self.helper.handler.reject_multiple_versions() self.addon.reload() self.file.reload() assert self.addon.status == amo.STATUS_NULL assert self.addon.current_version is None assert list(self.addon.versions.all()) == [self.version, old_version] assert self.file.status == amo.STATUS_DISABLED assert len(mail.outbox) == 1 assert mail.outbox[0].to == [self.addon.authors.all()[0].email] assert mail.outbox[0].subject == ( u"Mozilla Add-ons: One or more versions of Delicious Bookmarks " u"didn't pass review") assert ('Version(s) affected and disabled:\n3.0, 2.1.072' in mail.outbox[0].body) log_token = ActivityLogToken.objects.get() assert log_token.uuid.hex in mail.outbox[0].reply_to[0] assert self.check_log_count(amo.LOG.REJECT_VERSION.id) == 2 assert self.check_log_count(amo.LOG.REJECT_CONTENT.id) == 0 # Check points awarded. self._check_score(amo.REVIEWED_EXTENSION_HIGH_RISK)
def test_extract_version_and_files(self): version = self.addon.current_version file_factory(version=version, platform=PLATFORM_MAC.id) extracted = self._extract() assert extracted['current_version'] assert extracted['current_version']['id'] == version.pk assert extracted['current_version']['reviewed'] == version.reviewed assert extracted['current_version']['version'] == version.version for index, file_ in enumerate(version.all_files): extracted_file = extracted['current_version']['files'][index] assert extracted_file['id'] == file_.pk assert extracted_file['created'] == file_.created assert extracted_file['filename'] == file_.filename assert extracted_file['hash'] == file_.hash assert extracted_file['platform'] == file_.platform assert extracted_file['size'] == file_.size assert extracted_file['status'] == file_.status assert extracted['has_version'] assert set(extracted['platforms']) == set([PLATFORM_MAC.id, PLATFORM_ALL.id])
def test_extract_version_and_files(self): version = self.addon.current_version file_factory(version=version, platform=PLATFORM_MAC.id) current_beta_version = version_factory( addon=self.addon, file_kw={'status': amo.STATUS_BETA}) unlisted_version = version_factory( addon=self.addon, channel=amo.RELEASE_CHANNEL_UNLISTED) # FIXME: remove this next line once current_version is modified to only # return listed versions. unlisted_version.update( created=version.created - timedelta(days=42)) extracted = self._extract() assert extracted['current_version'] assert extracted['current_version']['id'] == version.pk assert extracted['current_version']['compatible_apps'] == { FIREFOX.id: { 'min': 2000000200100L, 'max': 4000000200100L, 'max_human': '4.0', 'min_human': '2.0', } }
def test_extract_version_and_files(self): version = self.addon.current_version file_factory(version=version, platform=PLATFORM_MAC.id) unlisted_version = version_factory( addon=self.addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={ 'is_webextension': True, }) # Give one of the versions some webext permissions to test that. WebextPermission.objects.create( file=unlisted_version.all_files[0], permissions=['bookmarks', 'random permission'] ) extracted = self._extract() assert extracted['current_version'] assert extracted['current_version']['id'] == version.pk # Because strict_compatibility is False, the max version we record in # the index is an arbitrary super high version. assert extracted['current_version']['compatible_apps'] == { FIREFOX.id: { 'min': 2000000200100, 'max': 9999000000200100, 'max_human': '4.0', 'min_human': '2.0', } } assert extracted['current_version']['reviewed'] == version.reviewed assert extracted['current_version']['version'] == version.version for index, file_ in enumerate(version.all_files): extracted_file = extracted['current_version']['files'][index] assert extracted_file['id'] == file_.pk assert extracted_file['created'] == file_.created assert extracted_file['filename'] == file_.filename assert extracted_file['hash'] == file_.hash assert extracted_file['is_webextension'] == file_.is_webextension assert extracted_file['is_restart_required'] == ( file_.is_restart_required) assert extracted_file['is_mozilla_signed_extension'] == ( file_.is_mozilla_signed_extension) assert extracted_file['platform'] == file_.platform assert extracted_file['size'] == file_.size assert extracted_file['status'] == file_.status assert extracted_file['webext_permissions_list'] == [] assert set(extracted['platforms']) == set([PLATFORM_MAC.id, PLATFORM_ALL.id]) version = unlisted_version assert extracted['latest_unlisted_version'] assert extracted['latest_unlisted_version']['id'] == version.pk # Because strict_compatibility is False, the max version we record in # the index is an arbitrary super high version. assert extracted['latest_unlisted_version']['compatible_apps'] == { FIREFOX.id: { 'min': 4009900200100, 'max': 9999000000200100, 'max_human': '5.0.99', 'min_human': '4.0.99', } } assert ( extracted['latest_unlisted_version']['version'] == version.version) for idx, file_ in enumerate(version.all_files): extracted_file = extracted['latest_unlisted_version']['files'][idx] assert extracted_file['id'] == file_.pk assert extracted_file['created'] == file_.created assert extracted_file['filename'] == file_.filename assert extracted_file['hash'] == file_.hash assert extracted_file['is_webextension'] == file_.is_webextension assert extracted_file['is_mozilla_signed_extension'] == ( file_.is_mozilla_signed_extension) assert extracted_file['is_restart_required'] == ( file_.is_restart_required) assert extracted_file['platform'] == file_.platform assert extracted_file['size'] == file_.size assert extracted_file['status'] == file_.status assert (extracted_file['webext_permissions_list'] == file_.webext_permissions_list == ['bookmarks', 'random permission'])
def test_fetch_candidates(self): # Add nominated add-on: it should be considered. self.version.update(nomination=self.days_ago(1)) new_addon = addon_factory(status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) new_addon_version = new_addon.versions.all()[0] new_addon_version.update(nomination=self.days_ago(2)) # Add langpack: it should also be considered. langpack = addon_factory(type=amo.ADDON_LPAPP, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) langpack_version = langpack.versions.all()[0] langpack_version.update(nomination=self.days_ago(3)) # Add a bunch of add-ons in various states that should not be returned. # Public add-on with no updates. addon_factory(file_kw={'is_webextension': True}) # Non-extension with updates. search_addon = addon_factory(type=amo.ADDON_SEARCH) version_factory(addon=search_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Disabled add-on with updates. disabled_addon = addon_factory(disabled_by_user=True) version_factory(addon=disabled_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Add-on with deleted version. addon_with_deleted_version = addon_factory() deleted_version = version_factory(addon=addon_with_deleted_version, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) deleted_version.delete() # Add-on with a non-webextension update. non_webext_addon = addon_factory() version_factory(addon=non_webext_addon, file_kw={'status': amo.STATUS_AWAITING_REVIEW}) # Add-on with 3 versions: # - one webext, listed, public. # - one non-listed webext version # - one listed non-webext awaiting review. complex_addon = addon_factory(file_kw={'is_webextension': True}) version_factory(addon=complex_addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'is_webextension': True}) version_factory(addon=complex_addon, file_kw={'status': amo.STATUS_AWAITING_REVIEW}) # Finally, add a second file to self.version to test the distinct(). file_factory(version=self.version, status=amo.STATUS_AWAITING_REVIEW, is_webextension=True) # Gather the candidates. command = auto_approve.Command() command.post_review = True qs = command.fetch_candidates() # 3 versions should be found. Because of the nomination date, # langpack_version should be first (its nomination date is the oldest), # followed by new_addon_version and then self.version. assert len(qs) == 3 assert qs[0] == langpack_version assert qs[1] == new_addon_version assert qs[2] == self.version
def test_fetch_candidates(self): # We already have an add-on with a version awaiting review that should # be considered. Make sure its nomination date is in the past to test # ordering. self.version.update(nomination=self.days_ago(1)) # Add reviewer flags disabling auto-approval for this add-on. It would # still be fetched as a candidate, just rejected later on when # calculating the verdict. AddonReviewerFlags.objects.create( addon=self.addon, auto_approval_disabled=True) # Add nominated add-on: it should be considered. new_addon = addon_factory(status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) new_addon_version = new_addon.versions.all()[0] new_addon_version.update(nomination=self.days_ago(2)) # Even add an empty reviewer flags instance, that should not matter. AddonReviewerFlags.objects.create(addon=new_addon) # Add langpack: it should be considered. langpack = addon_factory( type=amo.ADDON_LPAPP, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) langpack_version = langpack.versions.all()[0] langpack_version.update(nomination=self.days_ago(3)) # Add a dictionary: it should also be considered. dictionary = addon_factory( type=amo.ADDON_DICT, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) dictionary_version = dictionary.versions.all()[0] dictionary_version.update(nomination=self.days_ago(4)) # search engine plugins are considered now search_addon = addon_factory(type=amo.ADDON_SEARCH) version_factory( addon=search_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}, nomination=self.days_ago(5)) # Some recommended add-ons - one nominated and one update. # They should be considered by fetch_candidate(), so that they get a # weight assigned etc - they will not be auto-approved but that's # handled at a later stage, when calculating the verdict. recommendable_addon_nominated = addon_factory( status=amo.STATUS_NOMINATED, version_kw={ 'recommendation_approved': True, 'nomination': self.days_ago(6) }, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}, ) recommended_addon = version_factory( addon=addon_factory(), recommendation_approved=True, nomination=self.days_ago(7), file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }).addon DiscoveryItem.objects.create( recommendable=True, addon=recommendable_addon_nominated) DiscoveryItem.objects.create( recommendable=True, addon=recommended_addon) # --------------------------------------------------------------------- # Add a bunch of add-ons in various states that should not be returned. # Public add-on with no updates. addon_factory(file_kw={'is_webextension': True}) # Disabled add-on with updates. disabled_addon = addon_factory(disabled_by_user=True) version_factory(addon=disabled_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) # Add-on with deleted version. addon_with_deleted_version = addon_factory() deleted_version = version_factory( addon=addon_with_deleted_version, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) deleted_version.delete() # Add-on with a non-webextension update. non_webext_addon = addon_factory() version_factory(addon=non_webext_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW}) # Add-on with 3 versions: # - one webext, listed, public. # - one non-listed webext version # - one listed non-webext awaiting review. complex_addon = addon_factory(file_kw={'is_webextension': True}) version_factory( addon=complex_addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'is_webextension': True}) version_factory(addon=complex_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW}) # Finally, add a second file to self.version to test the distinct(). file_factory( version=self.version, status=amo.STATUS_AWAITING_REVIEW, is_webextension=True) # Add-on with an already public version and an unlisted webext # still awaiting review complex_addon_2 = addon_factory(file_kw={'is_webextension': True}) version_factory( addon=complex_addon_2, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'is_webextension': True, 'status': amo.STATUS_AWAITING_REVIEW}) # --------------------------------------------------------------------- # Gather the candidates. command = auto_approve.Command() command.post_review = True qs = command.fetch_candidates() # 5 versions should be found. Because of the nomination date, # search_version should be first (its nomination date is the # oldest) followed etc. assert len(qs) == 7 assert [v.addon.pk for v in qs] == [a.pk for a in ( recommended_addon, recommendable_addon_nominated, search_addon, dictionary, langpack, new_addon, self.addon, )]
def test_basic(self): now = self.days_ago(0) license = License.objects.create( name={ 'en-US': u'My License', 'fr': u'Mä Licence', }, text={ 'en-US': u'Lorem ipsum dolor sit amet, has nemore patrioqué', }, url='http://license.example.com/' ) addon = addon_factory( file_kw={ 'hash': 'fakehash', 'is_webextension': True, 'is_mozilla_signed_extension': True, 'platform': amo.PLATFORM_WIN.id, 'size': 42, }, version_kw={ 'license': license, 'min_app_version': '50.0', 'max_app_version': '*', 'releasenotes': { 'en-US': u'Release notes in english', 'fr': u'Notes de version en français', }, 'reviewed': now, } ) self.version = addon.current_version first_file = self.version.files.latest('pk') file_factory( version=self.version, platform=amo.PLATFORM_MAC.id) second_file = self.version.files.latest('pk') # Force reload of all_files cached property. del self.version.all_files result = self.serialize() assert result['id'] == self.version.pk assert result['compatibility'] == { 'firefox': {'max': u'*', 'min': u'50.0'} } assert result['files'] assert len(result['files']) == 2 assert result['files'][0]['id'] == first_file.pk assert result['files'][0]['created'] == ( first_file.created.replace(microsecond=0).isoformat() + 'Z') assert result['files'][0]['hash'] == first_file.hash assert result['files'][0]['is_webextension'] == ( first_file.is_webextension) assert result['files'][0]['is_mozilla_signed_extension'] == ( first_file.is_mozilla_signed_extension) assert result['files'][0]['platform'] == 'windows' assert result['files'][0]['size'] == first_file.size assert result['files'][0]['status'] == 'public' assert result['files'][0]['url'] == first_file.get_url_path(src='') assert result['files'][1]['id'] == second_file.pk assert result['files'][1]['created'] == ( second_file.created.replace(microsecond=0).isoformat() + 'Z') assert result['files'][1]['hash'] == second_file.hash assert result['files'][1]['is_webextension'] == ( second_file.is_webextension) assert result['files'][1]['is_mozilla_signed_extension'] == ( second_file.is_mozilla_signed_extension) assert result['files'][1]['platform'] == 'mac' assert result['files'][1]['size'] == second_file.size assert result['files'][1]['status'] == 'public' assert result['files'][1]['url'] == second_file.get_url_path(src='') assert result['channel'] == 'listed' assert result['edit_url'] == absolutify(addon.get_dev_url( 'versions.edit', args=[self.version.pk], prefix_only=True)) assert result['release_notes'] == { 'en-US': u'Release notes in english', 'fr': u'Notes de version en français', } assert result['license'] assert dict(result['license']) == { 'id': license.pk, 'name': {'en-US': u'My License', 'fr': u'Mä Licence'}, 'text': { 'en-US': u'Lorem ipsum dolor sit amet, has nemore patrioqué', }, 'url': 'http://license.example.com/', } assert result['reviewed'] == ( now.replace(microsecond=0).isoformat() + 'Z') assert result['url'] == absolutify(self.version.get_url_path())
def test_fetch_candidates(self): # We already have an add-on with a version awaiting review that should # be considered. Make sure its nomination date is in the past to test # ordering. self.version.update(nomination=self.days_ago(1)) # Add a second file to self.version to test the distinct(). file_factory(version=self.version, status=amo.STATUS_AWAITING_REVIEW, is_webextension=True) # Add reviewer flags disabling auto-approval for this add-on. It would # still be fetched as a candidate, just rejected later on when # calculating the verdict. AddonReviewerFlags.objects.create(addon=self.addon, auto_approval_disabled=True) # Add nominated add-on: it should be considered. new_addon = addon_factory(name='New Addon', status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) new_addon_version = new_addon.versions.all()[0] new_addon_version.update(nomination=self.days_ago(2)) # Even add an empty reviewer flags instance, that should not matter. AddonReviewerFlags.objects.create(addon=new_addon) # Add langpack: it should be considered. langpack = addon_factory(name='Langpack', type=amo.ADDON_LPAPP, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) langpack_version = langpack.versions.all()[0] langpack_version.update(nomination=self.days_ago(3)) # Add a dictionary: it should also be considered. dictionary = addon_factory(name='Dictionary', type=amo.ADDON_DICT, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) dictionary_version = dictionary.versions.all()[0] dictionary_version.update(nomination=self.days_ago(4)) # search engine plugins are considered now search_addon = addon_factory(name='Search', type=amo.ADDON_SEARCH) search_addon_version = version_factory(addon=search_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }, nomination=self.days_ago(5)) # Some recommended add-ons - one nominated and one update. # They should be considered by fetch_candidate(), so that they get a # weight assigned etc - they will not be auto-approved but that's # handled at a later stage, when calculating the verdict. recommendable_addon_nominated = addon_factory( name='Recommendable Addon', status=amo.STATUS_NOMINATED, version_kw={ 'recommendation_approved': True, 'nomination': self.days_ago(6) }, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }, ) DiscoveryItem.objects.create(recommendable=True, addon=recommendable_addon_nominated) recommended_addon = addon_factory(name='Recommended Addon', ) recommended_addon_version = version_factory( addon=recommended_addon, recommendation_approved=True, nomination=self.days_ago(7), file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) DiscoveryItem.objects.create(recommendable=True, addon=recommended_addon) # Add-on with 3 versions: # - one webext, listed, public. # - one non-listed webext version awaiting review. # - one listed non-webext awaiting review (should be ignored) complex_addon = addon_factory(name='Complex Addon', file_kw={'is_webextension': True}) complex_addon_version = version_factory( nomination=self.days_ago(8), addon=complex_addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={ 'is_webextension': True, 'status': amo.STATUS_AWAITING_REVIEW }) version_factory(nomination=self.days_ago(9), addon=complex_addon, file_kw={'status': amo.STATUS_AWAITING_REVIEW}) # Add-on with an already public version and an unlisted webext # awaiting review. complex_addon_2 = addon_factory(name='Second Complex Addon', file_kw={'is_webextension': True}) complex_addon_2_version = version_factory( addon=complex_addon_2, channel=amo.RELEASE_CHANNEL_UNLISTED, nomination=self.days_ago(10), file_kw={ 'is_webextension': True, 'status': amo.STATUS_AWAITING_REVIEW }) # Disabled version with a webext waiting review (Still has to be # considered because unlisted doesn't care about disabled by user # state. user_disabled_addon = addon_factory( name='Disabled by user waiting review', disabled_by_user=True) user_disabled_addon_version = version_factory( nomination=self.days_ago(11), channel=amo.RELEASE_CHANNEL_UNLISTED, addon=user_disabled_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Pure unlisted upload. Addon status is "incomplete" as a result, but # it should still be considered because unlisted versions don't care # about that. pure_unlisted = addon_factory(name='Pure unlisted', version_kw={ 'channel': amo.RELEASE_CHANNEL_UNLISTED, 'nomination': self.days_ago(12) }, file_kw={ 'is_webextension': True, 'status': amo.STATUS_AWAITING_REVIEW }, status=amo.STATUS_NULL) pure_unlisted_version = pure_unlisted.versions.get() # Unlisted static theme. unlisted_theme = addon_factory(name='Unlisted theme', version_kw={ 'channel': amo.RELEASE_CHANNEL_UNLISTED, 'nomination': self.days_ago(13) }, file_kw={ 'is_webextension': True, 'status': amo.STATUS_AWAITING_REVIEW }, status=amo.STATUS_NULL, type=amo.ADDON_STATICTHEME) unlisted_theme_version = unlisted_theme.versions.get() # --------------------------------------------------------------------- # Add a bunch of add-ons in various states that should not be returned. # Public add-on with no updates. addon_factory(name='Already Public', file_kw={'is_webextension': True}) # Mozilla Disabled add-on with updates. disabled_addon = addon_factory( name='Mozilla Disabled', status=amo.STATUS_DISABLED, ) version_factory(addon=disabled_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Add-on with deleted version. addon_with_deleted_version = addon_factory( name='With deleted version awaiting review') deleted_version = version_factory(addon=addon_with_deleted_version, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) deleted_version.delete() # Add-on with a non-webextension update. non_webext_addon = addon_factory(name='Non Webext waiting review') version_factory(addon=non_webext_addon, file_kw={'status': amo.STATUS_AWAITING_REVIEW}) # Somehow deleted add-on with a file still waiting for review. deleted_addon = addon_factory( name='Deleted Awaiting Review Somehow', status=amo.STATUS_DELETED, ) version_factory(addon=deleted_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # listed version belonging to an add-on disabled by user addon_factory(name='Listed Disabled by user', disabled_by_user=True, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Incomplete listed addon addon_factory(name='Incomplete listed', status=amo.STATUS_NULL, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Listed static theme addon_factory(name='Listed theme', file_kw={ 'is_webextension': True, 'status': amo.STATUS_AWAITING_REVIEW }, status=amo.STATUS_NOMINATED, type=amo.ADDON_STATICTHEME) # --------------------------------------------------------------------- # Gather the candidates. command = auto_approve.Command() command.post_review = True qs = command.fetch_candidates() # We should find these versions, in this exact order. expected = [(version.addon, version) for version in [ unlisted_theme_version, pure_unlisted_version, user_disabled_addon_version, complex_addon_2_version, complex_addon_version, recommended_addon_version, recommendable_addon_nominated.current_version, search_addon_version, dictionary.current_version, langpack.current_version, new_addon.current_version, self.version, ]] assert [(version.addon, version) for version in qs] == expected
def test_fetch_candidates(self): # Add nominated add-on: it should be considered. self.version.update(nomination=self.days_ago(1)) new_addon = addon_factory(status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) new_addon_version = new_addon.versions.all()[0] new_addon_version.update(nomination=self.days_ago(2)) # Add langpack: it should also be considered. langpack = addon_factory( type=amo.ADDON_LPAPP, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) langpack_version = langpack.versions.all()[0] langpack_version.update(nomination=self.days_ago(3)) # Add a bunch of add-ons in various states that should not be returned. # Public add-on with no updates. addon_factory(file_kw={'is_webextension': True}) # Non-extension with updates. search_addon = addon_factory(type=amo.ADDON_SEARCH) version_factory(addon=search_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) # Disabled add-on with updates. disabled_addon = addon_factory(disabled_by_user=True) version_factory(addon=disabled_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) # Add-on with deleted version. addon_with_deleted_version = addon_factory() deleted_version = version_factory( addon=addon_with_deleted_version, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) deleted_version.delete() # Add-on with a non-webextension update. non_webext_addon = addon_factory() version_factory(addon=non_webext_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW}) # Add-on with 3 versions: # - one webext, listed, public. # - one non-listed webext version # - one listed non-webext awaiting review. complex_addon = addon_factory(file_kw={'is_webextension': True}) version_factory( addon=complex_addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'is_webextension': True}) version_factory(addon=complex_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW}) # Finally, add a second file to self.version to test the distinct(). file_factory( version=self.version, status=amo.STATUS_AWAITING_REVIEW, is_webextension=True) # Gather the candidates. command = auto_approve.Command() command.post_review = True qs = command.fetch_candidates() # 3 versions should be found. Because of the nomination date, # langpack_version should be first (its nomination date is the oldest), # followed by new_addon_version and then self.version. assert len(qs) == 3 assert qs[0] == langpack_version assert qs[1] == new_addon_version assert qs[2] == self.version
def test_fetch_candidates(self): # Add a bunch of add-ons in various states that should not be returned. # Public add-on with no updates. addon_factory(file_kw={'is_webextension': True}) # Non-extension with updates. search_addon = addon_factory(type=amo.ADDON_SEARCH) version_factory(addon=search_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Disabled add-on with updates. disabled_addon = addon_factory(disabled_by_user=True) version_factory(addon=disabled_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Non-public add-on. addon_factory(status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Add-on with deleted version. addon_with_deleted_version = addon_factory() deleted_version = version_factory(addon=addon_with_deleted_version, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) deleted_version.delete() # Add-on with a non-webextension update. non_webext_addon = addon_factory() version_factory(addon=non_webext_addon, file_kw={'status': amo.STATUS_AWAITING_REVIEW}) # Add-on with 3 versions: # - one webext, listed, public. # - one non-listed webext version # - one listed non-webext awaiting review. complex_addon = addon_factory(file_kw={'is_webextension': True}) version_factory(addon=complex_addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'is_webextension': True}) version_factory(addon=complex_addon, file_kw={'status': amo.STATUS_AWAITING_REVIEW}) # Finally, add a second file to self.version to test the distinct(). file_factory(version=self.version, status=amo.STATUS_AWAITING_REVIEW, is_webextension=True) # Gather the candidates. command = auto_approve.Command() qs = command.fetch_candidates() # Only self.version should be found, once. assert len(qs) == 1 assert qs[0] == self.version
def test_fetch_candidates(self): # We already have an add-on with a version awaiting review that should # be considered. Make sure its nomination date is in the past to test # ordering. self.version.update(nomination=self.days_ago(1)) # Add reviewer flags disabling auto-approval for this add-on. It would # still be fetched as a candidate, just rejected later on when # calculating the verdict. AddonReviewerFlags.objects.create( addon=self.addon, auto_approval_disabled=True) # Add nominated add-on: it should be considered. new_addon = addon_factory(status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) new_addon_version = new_addon.versions.all()[0] new_addon_version.update(nomination=self.days_ago(2)) # Even add an empty reviewer flags instance, that should not matter. AddonReviewerFlags.objects.create(addon=new_addon) # Add langpack: it should be considered. langpack = addon_factory( type=amo.ADDON_LPAPP, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) langpack_version = langpack.versions.all()[0] langpack_version.update(nomination=self.days_ago(3)) # Add a dictionary: it should also be considered. dictionary = addon_factory( type=amo.ADDON_DICT, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) dictionary_version = dictionary.versions.all()[0] dictionary_version.update(nomination=self.days_ago(4)) # search engine plugins are considered now search_addon = addon_factory(type=amo.ADDON_SEARCH) search_version = version_factory( addon=search_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}, nomination=self.days_ago(5)) # Add a bunch of add-ons in various states that should not be returned. # Public add-on with no updates. addon_factory(file_kw={'is_webextension': True}) # Disabled add-on with updates. disabled_addon = addon_factory(disabled_by_user=True) version_factory(addon=disabled_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) # Add-on with deleted version. addon_with_deleted_version = addon_factory() deleted_version = version_factory( addon=addon_with_deleted_version, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}) deleted_version.delete() # Add-on with a non-webextension update. non_webext_addon = addon_factory() version_factory(addon=non_webext_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW}) # Add-on with 3 versions: # - one webext, listed, public. # - one non-listed webext version # - one listed non-webext awaiting review. complex_addon = addon_factory(file_kw={'is_webextension': True}) version_factory( addon=complex_addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'is_webextension': True}) version_factory(addon=complex_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW}) # Some recommended add-ons - one nominated and one update DiscoveryItem.objects.create( recommendable=True, addon=addon_factory( status=amo.STATUS_NOMINATED, version_kw={'recommendation_approved': True}, file_kw={'status': amo.STATUS_AWAITING_REVIEW})) DiscoveryItem.objects.create( recommendable=True, addon=version_factory( addon=addon_factory(), recommendation_approved=True, file_kw={'status': amo.STATUS_AWAITING_REVIEW}).addon) # Finally, add a second file to self.version to test the distinct(). file_factory( version=self.version, status=amo.STATUS_AWAITING_REVIEW, is_webextension=True) # Gather the candidates. command = auto_approve.Command() command.post_review = True qs = command.fetch_candidates() # 4 versions should be found. Because of the nomination date, # search_version should be first (its nomination date is the # oldest) followed etc. assert len(qs) == 5 assert list(v.addon.type for v in qs) == list( a.type for a in ( search_addon, dictionary, langpack, new_addon, self.addon)) assert qs[0] == search_version assert qs[1] == dictionary_version assert qs[2] == langpack_version assert qs[3] == new_addon_version assert qs[4] == self.version
def test_extract_version_and_files(self): version = self.addon.current_version # Make the version a webextension and add a bunch of things to it to # test different scenarios. version.all_files[0].update(is_webextension=True) file_factory( version=version, platform=PLATFORM_MAC.id, is_webextension=True) del version.all_files version.license = License.objects.create( name=u'My licensé', url='http://example.com/', builtin=0) [WebextPermission.objects.create( file=file_, permissions=['bookmarks', 'random permission'] ) for file_ in version.all_files] version.save() # Now we can run the extraction and start testing. extracted = self._extract() assert extracted['current_version'] assert extracted['current_version']['id'] == version.pk # Because strict_compatibility is False, the max version we record in # the index is an arbitrary super high version. assert extracted['current_version']['compatible_apps'] == { FIREFOX.id: { 'min': 2000000200100, 'max': 9999000000200100, 'max_human': '4.0', 'min_human': '2.0', } } assert extracted['current_version']['license'] == { 'builtin': 0, 'id': version.license.pk, 'name_translations': [{'lang': u'en-US', 'string': u'My licensé'}], 'url': u'http://example.com/' } assert extracted['current_version']['release_notes_translations'] == [ {'lang': 'en-US', 'string': u'Fix for an important bug'}, {'lang': 'fr', 'string': u"Quelque chose en fran\xe7ais." u"\n\nQuelque chose d'autre."}, ] assert extracted['current_version']['reviewed'] == version.reviewed assert extracted['current_version']['version'] == version.version for index, file_ in enumerate(version.all_files): extracted_file = extracted['current_version']['files'][index] assert extracted_file['id'] == file_.pk assert extracted_file['created'] == file_.created assert extracted_file['filename'] == file_.filename assert extracted_file['hash'] == file_.hash assert extracted_file['is_webextension'] == file_.is_webextension assert extracted_file['is_restart_required'] == ( file_.is_restart_required) assert extracted_file['is_mozilla_signed_extension'] == ( file_.is_mozilla_signed_extension) assert extracted_file['platform'] == file_.platform assert extracted_file['size'] == file_.size assert extracted_file['status'] == file_.status assert extracted_file['webext_permissions_list'] == [ 'bookmarks', 'random permission'] assert set(extracted['platforms']) == set([PLATFORM_MAC.id, PLATFORM_ALL.id])
def test_basic(self): now = self.days_ago(0) license = License.objects.create( name={ 'en-US': u'My License', 'fr': u'Mä Licence', }, text={ 'en-US': u'Lorem ipsum dolor sit amet, has nemore patrioqué', }, url='http://license.example.com/') addon = addon_factory(file_kw={ 'hash': 'fakehash', 'is_webextension': True, 'platform': amo.PLATFORM_WIN.id, 'size': 42, }, version_kw={ 'license': license, 'min_app_version': '50.0', 'max_app_version': '*', 'releasenotes': { 'en-US': u'Release notes in english', 'fr': u'Notes de version en français', }, 'reviewed': now, }) self.version = addon.current_version first_file = self.version.files.latest('pk') file_factory(version=self.version, platform=amo.PLATFORM_MAC.id) second_file = self.version.files.latest('pk') # Force reload of all_files cached property. del self.version.all_files result = self.serialize() assert result['id'] == self.version.pk assert result['compatibility'] == { 'firefox': { 'max': u'*', 'min': u'50.0' } } assert result['files'] assert len(result['files']) == 2 assert result['files'][0]['id'] == first_file.pk assert result['files'][0]['created'] == ( first_file.created.replace(microsecond=0).isoformat() + 'Z') assert result['files'][0]['hash'] == first_file.hash assert result['files'][0]['is_webextension'] == ( first_file.is_webextension) assert result['files'][0]['platform'] == 'windows' assert result['files'][0]['size'] == first_file.size assert result['files'][0]['status'] == 'public' assert result['files'][0]['url'] == first_file.get_url_path(src='') assert result['files'][1]['id'] == second_file.pk assert result['files'][1]['created'] == ( second_file.created.replace(microsecond=0).isoformat() + 'Z') assert result['files'][1]['hash'] == second_file.hash assert result['files'][1]['is_webextension'] == ( second_file.is_webextension) assert result['files'][1]['platform'] == 'mac' assert result['files'][1]['size'] == second_file.size assert result['files'][1]['status'] == 'public' assert result['files'][1]['url'] == second_file.get_url_path(src='') assert result['channel'] == 'listed' assert result['edit_url'] == absolutify( addon.get_dev_url('versions.edit', args=[self.version.pk], prefix_only=True)) assert result['release_notes'] == { 'en-US': u'Release notes in english', 'fr': u'Notes de version en français', } assert result['license'] assert dict(result['license']) == { 'id': license.pk, 'name': { 'en-US': u'My License', 'fr': u'Mä Licence' }, 'text': { 'en-US': u'Lorem ipsum dolor sit amet, has nemore patrioqué', }, 'url': 'http://license.example.com/', } assert result['reviewed'] == (now.replace(microsecond=0).isoformat() + 'Z') assert result['url'] == absolutify(self.version.get_url_path())
def test_fetch_candidates(self): # We already have an add-on with a version awaiting review that should # be considered. Make sure its nomination date is in the past to test # ordering. self.version.update(nomination=self.days_ago(1)) # Add reviewer flags disabling auto-approval for this add-on. It would # still be fetched as a candidate, just rejected later on when # calculating the verdict. AddonReviewerFlags.objects.create(addon=self.addon, auto_approval_disabled=True) # Add nominated add-on: it should be considered. new_addon = addon_factory(status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) new_addon_version = new_addon.versions.all()[0] new_addon_version.update(nomination=self.days_ago(2)) # Even add an empty reviewer flags instance, that should not matter. AddonReviewerFlags.objects.create(addon=new_addon) # Add langpack: it should also be considered. langpack = addon_factory(type=amo.ADDON_LPAPP, status=amo.STATUS_NOMINATED, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) langpack_version = langpack.versions.all()[0] langpack_version.update(nomination=self.days_ago(3)) # Add a bunch of add-ons in various states that should not be returned. # Public add-on with no updates. addon_factory(file_kw={'is_webextension': True}) # Non-extension with updates. search_addon = addon_factory(type=amo.ADDON_SEARCH) version_factory(addon=search_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Disabled add-on with updates. disabled_addon = addon_factory(disabled_by_user=True) version_factory(addon=disabled_addon, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) # Add-on with deleted version. addon_with_deleted_version = addon_factory() deleted_version = version_factory(addon=addon_with_deleted_version, file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True }) deleted_version.delete() # Add-on with a non-webextension update. non_webext_addon = addon_factory() version_factory(addon=non_webext_addon, file_kw={'status': amo.STATUS_AWAITING_REVIEW}) # Add-on with 3 versions: # - one webext, listed, public. # - one non-listed webext version # - one listed non-webext awaiting review. complex_addon = addon_factory(file_kw={'is_webextension': True}) version_factory(addon=complex_addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'is_webextension': True}) version_factory(addon=complex_addon, file_kw={'status': amo.STATUS_AWAITING_REVIEW}) # Finally, add a second file to self.version to test the distinct(). file_factory(version=self.version, status=amo.STATUS_AWAITING_REVIEW, is_webextension=True) # Gather the candidates. command = auto_approve.Command() command.post_review = True qs = command.fetch_candidates() # 3 versions should be found. Because of the nomination date, # langpack_version should be first (its nomination date is the oldest), # followed by new_addon_version and then self.version. assert len(qs) == 3 assert qs[0] == langpack_version assert qs[1] == new_addon_version assert qs[2] == self.version
def test_extract_version_and_files(self): version = self.addon.current_version file_factory(version=version, platform=PLATFORM_MAC.id) unlisted_version = version_factory( addon=self.addon, channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={ 'is_webextension': True, }) # Give one of the versions some webext permissions to test that. WebextPermission.objects.create( file=unlisted_version.all_files[0], permissions=['bookmarks', 'random permission'] ) extracted = self._extract() assert extracted['current_version'] assert extracted['current_version']['id'] == version.pk # Because strict_compatibility is False, the max version we record in # the index is an arbitrary super high version. assert extracted['current_version']['compatible_apps'] == { FIREFOX.id: { 'min': 2000000200100, 'max': 9999000000200100, 'max_human': '4.0', 'min_human': '2.0', } } assert extracted['current_version']['reviewed'] == version.reviewed assert extracted['current_version']['version'] == version.version for index, file_ in enumerate(version.all_files): extracted_file = extracted['current_version']['files'][index] assert extracted_file['id'] == file_.pk assert extracted_file['created'] == file_.created assert extracted_file['filename'] == file_.filename assert extracted_file['hash'] == file_.hash assert extracted_file['is_webextension'] == file_.is_webextension assert extracted_file['is_restart_required'] == ( file_.is_restart_required) assert extracted_file['is_mozilla_signed_extension'] == ( file_.is_mozilla_signed_extension) assert extracted_file['platform'] == file_.platform assert extracted_file['size'] == file_.size assert extracted_file['status'] == file_.status assert extracted_file['webext_permissions_list'] == [] assert set(extracted['platforms']) == set([PLATFORM_MAC.id, PLATFORM_ALL.id]) version = unlisted_version assert extracted['latest_unlisted_version'] assert extracted['latest_unlisted_version']['id'] == version.pk # Because strict_compatibility is False, the max version we record in # the index is an arbitrary super high version. assert extracted['latest_unlisted_version']['compatible_apps'] == { FIREFOX.id: { 'min': 4009900200100, 'max': 9999000000200100, 'max_human': '5.0.99', 'min_human': '4.0.99', } } assert ( extracted['latest_unlisted_version']['version'] == version.version) for idx, file_ in enumerate(version.all_files): extracted_file = extracted['latest_unlisted_version']['files'][idx] assert extracted_file['id'] == file_.pk assert extracted_file['created'] == file_.created assert extracted_file['filename'] == file_.filename assert extracted_file['hash'] == file_.hash assert extracted_file['is_webextension'] == file_.is_webextension assert extracted_file['is_mozilla_signed_extension'] == ( file_.is_mozilla_signed_extension) assert extracted_file['is_restart_required'] == ( file_.is_restart_required) assert extracted_file['platform'] == file_.platform assert extracted_file['size'] == file_.size assert extracted_file['status'] == file_.status assert (extracted_file['webext_permissions_list'] == file_.webext_permissions_list == ['bookmarks', 'random permission'])
def test_extract_version_and_files(self): version = self.addon.current_version # Make the version a webextension and add a bunch of things to it to # test different scenarios. version.all_files[0].update(is_webextension=True) file_factory( version=version, platform=PLATFORM_MAC.id, is_webextension=True) del version.all_files version.license = License.objects.create( name=u'My licensé', url='http://example.com/', builtin=0) [WebextPermission.objects.create( file=file_, permissions=['bookmarks', 'random permission'] ) for file_ in version.all_files] version.save() # Now we can run the extraction and start testing. extracted = self._extract() assert extracted['current_version'] assert extracted['current_version']['id'] == version.pk # Because strict_compatibility is False, the max version we record in # the index is an arbitrary super high version. assert extracted['current_version']['compatible_apps'] == { FIREFOX.id: { 'min': 2000000200100, 'max': 9999000000200100, 'max_human': '4.0', 'min_human': '2.0', } } assert extracted['current_version']['license'] == { 'builtin': 0, 'id': version.license.pk, 'name_translations': [{'lang': u'en-US', 'string': u'My licensé'}], 'url': u'http://example.com/' } assert extracted['current_version']['release_notes_translations'] == [ {'lang': 'en-US', 'string': u'Fix for an important bug'}, {'lang': 'fr', 'string': u"Quelque chose en fran\xe7ais." u"\n\nQuelque chose d'autre."}, ] assert extracted['current_version']['reviewed'] == version.reviewed assert extracted['current_version']['version'] == version.version for index, file_ in enumerate(version.all_files): extracted_file = extracted['current_version']['files'][index] assert extracted_file['id'] == file_.pk assert extracted_file['created'] == file_.created assert extracted_file['filename'] == file_.filename assert extracted_file['hash'] == file_.hash assert extracted_file['is_webextension'] == file_.is_webextension assert extracted_file['is_restart_required'] == ( file_.is_restart_required) assert extracted_file['is_mozilla_signed_extension'] == ( file_.is_mozilla_signed_extension) assert extracted_file['platform'] == file_.platform assert extracted_file['size'] == file_.size assert extracted_file['status'] == file_.status assert extracted_file['webext_permissions_list'] == [ 'bookmarks', 'random permission'] assert set(extracted['platforms']) == set([PLATFORM_MAC.id, PLATFORM_ALL.id])