def test_update_counts_from_file_includes_disabled_addons(self): addon_factory( guid='{39e6cf40-02f6-4bda-b1ee-409910ffd9f9}', slug='disabled-addon', status=amo.STATUS_DISABLED) addon_factory( guid='9c444b87-1124-4fd2-b97f-8fb7e9be1820', slug='incomplete-addon', status=amo.STATUS_NULL) management.call_command('update_counts_from_file', hive_folder, date=self.date, stats_source=self.stats_source) assert UpdateCount.objects.all().count() == 2 update_count = UpdateCount.objects.get(addon_id=3615) # should be identical to `statuses.userEnabled` assert update_count.count == 4 assert update_count.date == date(2014, 7, 10) assert update_count.versions == {u'3.8': 2, u'3.7': 3} assert update_count.statuses == {u'userDisabled': 1, u'userEnabled': 4} update_count = UpdateCount.objects.get(addon__slug='disabled-addon') assert update_count.count == 2 assert update_count.date == date(2014, 7, 10) assert update_count.versions == {} assert update_count.statuses == {u'userEnabled': 2} # Make sure we didn't generate any stats for incomplete add-ons assert not UpdateCount.objects.filter( addon__slug='incomplete-addon').exists()
def test_recommendations(self): author = user_factory() recommendations = { 101: addon_factory(id=101, guid='101@mozilla', users=[author]), 102: addon_factory(id=102, guid='102@mozilla', users=[author]), 103: addon_factory(id=103, guid='103@mozilla', users=[author]), 104: addon_factory(id=104, guid='104@mozilla', users=[author]), } replacement_items = [ DiscoItem(addon_id=101, is_recommendation=True), DiscoItem(addon_id=102, is_recommendation=True), DiscoItem(addon_id=103, is_recommendation=True), DiscoItem(addon_id=104, is_recommendation=True), ] self.addons.update(recommendations) self.get_recommendations.return_value = replacement_items response = self.client.get(self.url, {'lang': 'en-US', 'telemetry-client-id': '666'}) # should still be the same number of results. assert response.data['count'] == len(discopane_items) assert response.data['results'] # personas aren't replaced by recommendations, so should be as before. new_discopane_items = replace_extensions( discopane_items, replacement_items) for i, result in enumerate(response.data['results']): if 'theme_data' in result['addon']: self._check_disco_theme(result, new_discopane_items[i]) # There aren't any theme recommendations. assert result['is_recommendation'] is False else: self._check_disco_addon(result, new_discopane_items[i]) assert result['is_recommendation'] is True
def setUpTestData(cls): cls.addon1 = addon_factory(guid='@guid1') cls.addon2 = addon_factory(guid='@guid2') cls.addon3 = addon_factory(guid='@guid3') cls.user = user_factory() grant_permission(cls.user, 'Admin:Tools', 'Admin Group') grant_permission(cls.user, 'AbuseReports:Edit', 'Abuse Report Triage') # Create a few abuse reports. AbuseReport.objects.create( addon=cls.addon1, guid='@guid1', message='Foo', state=AbuseReport.STATES.VALID, created=days_ago(98)) AbuseReport.objects.create( addon=cls.addon2, guid='@guid2', message='Bar', state=AbuseReport.STATES.VALID) AbuseReport.objects.create( addon=cls.addon3, guid='@guid3', message='Soap', reason=AbuseReport.REASONS.OTHER, created=days_ago(100)) AbuseReport.objects.create( addon=cls.addon1, guid='@guid1', message='', reporter=user_factory()) # This is a report for an addon not in the database. AbuseReport.objects.create( guid='@unknown_guid', addon_name='Mysterious Addon', message='Doo') # This is one against a user. AbuseReport.objects.create( user=user_factory(), message='Eheheheh')
def setUp(self): user_factory( id=settings.TASK_USER_ID, username='******', email='*****@*****.**') self.addons = [ addon_factory(average_daily_users=666, users=[user_factory()]), addon_factory(average_daily_users=999, users=[user_factory()]), ] self.versions = [ version_factory( addon=self.addons[0], file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}), version_factory( addon=self.addons[1], file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'is_webextension': True}), ] self.files = [ self.versions[0].all_files[0], self.versions[1].all_files[0], ] self.versions[0].update(nomination=days_ago(1)) FileValidation.objects.create( file=self.versions[0].all_files[0], validation=u'{}') FileValidation.objects.create( file=self.versions[1].all_files[0], validation=u'{}') super(TestAutoApproveCommandTransactions, self).setUp()
def test_fix_langpack_summary(self): """What happened on our production system: The `zadmin.tasks.fetch_langpack` task set `summary` to the same translation instance of `name` for add-ons without a summary set. This meant that changing `name` or `summary` automatically changed the other one. """ owner = UserProfile.objects.get(email=settings.LANGPACK_OWNER_EMAIL) a1 = addon_factory(name='addon 1', users=[owner]) a1.summary = a1.name a1.save() # We won't touch this add-on, wrong owner a2 = addon_factory(name='addon 2', users=[owner]) a2.summary = a2.name a2.save() assert a1.summary.id == a1.name.id assert a2.summary.id == a2.summary.id # Now, let's fix this mess. management.call_command('fix_langpack_summary') a1.refresh_from_db() a2.refresh_from_db() assert a1.summary_id != a1.name_id # Didn't touch wrong owner add-on assert a2.summary_id == a2.summary_id
def test_count_stats_for_date(self): # Add a listed add-on, it should show up in "addon_count_new". listed_addon = addon_factory() # Add an unlisted version to that add-on, it should *not* increase the # "version_count_new" count. version_factory( addon=listed_addon, channel=amo.RELEASE_CHANNEL_UNLISTED) # Add an unlisted add-on, it should not show up in either # "addon_count_new" or "version_count_new". addon_factory(version_kw={ 'channel': amo.RELEASE_CHANNEL_UNLISTED }) date = datetime.date.today() job = 'addon_count_new' tasks.update_global_totals(job, date) global_stat = GlobalStat.objects.no_cache().get(date=date, name=job) assert global_stat.count == 1 job = 'version_count_new' tasks.update_global_totals(job, date) global_stat = GlobalStat.objects.no_cache().get(date=date, name=job) assert global_stat.count == 1
def test_through_cron(self): # Yesterday, create some stuff. with freeze_time(datetime.datetime.now() - datetime.timedelta(days=1)): yesterday = datetime.date.today() # Add a listed add-on, it should show up in "addon_count_new". listed_addon = addon_factory(created=datetime.datetime.now()) # Add an unlisted version to that add-on, it should *not* increase # the "version_count_new" count. version_factory( addon=listed_addon, channel=amo.RELEASE_CHANNEL_UNLISTED) # Add an unlisted add-on, it should not show up in either # "addon_count_new" or "version_count_new". addon_factory(version_kw={ 'channel': amo.RELEASE_CHANNEL_UNLISTED }) # Launch the cron. cron.update_global_totals() job = 'addon_count_new' global_stat = GlobalStat.objects.get(date=yesterday, name=job) assert global_stat.count == 1 job = 'version_count_new' global_stat = GlobalStat.objects.get(date=yesterday, name=job) assert global_stat.count == 1
def create_named_addon_with_author(self, name, author=None): """Create a generic addon and a user. The user will be created if a user is not given. """ if author is None: author = user_factory() try: generate_user(author) except Exception: # django.db.utils.IntegrityError # If the user is already made, use that same user, # if not use created user addon = addon_factory( status=STATUS_PUBLIC, users=[UserProfile.objects.get(username=author)], name=u'{}'.format(name), slug=u'{}'.format(name), ) addon.save() else: addon = addon_factory( status=STATUS_PUBLIC, users=[UserProfile.objects.get(username=author.username)], name=u'{}'.format(name), slug=u'{}'.format(name), ) addon.save() return addon
def test_only_show_notifications_user_has_permission_to(self): create_switch('activate-basket-sync') with patch('basket.base.request', autospec=True) as request_call: request_call.return_value = { 'status': 'ok', 'token': '123', 'newsletters': []} form = UserEditForm({}, instance=self.user) request_call.assert_called_with( 'get', 'lookup-user', headers={'x-api-key': 'testkey'}, params={'email': u'*****@*****.**'}) # It needs a developer account to subscribe to a newsletter # So the `announcements` notification is not among the valid choices # This isn't really user visible since the user doesn't have # the ability to choose newsletters he doesn't have permissions # to see. assert len(form.fields['notifications'].choices) == 2 assert form.fields['notifications'].choices[0][0] == 3 assert form.fields['notifications'].choices[1][0] == 4 addon_factory(users=[self.user]) # Clear cache del self.user.is_developer form = UserEditForm({}, instance=self.user) assert len(form.fields['notifications'].choices) == 10 assert [x[0] for x in form.fields['notifications'].choices] == [ 3, 4, 5, 6, 7, 9, 10, 11, 12, 8 ]
def test_pagination(self): addon = addon_factory(slug='my-addon', name=u'My Addôn', weekly_downloads=33) addon2 = addon_factory(slug='my-second-addon', name=u'My second Addôn', weekly_downloads=22) addon_factory(slug='my-third-addon', name=u'My third Addôn', weekly_downloads=11) self.refresh() data = self.perform_search_with_senior_editor( self.url, {'page_size': 1}) assert data['count'] == 3 assert len(data['results']) == 1 result = data['results'][0] assert result['id'] == addon.pk assert result['name'] == {'en-US': u'My Addôn'} assert result['slug'] == 'my-addon' # Search using the second page URL given in return value. # Expect 0 SQL queries since they should be cached after the first # call above. data = self.perform_search_with_senior_editor( data['next'], expected_queries_count=0) assert data['count'] == 3 assert len(data['results']) == 1 result = data['results'][0] assert result['id'] == addon2.pk assert result['name'] == {'en-US': u'My second Addôn'} assert result['slug'] == 'my-second-addon'
def test_can_change_addon_with_discovery_edit_permission(self): addon = addon_factory(name=u'BarFöo') addon2 = addon_factory(name=u'Another ône', slug='another-addon') item = DiscoveryItem.objects.create(addon=addon) self.detail_url = reverse( 'admin:discovery_discoveryitem_change', args=(item.pk,) ) user = user_factory() self.grant_permission(user, 'Admin:Tools') self.grant_permission(user, 'Discovery:Edit') self.client.login(email=user.email) response = self.client.get(self.detail_url, follow=True) assert response.status_code == 200 assert u'BarFöo' in response.content.decode('utf-8') # Change add-on using the slug. response = self.client.post( self.detail_url, {'addon': six.text_type(addon2.slug)}, follow=True) assert response.status_code == 200 item.reload() assert DiscoveryItem.objects.count() == 1 # assert item.addon == addon2 # Change add-on using the id. response = self.client.post( self.detail_url, {'addon': six.text_type(addon.pk)}, follow=True) assert response.status_code == 200 item.reload() assert DiscoveryItem.objects.count() == 1 assert item.addon == addon
def test_basic(self): addon = addon_factory( name=u'My Addôn', slug='my-addon', status=amo.STATUS_NULL, version_kw={'channel': amo.RELEASE_CHANNEL_UNLISTED}, weekly_downloads=666) addon2 = addon_factory(slug='my-second-addon', name=u'My second Addôn', weekly_downloads=555) addon2.delete() self.refresh() data = self.perform_search_with_senior_editor(self.url) # No query. assert data['count'] == 2 assert len(data['results']) == 2 result = data['results'][0] assert result['id'] == addon.pk assert result['status'] == 'incomplete' assert result['name'] == {'en-US': u'My Addôn'} assert result['slug'] == 'my-addon' assert result['last_updated'] == addon.last_updated.isoformat() + 'Z' assert result['latest_unlisted_version'] assert (result['latest_unlisted_version']['id'] == addon.latest_unlisted_version.pk) result = data['results'][1] assert result['id'] == addon2.pk assert result['name'] == {'en-US': u'My second Addôn'} assert result['slug'] is None # Because it was deleted. assert result['status'] == 'deleted' assert result['latest_unlisted_version'] is None
def test_only_affects_legacy_addons_targeting_firefox_lower_than_56(self): # Should be included: addon = addon_factory(version_kw={'max_app_version': '55.*'}) addon2 = addon_factory(version_kw={'application': amo.ANDROID.id}) addon3 = addon_factory(type=amo.ADDON_THEME) # Should not be included: addon_factory(file_kw={'is_webextension': True}) addon_factory(version_kw={'max_app_version': '56.*'}) addon_factory(version_kw={'application': amo.THUNDERBIRD.id}) # Also should not be included, this super weird add-on targets both # Firefox and Thunderbird - with a low version for Thunderbird, but a # high enough (56.*) for Firefox to be ignored by the task. weird_addon = addon_factory( version_kw={'application': amo.THUNDERBIRD.id}) av_min, _ = AppVersion.objects.get_or_create( application=amo.FIREFOX.id, version='48.*') ApplicationsVersions.objects.get_or_create( application=amo.FIREFOX.id, version=weird_addon.current_version, min=av_min, max=self.firefox_56_star) with count_subtask_calls(pa.bump_appver_for_legacy_addons) as calls: call_command( 'process_addons', task='bump_appver_for_legacy_addons') assert len(calls) == 1 assert calls[0]['kwargs']['args'] == [[addon.pk, addon2.pk, addon3.pk]]
def test_valid_addon(self): addon_factory(slug='bar') form = ReplacementAddonAdmin( ReplacementAddon, admin.site).get_form(None)( {'guid': 'foo', 'path': '/addon/bar/'}) assert form.is_valid(), form.errors assert form.cleaned_data['path'] == '/addon/bar/'
def test_get_disco_recommendations(call_recommendation_server): expected_addons = [ addon_factory(guid='101@mozilla'), addon_factory(guid='102@mozilla'), addon_factory(guid='103@mozilla'), addon_factory(guid='104@mozilla'), ] # Only the first one has a DiscoveryItem. The rest should still be # returned. call_recommendation_server.return_value = [ '101@mozilla', '102@mozilla', '103@mozilla', '104@mozilla' ] recommendations = get_disco_recommendations('0', []) call_recommendation_server.assert_called_with( 'https://taar.dev.mozaws.net/v1/api/recommendations/', '0', None, verb='post') assert [result.addon for result in recommendations] == expected_addons # only valid, public add-ons should match guids incomplete_addon = expected_addons.pop() incomplete_addon.update(status=amo.STATUS_NULL) # Remove this one and have recommendations return a bad guid instead. expected_addons.pop() call_recommendation_server.return_value = [ '101@mozilla', '102@mozilla', '103@badbadguid', '104@mozilla' ] recommendations = get_disco_recommendations('0', []) assert [result.addon for result in recommendations] == expected_addons
def test_basic(self): addon = addon_factory(slug='my-addon', name=u'My Addôn', weekly_downloads=666, is_listed=False) addon2 = addon_factory(slug='my-second-addon', name=u'My second Addôn', weekly_downloads=555) addon2.delete() self.refresh() data = self.perform_search_with_senior_editor(self.url) # No query. assert data['count'] == 2 assert len(data['results']) == 2 result = data['results'][0] assert result['id'] == addon.pk assert result['is_listed'] is False assert result['status'] == 'public' assert result['name'] == {'en-US': u'My Addôn'} assert result['slug'] == 'my-addon' assert result['last_updated'] == addon.last_updated.isoformat() result = data['results'][1] assert result['id'] == addon2.pk assert result['name'] == {'en-US': u'My second Addôn'} assert result['slug'] is None # Because it was deleted. assert result['status'] == 'deleted'
def setUp(self): super(TestDiscoveryRecommendations, self).setUp() self.addons = [] # This one should not appear anywhere, position isn't set. DiscoveryItem.objects.create(addon=addon_factory()) for i in range(1, 8): if i % 3: type_ = amo.ADDON_PERSONA else: type_ = amo.ADDON_EXTENSION addon = addon_factory(type=type_) self.addons.append(addon) DiscoveryItem.objects.create(addon=addon, position=i) for i in range(1, 8): if i % 3: type_ = amo.ADDON_PERSONA else: type_ = amo.ADDON_EXTENSION addon = addon_factory(type=type_) DiscoveryItem.objects.create(addon=addon, position_china=i) patcher = mock.patch( 'olympia.discovery.views.get_recommendations') self.get_recommendations = patcher.start() self.addCleanup(patcher.stop) # If no recommendations then results should be as before - tests from # the parent class check this. self.get_recommendations.return_value = [] self.url = reverse_ns('discovery-list')
def test_response(self): lwt = addon_factory(type=amo.ADDON_PERSONA) lwt.persona.persona_id = 666 lwt.persona.save() stheme = addon_factory(type=amo.ADDON_STATICTHEME) stheme.current_version.files.all()[0].update( filename='foo.xpi', hash='brown') MigratedLWT.objects.create( lightweight_theme=lwt, static_theme=stheme, getpersonas_id=666) update = self.get_update('en-US', lwt.id) response = json.loads(update.get_json()) url = '{0}{1}/{2}?{3}'.format( user_media_url('addons'), str(stheme.id), 'foo.xpi', urllib.urlencode({'filehash': 'brown'})) assert update.data == { 'stheme_id': stheme.id, 'filename': 'foo.xpi', 'hash': 'brown'} assert response == { "converted_theme": { "url": url, "hash": 'brown' } } update = self.get_update('en-US', 666, 'src=gp') response = json.loads(update.get_json()) assert update.data == { 'stheme_id': stheme.id, 'filename': 'foo.xpi', 'hash': 'brown'} assert response == { "converted_theme": { "url": url, "hash": 'brown' } }
def test_migrate_lwts_to_static_themes(add_static_theme_from_lwt_mock): persona_a = addon_factory(type=amo.ADDON_PERSONA, slug='theme_a') persona_b = addon_factory(type=amo.ADDON_PERSONA, slug='theme_b') addon_a = addon_factory(type=amo.ADDON_STATICTHEME) addon_b = addon_factory(type=amo.ADDON_STATICTHEME) add_static_theme_from_lwt_mock.side_effect = [addon_a, addon_b] # call the migration task, as the command would: migrate_lwts_to_static_themes([persona_a.id, persona_b.id]) assert MigratedLWT.objects.all().count() == 2 persona_a.reload() addon_a.reload() assert persona_a.status == amo.STATUS_DELETED assert MigratedLWT.objects.get( lightweight_theme=persona_a).static_theme == addon_a assert addon_a.slug == 'theme_a' persona_b.reload() addon_a.reload() assert persona_b.status == amo.STATUS_DELETED assert MigratedLWT.objects.get( lightweight_theme=persona_b).static_theme == addon_b assert addon_b.slug == 'theme_b'
def test_repack_themes_for_69(): user_factory(id=settings.TASK_USER_ID) broken_theme = addon_factory(name='broken') already_theme = addon_factory(name='already') deprecated_theme = addon_factory( name='deprecated', version_kw={'version': '1.0'}) to_mock = 'olympia.addons.tasks.new_theme_version_with_69_properties' with mock.patch(to_mock) as new_theme_version_with_69_properties_mock: with mock.patch('olympia.addons.tasks.parse_addon') as parse_mock: parse_mock.configure_mock(side_effect=[ IOError(), {'theme': {'colors': {'frame': '#baa'}}}, {'theme': {'colors': {'accentcolor': '#f00'}}}, ]) # call the task, as the command would: repack_themes_for_69([ broken_theme.id, already_theme.id, deprecated_theme.id, ]) new_theme_version_with_69_properties_mock.assert_called_once() new_theme_version_with_69_properties_mock.assert_called_with( deprecated_theme.current_version)
def test_count_stats_for_date(self): # Add a listed add-on, it should show up in "addon_count_new". listed_addon = addon_factory(created=datetime.datetime.now()) # Add an unlisted version to that add-on, it should *not* increase the # "version_count_new" count. version_factory( addon=listed_addon, channel=amo.RELEASE_CHANNEL_UNLISTED) # Add an unlisted add-on, it should not show up in either # "addon_count_new" or "version_count_new". addon_factory(version_kw={ 'channel': amo.RELEASE_CHANNEL_UNLISTED }) date = datetime.date.today() job = 'addon_count_new' tasks.update_global_totals(job, date) global_stat = GlobalStat.objects.get(date=date, name=job) assert global_stat.count == 1 # Should still work if the date is passed as a datetime string (what # celery serialization does). job = 'version_count_new' tasks.update_global_totals(job, datetime.datetime.now().isoformat()) global_stat = GlobalStat.objects.get(date=date, name=job) assert global_stat.count == 1
def test_recreate_theme_previews(): xpi_path = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/mozilla_static_theme.zip') addon_without_previews = addon_factory(type=amo.ADDON_STATICTHEME) copy_stored_file( xpi_path, addon_without_previews.current_version.all_files[0].file_path) addon_with_previews = addon_factory(type=amo.ADDON_STATICTHEME) copy_stored_file( xpi_path, addon_with_previews.current_version.all_files[0].file_path) VersionPreview.objects.create( version=addon_with_previews.current_version, sizes={'image': [123, 456], 'thumbnail': [34, 45]}) assert addon_without_previews.current_previews.count() == 0 assert addon_with_previews.current_previews.count() == 1 recreate_theme_previews( [addon_without_previews.id, addon_with_previews.id]) assert addon_without_previews.reload().current_previews.count() == 3 assert addon_with_previews.reload().current_previews.count() == 3 sizes = addon_without_previews.current_previews.values_list( 'sizes', flat=True) assert list(sizes) == [ {'image': list(amo.THEME_PREVIEW_SIZES['header']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['header']['thumbnail'])}, {'image': list(amo.THEME_PREVIEW_SIZES['list']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['list']['thumbnail'])}, {'image': list(amo.THEME_PREVIEW_SIZES['single']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['single']['thumbnail'])}]
def test_total_and_average_downloads(self): addon = Addon.objects.get(pk=3615) old_total_downloads = addon.total_downloads DownloadCount.objects.update_or_create( addon=addon, date=datetime.date.today(), defaults={'count': 42}) DownloadCount.objects.update_or_create( addon=addon, date=datetime.date.today() - datetime.timedelta(days=1), defaults={'count': 59}) addon_deleted = addon_factory() addon_deleted.delete() DownloadCount.objects.update_or_create( addon=addon_deleted, date=datetime.date.today(), defaults={'count': 666}) addon2 = addon_factory() DownloadCount.objects.update_or_create( addon=addon2, date=datetime.date.today() - datetime.timedelta(days=366), defaults={'count': 21}) addon_factory() # No downloads for this add-on cron.update_addon_download_totals() addon.reload() assert addon.total_downloads != old_total_downloads assert addon.total_downloads == 101 addon2.reload() assert addon2.total_downloads == 21
def test_add_static_theme_from_lwt(self): author = user_factory() persona = addon_factory( type=amo.ADDON_PERSONA, users=[author], name='Firefox Theme') persona.update( created=self.create_date, modified=self.modify_date, last_updated=self.update_date) persona.persona.license = licenses.LICENSE_CC_BY_ND.id Tag.objects.create(tag_text='themey').save_tag(persona) License.objects.create(builtin=licenses.LICENSE_CC_BY_ND.builtin) rating_user = user_factory() rating = Rating.objects.create( addon=persona, version=persona.current_version, user=rating_user, rating=2, body=u'fooooo', user_responsible=rating_user) ThemeUpdateCount.objects.create( addon_id=persona.id, date=datetime(2018, 1, 1), count=123) ThemeUpdateCount.objects.create( addon_id=persona.id, date=datetime(2018, 2, 1), count=456) # Create a count for an addon that shouldn't be migrated too. ThemeUpdateCount.objects.create( addon_id=addon_factory().id, date=datetime(2018, 2, 1), count=45) # And add it to a collection collection = collection_factory() collection.add_addon(persona) collection.add_addon(addon_factory()) static_theme = add_static_theme_from_lwt(persona) self._check_result( static_theme, [author], list(persona.tags.all()), persona.all_categories, licenses.LICENSE_CC_BY_ND.builtin, [rating], collection)
def setUp(self): self.persona = addon_factory(type=amo.ADDON_PERSONA) self.extension = addon_factory() self.static_theme = addon_factory(type=amo.ADDON_STATICTHEME) self.awaiting_review = addon_factory(status=amo.STATUS_NOMINATED) today = datetime.date.today() stats = [ (today - datetime.timedelta(days=days_in_past), update_count) for days_in_past, update_count in ( (1, 827080), (2, 787930), (3, 995860), (4, 1044260), (5, 105431), (6, 106065), (7, 980930), (8, 817100), (9, 78843), (10, 993830), (11, 104431), (12, 105943), (13, 105039), (14, 100183), (15, 82265), (16, 100183), (17, 82265), (18, 100183), (19, 82265), (20, 100183), (21, 82265), )] for obj in (self.persona, self.extension, self.static_theme, self.awaiting_review): UpdateCount.objects.bulk_create([ UpdateCount(addon=obj, date=date, count=count) for date, count in stats ])
def test_extract_persona(self): # Override self.addon with a persona. self.addon = addon_factory(persona_id=42, type=amo.ADDON_PERSONA) persona = self.addon.persona persona.header = u'myheader.jpg' persona.footer = u'myfooter.jpg' persona.accentcolor = u'336699' persona.textcolor = u'f0f0f0' persona.author = u'Me-me-me-Myself' persona.display_username = u'my-username' persona.save() extracted = self._extract() assert extracted['has_theme_rereview'] is False assert extracted['persona']['accentcolor'] == persona.accentcolor # We need the author that will go in theme_data here, which is # persona.display_username, not persona.author. assert extracted['persona']['author'] == persona.display_username assert extracted['persona']['header'] == persona.header assert extracted['persona']['footer'] == persona.footer assert extracted['persona']['is_new'] is False # It has a persona_id. assert extracted['persona']['textcolor'] == persona.textcolor self.addon = addon_factory(persona_id=0, type=amo.ADDON_PERSONA) extracted = self._extract() assert extracted['persona']['is_new'] is True # No persona_id.
def test_hotness_normal_strict_opt_in(self): # Add a 3rd add-on that should get filtered out b/c of compatibility. addon_factory(hotness=50, version_kw=dict(max_app_version='7.0'), file_kw=dict(strict_compatibility=True)) res = self.client.get(self._url(version='12.0', compat_mode='normal')) eq_(res.status_code, 200) eq_(pq(res.content)('.featured-addons').length, 2)
def test_themes_less_than_initial(self): """ Number of themes in the pool is less than amount we want to check out. """ addon_factory(type=amo.ADDON_PERSONA, status=self.status) reviewer = self.create_and_become_reviewer() assert len(_get_themes(mock.Mock(), reviewer)) == 1 assert len(_get_themes(mock.Mock(), reviewer)) == 1
def test_hotness_normal_binary_components(self): # Add a 3rd add-on that should get filtered out b/c of compatibility. addon_factory(hotness=50, version_kw=dict(max_app_version='7.0'), file_kw=dict(binary_components=True)) res = self.client.get(self._url(version='12.0', compat_mode='normal')) assert res.status_code == 200 assert pq(res.content)('.featured-addons').length == 2
def test_total_reviews(self): addon = addon_factory() addon2 = addon_factory() # Add a purely unlisted add-on. It should not be considered when # calculating bayesian rating for the other add-ons. addon3 = addon_factory(total_reviews=3, average_rating=4) self.make_addon_unlisted(addon3) # Create a few reviews with various ratings. review = Review.objects.create( addon=addon, rating=3, user=user_factory()) Review.objects.create(addon=addon, rating=3, user=user_factory()) Review.objects.create(addon=addon, rating=2, user=user_factory()) Review.objects.create(addon=addon, rating=1, user=user_factory()) # On another addon as well. Review.objects.create(addon=addon2, rating=1, user=user_factory()) Review.objects.create(addon=addon2, rating=1, user=user_factory()) # addon_review_aggregates should ignore replies, so let's add one. Review.objects.create( addon=addon, rating=5, user=user_factory(), reply_to=review) # Make sure total_reviews hasn't been updated yet (because we are # mocking Review.refresh()). addon.reload() addon2.reload() assert addon.total_reviews == 0 assert addon2.total_reviews == 0 assert addon.bayesian_rating == 0 assert addon.average_rating == 0 assert addon2.bayesian_rating == 0 assert addon2.average_rating == 0 # Trigger the task and test results. addon_review_aggregates([addon.pk, addon2.pk]) addon.reload() addon2.reload() assert addon.total_reviews == 4 assert addon2.total_reviews == 2 assert addon.bayesian_rating == 1.9821428571428572 assert addon.average_rating == 2.25 assert addon2.bayesian_rating == 1.375 assert addon2.average_rating == 1.0 # Trigger the task with a single add-on. Review.objects.create(addon=addon2, rating=5, user=user_factory()) addon2.reload() assert addon2.total_reviews == 2 addon_review_aggregates(addon2.pk) addon2.reload() assert addon2.total_reviews == 3 assert addon.bayesian_rating == 1.9821428571428572 assert addon.average_rating == 2.25 assert addon2.bayesian_rating == 1.97915 assert addon2.average_rating == 2.3333
def setUp(self): super(TestThemeSearch, self).setUp() self.addon = addon_factory(type=amo.ADDON_PERSONA, name='themeteam', status=amo.STATUS_PENDING) self.refresh('default')
def test_basic(self): av_min, _ = AppVersion.objects.get_or_create( application=amo.ANDROID.id, version='48.0') av_max, _ = AppVersion.objects.get_or_create( application=amo.ANDROID.id, version='48.*') av_seamonkey_min, _ = AppVersion.objects.get_or_create( application=amo.SEAMONKEY.id, version='2.49.3') av_seamonkey_max, _ = AppVersion.objects.get_or_create( application=amo.SEAMONKEY.id, version='2.49.*') # Those add-ons should not be deleted, because they are compatible with # at least Firefox or Firefox for Android. addon_factory() # A pure Firefox add-on addon_factory(version_kw={'application': amo.ANDROID.id}) addon_with_both_firefoxes = addon_factory() ApplicationsVersions.objects.get_or_create( application=amo.ANDROID.id, version=addon_with_both_firefoxes.current_version, min=av_min, max=av_max) addon_with_thunderbird_and_android = addon_factory( version_kw={'application': amo.THUNDERBIRD.id}) ApplicationsVersions.objects.get_or_create( application=amo.ANDROID.id, version=addon_with_thunderbird_and_android.current_version, min=av_min, max=av_max) addon_with_firefox_and_seamonkey = addon_factory( version_kw={'application': amo.FIREFOX.id}) ApplicationsVersions.objects.get_or_create( application=amo.SEAMONKEY.id, version=addon_with_firefox_and_seamonkey.current_version, min=av_seamonkey_min, max=av_seamonkey_max) addon_factory( status=amo.STATUS_NULL, # Non-public, will cause it to be ignored. version_kw={'application': amo.THUNDERBIRD.id}) # Those add-ons should be deleted as they are only compatible with # Thunderbird or Seamonkey, or both. addon = addon_factory(version_kw={'application': amo.THUNDERBIRD.id}) addon2 = addon_factory( version_kw={ 'application': amo.SEAMONKEY.id, 'min_app_version': '2.49.3', 'max_app_version': '2.49.*' }) addon3 = addon_factory(version_kw={'application': amo.THUNDERBIRD.id}) ApplicationsVersions.objects.get_or_create( application=amo.SEAMONKEY.id, version=addon3.current_version, min=av_seamonkey_min, max=av_seamonkey_max) # We've manually changed the ApplicationVersions, so let's run # update_appsupport() on all public add-ons. In the real world that is # done automatically when uploading a new version, either through the # version_changed signal or via a cron that catches any versions that # somehow fell through the cracks once a day. update_appsupport(Addon.objects.public().values_list('pk', flat=True)) assert Addon.objects.count() == 9 with count_subtask_calls( pa.delete_addon_not_compatible_with_firefoxes) as calls: self.make_the_call() assert len(calls) == 1 assert calls[0]['kwargs']['args'] == [[addon.pk, addon2.pk, addon3.pk]] assert not Addon.objects.filter(pk=addon.pk).exists() assert not Addon.objects.filter(pk=addon2.pk).exists() assert not Addon.objects.filter(pk=addon3.pk).exists() assert Addon.objects.count() == 6 # Make sure ApplicationsVersions targeting Thunderbird or Seamonkey are # gone. assert not ApplicationsVersions.objects.filter( application=amo.SEAMONKEY.id).exists() assert not ApplicationsVersions.objects.filter( application=amo.THUNDERBIRD.id).exists() # Make sure AppSupport targeting Thunderbird or Seamonkey are gone for # add-ons we touched. assert not AppSupport.objects.filter(addon__in=(addon, addon2, addon3), app=amo.SEAMONKEY.id).exists() assert not AppSupport.objects.filter(addon__in=(addon, addon2, addon3), app=amo.THUNDERBIRD.id).exists()
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_run(self): # Pretend we went through the admin. self.rule.update(state=SCHEDULED) # Similar to test_run_on_chunk() except it needs to find the versions # by itself. other_addon = addon_factory( file_kw={'is_webextension': True}, version_kw={'created': self.days_ago(1)}, ) other_addon_previous_current_version = other_addon.current_version included_versions = [ # Only listed webextension version on this add-on. self.version, # Unlisted webextension version of this add-on. addon_factory( disabled_by_user=True, # Doesn't matter. file_kw={ 'is_webextension': True }, version_kw={ 'channel': amo.RELEASE_CHANNEL_UNLISTED }, ).versions.get(), # Unlisted webextension version of an add-on that has multiple # versions. version_factory( addon=other_addon, created=self.days_ago(42), channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'is_webextension': True}, ), # Listed webextension versions of an add-on that has multiple # versions. other_addon_previous_current_version, version_factory(addon=other_addon, file_kw={'is_webextension': True}), ] # Ignored versions: # Listed Webextension version belonging to mozilla disabled add-on. addon_factory(file_kw={ 'is_webextension': True }, status=amo.STATUS_DISABLED).current_version # Non-Webextension addon_factory(file_kw={'is_webextension': False}).current_version for version in Version.unfiltered.all(): self.xpi_copy_over(version.all_files[0], 'webextension.xpi') # Run the task. run_yara_query_rule.delay(self.rule.pk) assert ScannerQueryResult.objects.count() == len(included_versions) assert sorted( ScannerQueryResult.objects.values_list( 'version_id', flat=True)) == sorted(v.pk for v in included_versions) self.rule.reload() assert self.rule.state == COMPLETED assert self.rule.task_count == 1 # We run tests in eager mode, so we can't retrieve the result for real, # just make sure the id was set to something. assert self.rule.celery_group_result_id is not None
def test_basic(self, sign_file_mock): file_kw = {'is_webextension': True, 'filename': 'webextension.xpi'} with freeze_time('2019-04-01'): addon_with_history = addon_factory(file_kw=file_kw) # Create a few more versions for this add-on to test that we only # re-sign current versions version_factory(addon=addon_with_history, file_kw=file_kw) version_factory(addon=addon_with_history, file_kw=file_kw) version_factory(addon=addon_with_history, file_kw=file_kw) addon_factory(file_kw=file_kw) addon_factory(type=amo.ADDON_STATICTHEME, file_kw=file_kw) addon_factory(type=amo.ADDON_LPAPP, file_kw=file_kw) addon_factory(type=amo.ADDON_DICT, file_kw=file_kw) # Don't resign add-ons created after April 4th 2019 with freeze_time('2019-05-01'): addon_factory(file_kw=file_kw) addon_factory(type=amo.ADDON_STATICTHEME, file_kw=file_kw) # Search add-ons won't get re-signed, same with deleted and disabled # versions. Also, only public addons are being resigned addon_factory(type=amo.ADDON_SEARCH, file_kw=file_kw) addon_factory(status=amo.STATUS_DISABLED, file_kw=file_kw) addon_factory(status=amo.STATUS_AWAITING_REVIEW, file_kw=file_kw) addon_factory(status=amo.STATUS_NULL, file_kw=file_kw) call_command('process_addons', task='resign_addons_for_cose') assert sign_file_mock.call_count == 5
def create_file_upload(self): addon = addon_factory() return FileUpload.objects.create(addon=addon)
def test_repr_when_strict(self): addon = addon_factory(version_kw=self.version_kw, file_kw=dict(strict_compatibility=True)) version = addon.current_version assert six.text_type(version.apps.all()[0]) == 'Firefox 5.0 - 6.*'
def test_approve_addons_get_files_incomplete(): """An incomplete add-on can't be approved.""" addon = addon_factory(status=amo.STATUS_NULL) assert approve_addons.get_files([addon.guid]) == []
def test_approve_addons_get_review_type_already_approved(): """The review type for a file that doesn't need approval is None.""" addon = addon_factory(status=amo.STATUS_PUBLIC) file_ = addon.versions.get().files.get() file_.update(status=amo.STATUS_PUBLIC) assert approve_addons.get_review_type(file_) is None
def test_basic(self): self.addon = addon_factory( average_daily_users=4242, average_rating=4.21, description=u'My Addôn description', file_kw={ 'hash': 'fakehash', 'platform': amo.PLATFORM_WIN.id, 'size': 42, }, guid=generate_addon_guid(), homepage=u'https://www.example.org/', icon_type='image/png', name=u'My Addôn', public_stats=True, slug='my-addon', summary=u'My Addôn summary', support_email=u'*****@*****.**', support_url=u'https://support.example.org/support/my-addon/', tags=['some_tag', 'some_other_tag'], total_reviews=666, weekly_downloads=2147483647, ) AddonUser.objects.create(user=user_factory(username='******'), addon=self.addon, listed=False) second_author = user_factory( username='******', display_name=u'Secönd Author') first_author = user_factory( username='******', display_name=u'First Authôr') AddonUser.objects.create( user=second_author, addon=self.addon, position=2) AddonUser.objects.create( user=first_author, addon=self.addon, position=1) second_preview = Preview.objects.create( addon=self.addon, position=2, caption={'en-US': u'My câption', 'fr': u'Mön tîtré'}) first_preview = Preview.objects.create(addon=self.addon, position=1) av_min = AppVersion.objects.get_or_create( application=amo.THUNDERBIRD.id, version='2.0.99')[0] av_max = AppVersion.objects.get_or_create( application=amo.THUNDERBIRD.id, version='3.0.99')[0] ApplicationsVersions.objects.get_or_create( application=amo.THUNDERBIRD.id, version=self.addon.current_version, min=av_min, max=av_max) # Reset current_version.compatible_apps now that we've added an app. del self.addon.current_version.compatible_apps cat1 = Category.from_static_category( CATEGORIES[amo.FIREFOX.id][amo.ADDON_EXTENSION]['bookmarks']) cat1.save() AddonCategory.objects.create(addon=self.addon, category=cat1) cat2 = Category.from_static_category( CATEGORIES[amo.FIREFOX.id][amo.ADDON_EXTENSION]['alerts-updates']) cat2.save() AddonCategory.objects.create(addon=self.addon, category=cat2) cat3 = Category.from_static_category( CATEGORIES[amo.THUNDERBIRD.id][amo.ADDON_EXTENSION]['calendar']) cat3.save() AddonCategory.objects.create(addon=self.addon, category=cat3) result = self.serialize() assert result['id'] == self.addon.pk assert result['average_daily_users'] == self.addon.average_daily_users assert result['categories'] == { 'firefox': ['alerts-updates', 'bookmarks'], 'thunderbird': ['calendar']} assert result['current_beta_version'] is None assert result['current_version'] self._test_version( self.addon.current_version, result['current_version']) assert result['authors'] assert len(result['authors']) == 2 assert result['authors'][0] == { 'id': first_author.pk, 'name': first_author.name, 'url': absolutify(first_author.get_url_path())} assert result['authors'][1] == { 'id': second_author.pk, 'name': second_author.name, 'url': absolutify(second_author.get_url_path())} assert result['edit_url'] == absolutify(self.addon.get_dev_url()) assert result['default_locale'] == self.addon.default_locale assert result['description'] == {'en-US': self.addon.description} assert result['guid'] == self.addon.guid assert result['has_eula'] is False assert result['has_privacy_policy'] is False assert result['homepage'] == {'en-US': self.addon.homepage} assert result['icon_url'] == absolutify(self.addon.get_icon_url(64)) assert result['is_disabled'] == self.addon.is_disabled assert result['is_experimental'] == self.addon.is_experimental is False assert result['is_listed'] == self.addon.is_listed assert result['is_source_public'] == self.addon.view_source assert result['name'] == {'en-US': self.addon.name} assert result['last_updated'] == ( self.addon.last_updated.isoformat() + 'Z') assert result['previews'] assert len(result['previews']) == 2 result_preview = result['previews'][0] assert result_preview['id'] == first_preview.pk assert result_preview['caption'] is None assert result_preview['image_url'] == absolutify( first_preview.image_url) assert result_preview['thumbnail_url'] == absolutify( first_preview.thumbnail_url) result_preview = result['previews'][1] assert result_preview['id'] == second_preview.pk assert result_preview['caption'] == { 'en-US': u'My câption', 'fr': u'Mön tîtré' } assert result_preview['image_url'] == absolutify( second_preview.image_url) assert result_preview['thumbnail_url'] == absolutify( second_preview.thumbnail_url) assert result['ratings'] == { 'average': self.addon.average_rating, 'count': self.addon.total_reviews, } assert result['public_stats'] == self.addon.public_stats assert result['review_url'] == absolutify( reverse('editors.review', args=[self.addon.pk])) assert result['slug'] == self.addon.slug assert result['status'] == 'public' assert result['summary'] == {'en-US': self.addon.summary} assert result['support_email'] == {'en-US': self.addon.support_email} assert result['support_url'] == {'en-US': self.addon.support_url} assert 'theme_data' not in result assert set(result['tags']) == set(['some_tag', 'some_other_tag']) assert result['type'] == 'extension' assert result['url'] == absolutify(self.addon.get_url_path()) assert result['weekly_downloads'] == self.addon.weekly_downloads return result
def test_is_experimental(self): self.addon = addon_factory(is_experimental=True) result = self.serialize() assert result['is_experimental'] is True
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', '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.isoformat() + 'Z') assert result['files'][0]['hash'] == first_file.hash 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.isoformat() + 'Z') assert result['files'][1]['hash'] == second_file.hash 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['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']) == { '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.isoformat() + 'Z' assert result['url'] == absolutify(self.version.get_url_path())
def test_unlisted(self): self.addon = addon_factory(name=u'My Unlisted Addôn', is_listed=False) result = self.serialize() assert result['id'] == self.addon.pk assert result['is_listed'] == self.addon.is_listed
def test_is_source_public(self): self.addon = addon_factory(view_source=True) result = self.serialize() assert result['is_source_public'] is True
def test_repr_when_compatible(self): addon = addon_factory(version_kw=self.version_kw) version = addon.current_version assert six.text_type(version.apps.all()[0]) == 'Firefox 5.0 and later'
def test_is_listed(self): self.addon = addon_factory(is_listed=False) result = self.serialize() assert result['is_listed'] is False
def setUp(self): self.addon1 = addon_factory() self.addon2 = addon_factory() self.file1 = self.addon1.current_version.all_files[0]
def test_is_disabled(self): self.addon = addon_factory(disabled_by_user=True) result = self.serialize() assert result['is_disabled'] is True
def test_affects_correct_addons(self): # *not considered* - Non auto-approved add-on addon_factory() # *not considered* - Non auto-approved add-on that has an # AutoApprovalSummary entry AutoApprovalSummary.objects.create( version=addon_factory().current_version, verdict=amo.NOT_AUTO_APPROVED) # *not considered* -Add-on with the current version not auto-approved extra_addon = addon_factory() AutoApprovalSummary.objects.create( version=extra_addon.current_version, verdict=amo.AUTO_APPROVED) extra_addon.current_version.update(created=self.days_ago(1)) version_factory(addon=extra_addon) # *not considered* - current version is auto-approved but doesn't # have recent abuse reports or low ratings auto_approved_addon = addon_factory() AutoApprovalSummary.objects.create( version=auto_approved_addon.current_version, verdict=amo.AUTO_APPROVED) # *considered* - current version is auto-approved and # has a recent rating with rating <= 3 auto_approved_addon1 = addon_factory() summary = AutoApprovalSummary.objects.create( version=auto_approved_addon1.current_version, verdict=amo.AUTO_APPROVED) Rating.objects.create( created=summary.modified + timedelta(days=3), addon=auto_approved_addon1, version=auto_approved_addon1.current_version, rating=2, body='Apocalypse', user=user_factory()), # *not considered* - current version is auto-approved but # has a recent rating with rating > 3 auto_approved_addon2 = addon_factory() summary = AutoApprovalSummary.objects.create( version=auto_approved_addon2.current_version, verdict=amo.AUTO_APPROVED) Rating.objects.create( created=summary.modified + timedelta(days=3), addon=auto_approved_addon2, version=auto_approved_addon2.current_version, rating=4, body='Apocalypse', user=user_factory()), # *not considered* - current version is auto-approved but # has a recent rating with rating > 3 auto_approved_addon3 = addon_factory() summary = AutoApprovalSummary.objects.create( version=auto_approved_addon3.current_version, verdict=amo.AUTO_APPROVED) Rating.objects.create( created=summary.modified + timedelta(days=3), addon=auto_approved_addon3, version=auto_approved_addon3.current_version, rating=4, body='Apocalypse', user=user_factory()), # *not considered* - current version is auto-approved but # has a low rating that isn't recent enough auto_approved_addon4 = addon_factory() summary = AutoApprovalSummary.objects.create( version=auto_approved_addon4.current_version, verdict=amo.AUTO_APPROVED) Rating.objects.create( created=summary.modified - timedelta(days=3), addon=auto_approved_addon4, version=auto_approved_addon4.current_version, rating=1, body='Apocalypse', user=user_factory()), # *considered* - current version is auto-approved and # has a recent abuse report auto_approved_addon5 = addon_factory() summary = AutoApprovalSummary.objects.create( version=auto_approved_addon5.current_version, verdict=amo.AUTO_APPROVED) AbuseReport.objects.create( addon=auto_approved_addon5, created=summary.modified + timedelta(days=3)) # *not considered* - current version is auto-approved but # has an abuse report that isn't recent enough auto_approved_addon6 = addon_factory() summary = AutoApprovalSummary.objects.create( version=auto_approved_addon6.current_version, verdict=amo.AUTO_APPROVED) AbuseReport.objects.create( addon=auto_approved_addon6, created=summary.modified - timedelta(days=3)) # *considered* - current version is auto-approved and # has an abuse report through it's author that is recent enough author = user_factory() auto_approved_addon7 = addon_factory(users=[author]) summary = AutoApprovalSummary.objects.create( version=auto_approved_addon7.current_version, verdict=amo.AUTO_APPROVED) AbuseReport.objects.create( user=author, created=summary.modified + timedelta(days=3)) # *not considered* - current version is auto-approved and # has an abuse report through it's author that is recent enough # BUT the abuse report is deleted. author = user_factory() auto_approved_addon8 = addon_factory(users=[author]) summary = AutoApprovalSummary.objects.create( version=auto_approved_addon8.current_version, verdict=amo.AUTO_APPROVED) AbuseReport.objects.create( user=author, state=AbuseReport.STATES.DELETED, created=summary.modified + timedelta(days=3)) # *not considered* - current version is auto-approved and # has a recent rating with rating <= 3 # but the rating is deleted. auto_approved_addon9 = addon_factory() summary = AutoApprovalSummary.objects.create( version=auto_approved_addon9.current_version, verdict=amo.AUTO_APPROVED) Rating.objects.create( created=summary.modified + timedelta(days=3), addon=auto_approved_addon9, version=auto_approved_addon9.current_version, deleted=True, rating=2, body='Apocalypse', user=user_factory()), # *considered* - current version is auto-approved and # has an abuse report through it's author that is recent enough # Used to test that we only recalculate the weight for # the most recent version author = user_factory() auto_approved_addon8 = addon_factory( users=[author], version_kw={'version': '0.1'}) AutoApprovalSummary.objects.create( version=auto_approved_addon8.current_version, verdict=amo.AUTO_APPROVED) # Let's create a new `current_version` and summary current_version = version_factory( addon=auto_approved_addon8, version='0.2') summary = AutoApprovalSummary.objects.create( version=current_version, verdict=amo.AUTO_APPROVED) AbuseReport.objects.create( user=author, created=summary.modified + timedelta(days=3)) mod = 'olympia.reviewers.tasks.AutoApprovalSummary.calculate_weight' with mock.patch(mod) as calc_weight_mock: with count_subtask_calls( process_addons.recalculate_post_review_weight) as calls: call_command( 'process_addons', task='constantly_recalculate_post_review_weight') assert len(calls) == 1 assert calls[0]['kwargs']['args'] == [[ auto_approved_addon1.pk, auto_approved_addon5.pk, auto_approved_addon7.pk, auto_approved_addon8.pk, ]] # Only 4 calls for each add-on, doesn't consider the extra version # that got created for addon 8 assert calc_weight_mock.call_count == 4
def test_with_addon(self): addon_factory(guid=self.block.guid, name='Addón náme') serializer = BlockSerializer(instance=self.block) assert serializer.data['addon_name'] == {'en-US': 'Addón náme'}
def test_latest_public_compatible_with(self): # Add compatible add-ons. We're going to request versions compatible # with 58.0. compatible_pack1 = addon_factory( name='Spanish Language Pack', type=amo.ADDON_LPAPP, target_locale='es', file_kw={'strict_compatibility': True}, version_kw={ 'min_app_version': '57.0', 'max_app_version': '57.*' }) compatible_pack1.current_version.update(created=self.days_ago(2)) compatible_version1 = version_factory( addon=compatible_pack1, file_kw={'strict_compatibility': True}, min_app_version='58.0', max_app_version='58.*') compatible_version1.update(created=self.days_ago(1)) compatible_pack2 = addon_factory( name='French Language Pack', type=amo.ADDON_LPAPP, target_locale='fr', file_kw={'strict_compatibility': True}, version_kw={ 'min_app_version': '58.0', 'max_app_version': '58.*' }) compatible_version2 = compatible_pack2.current_version compatible_version2.update(created=self.days_ago(2)) version_factory(addon=compatible_pack2, file_kw={'strict_compatibility': True}, min_app_version='59.0', max_app_version='59.*') # Add a more recent version for both add-ons, that would be compatible # with 58.0, but is not public/listed so should not be returned. version_factory(addon=compatible_pack1, file_kw={'strict_compatibility': True}, min_app_version='58.0', max_app_version='58.*', channel=amo.RELEASE_CHANNEL_UNLISTED) version_factory(addon=compatible_pack2, file_kw={ 'strict_compatibility': True, 'status': amo.STATUS_DISABLED }, min_app_version='58.0', max_app_version='58.*') # And for the first pack, add a couple of versions that are also # compatible. They are older so should appear after. extra_compatible_version_1 = version_factory( addon=compatible_pack1, file_kw={'strict_compatibility': True}, min_app_version='58.0', max_app_version='58.*') extra_compatible_version_1.update(created=self.days_ago(3)) extra_compatible_version_2 = version_factory( addon=compatible_pack1, file_kw={'strict_compatibility': True}, min_app_version='58.0', max_app_version='58.*') extra_compatible_version_2.update(created=self.days_ago(4)) # Add a few of incompatible add-ons. incompatible_pack1 = addon_factory( name='German Language Pack (incompatible with 58.0)', type=amo.ADDON_LPAPP, target_locale='fr', file_kw={'strict_compatibility': True}, version_kw={ 'min_app_version': '56.0', 'max_app_version': '56.*' }) version_factory(addon=incompatible_pack1, file_kw={'strict_compatibility': True}, min_app_version='59.0', max_app_version='59.*') addon_factory(name='Italian Language Pack (incompatible with 58.0)', type=amo.ADDON_LPAPP, target_locale='it', file_kw={'strict_compatibility': True}, version_kw={ 'min_app_version': '59.0', 'max_app_version': '59.*' }) # Even add a pack with a compatible version... not public. And another # one with a compatible version... not listed. incompatible_pack2 = addon_factory( name='Japanese Language Pack (public, but 58.0 version is not)', type=amo.ADDON_LPAPP, target_locale='ja', file_kw={'strict_compatibility': True}, version_kw={ 'min_app_version': '57.0', 'max_app_version': '57.*' }) version_factory(addon=incompatible_pack2, min_app_version='58.0', max_app_version='58.*', file_kw={ 'status': amo.STATUS_AWAITING_REVIEW, 'strict_compatibility': True }) incompatible_pack3 = addon_factory( name='Nederlands Language Pack (58.0 version is unlisted)', type=amo.ADDON_LPAPP, target_locale='ja', file_kw={'strict_compatibility': True}, version_kw={ 'min_app_version': '57.0', 'max_app_version': '57.*' }) version_factory(addon=incompatible_pack3, min_app_version='58.0', max_app_version='58.*', channel=amo.RELEASE_CHANNEL_UNLISTED, file_kw={'strict_compatibility': True}) appversions = { 'min': version_int('58.0'), 'max': version_int('58.0a'), } qs = Version.objects.latest_public_compatible_with( amo.FIREFOX.id, appversions) expected_versions = [ compatible_version1, compatible_version2, extra_compatible_version_1, extra_compatible_version_2 ] assert list(qs) == expected_versions
def get_object(self): version_preview = VersionPreview.objects.create( version=addon_factory().current_version) return version_preview
def test_basic(self, migrate_legacy_dictionarymock, index_addons_mock): self.counter = 0 def side_effect(*args, **kwargs): self.counter += 1 if self.counter == 2: raise ValidationError('Dummy validation error') addon_factory() addon_factory(type=amo.ADDON_LPAPP) addon_factory(type=amo.ADDON_STATICTHEME) addon_factory(type=amo.ADDON_DICT, file_kw={'is_webextension': True}) addon_factory(type=amo.ADDON_DICT, target_locale='es', status=amo.STATUS_DISABLED) addon_factory(type=amo.ADDON_DICT, target_locale='it', disabled_by_user=True) self.addon = addon_factory(type=amo.ADDON_DICT, target_locale='fr') self.addon2 = addon_factory(type=amo.ADDON_DICT, target_locale=None) self.addon3 = addon_factory(type=amo.ADDON_DICT, target_locale='') migrate_legacy_dictionarymock.side_effect = side_effect index_addons_mock.reset_mock() call_command('process_addons', task='migrate_legacy_dictionaries_to_webextension') assert migrate_legacy_dictionarymock.call_count == 3 actual_calls = (migrate_legacy_dictionarymock.call_args_list[0][0][0], migrate_legacy_dictionarymock.call_args_list[1][0][0], migrate_legacy_dictionarymock.call_args_list[2][0][0]) expected_calls = (self.addon, self.addon2, self.addon3) assert actual_calls == expected_calls # self.addon2 will raise a ValidationError because of the side_effect # above, so we should only reindex 1 and 3. assert index_addons_mock.call_args[0][0] == [self.addon, self.addon3]
def test_repr_when_unicode(self): addon = addon_factory( version_kw=dict(min_app_version=u'ك', max_app_version=u'ك')) version = addon.current_version assert six.text_type(version.apps.all()[0]) == u'Firefox ك - ك'
def setUp(self): super(TestPaneMoreAddons, self).setUp() self.addon1 = addon_factory(hotness=99, version_kw=dict(max_app_version='5.0')) self.addon2 = addon_factory(hotness=0, version_kw=dict(max_app_version='6.0'))
def test_repr_when_low_app_support(self): addon = addon_factory( version_kw=dict(min_app_version='3.0', max_app_version='3.5')) version = addon.current_version assert six.text_type(version.apps.all()[0]) == 'Firefox 3.0 - 3.5'
def setUp(self): super(TestDeletedThemeLookup, self).setUp() self.deleted = addon_factory(type=amo.ADDON_PERSONA) self.deleted.update(status=amo.STATUS_DELETED)
def test_repr_when_binary(self): addon = addon_factory(version_kw=self.version_kw, file_kw=dict(binary_components=True)) version = addon.current_version assert six.text_type(version.apps.all()[0]) == 'Firefox 5.0 - 6.*'
def test_no_license(self): addon = addon_factory() self.version = addon.current_version result = self.serialize() assert result['id'] == self.version.pk assert result['license'] is None
def test_icon_url_without_icon_type_set(self): self.addon = addon_factory() result = self.serialize() assert result['id'] == self.addon.pk assert result['icon_url'] == absolutify(self.addon.get_icon_url(64))