def test_match_client_match_locale(self): params = {} snippet = ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=['en-US']) ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=['fr']) self._assert_client_matches_snippets(params, [snippet])
def test_job(self): nightly_snippets = JobFactory.create_batch( 2, targets=[TargetFactory(on_release=False, on_nightly=True)]) JobFactory.create_batch(2, targets=[TargetFactory(on_release=False, on_beta=True)]) filtr = ChannelFilter(None, {'channel': 'on_nightly'}, Job, JobAdmin) result = filtr.queryset(None, Job.objects.all()) self.assertTrue(result.count(), 2) self.assertEqual(set(result.all()), set(nightly_snippets))
def test_save(self): data = self.data.copy() instance = TargetFactory() form = TargetAdminForm(data, instance=instance) self.assertTrue(form.is_valid()) form.save() instance.refresh_from_db() self.assertEqual(instance.jexl_expr, 'isDefaultBrowser == true') self.assertTrue(instance.filtr_is_default_browser)
def test_nightly_includes_release(self): release_job = JobFactory(status=models.Job.PUBLISHED, snippet__locale=',en,', targets=[ TargetFactory(on_release=True, on_beta=True, on_nightly=False, on_esr=False, on_aurora=False) ]) nightly_job = JobFactory(status=models.Job.PUBLISHED, snippet__locale=',en,', targets=[ TargetFactory(on_release=True, on_beta=False, on_nightly=True, on_esr=False, on_aurora=False) ]) # Beta only job, not to be included JobFactory(status=models.Job.PUBLISHED, snippet__locale=',en,', targets=[ TargetFactory(on_release=False, on_beta=True, on_nightly=False, on_esr=False, on_aurora=False) ]) with patch.multiple( 'snippets.base.management.commands.generate_bundles', json=DEFAULT, product_details=DEFAULT, default_storage=DEFAULT) as mock: mock['json'].dumps.return_value = '' mock['product_details'].languages.keys.return_value = ['en-us'] call_command('generate_bundles', stdout=Mock()) # Loop to find the nighlty bundle for arg_list in mock['json'].dumps.call_args_list: if arg_list[0][0]['metadata']['channel'] == 'nightly': self.assertEqual(len(arg_list[0][0]['messages']), 2) self.assertEqual( set([ arg_list[0][0]['messages'][0]['id'], arg_list[0][0]['messages'][1]['id'] ]), set([str(release_job.id), str(nightly_job.id)])) self.assertEqual( set([ arg_list[0][0]['messages'][0]['targeting'], arg_list[0][0]['messages'][1]['targeting'] ]), set(['', 'false']))
def test_modified_date_updates_when_target_updates(self): new_target = TargetFactory() snippet = ASRSnippetFactory() snippet.targets.add(new_target) old_modified = snippet.modified new_target.name = 'new name' new_target.save() snippet.refresh_from_db() new_modified = snippet.modified self.assertNotEqual(old_modified, new_modified)
def test_channels(self): job = JobFactory.create(targets=[ TargetFactory.create(on_release=True), TargetFactory.create(on_beta=True, on_nightly=True), TargetFactory.create(on_release=False, on_esr=False, on_aurora=False, on_beta=False, on_nightly=False), ]) self.assertTrue(job.channels, set(['release', 'beta', 'nightly']))
def test_match_client_invalid_locale(self): """ If client sends invalid locale return snippets with no locales specified. """ params = {'locale': 'foo'} snippet = ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=[]) ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=['en-us']) self._assert_client_matches_snippets(params, [snippet])
def test_match_client_match_channel_partially(self): """ Client channels like "release-cck-mozilla14" should match "release". """ params = {'channel': 'release-cck-mozilla14'} snippet = ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=['en-US']) ASRSnippetFactory.create( targets=[TargetFactory(on_release=False, on_startpage_6=True)], locales=['en-US']) self._assert_client_matches_snippets(params, [snippet])
def test_match_client_multiple_locales(self): """ If there are multiple locales that should match the client's locale, include all of them. """ params = {'locale': 'es-mx'} snippet_1 = ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=['es']) snippet_2 = ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=['es-mx']) self._assert_client_matches_snippets(params, [snippet_1, snippet_2])
def test_modified_date_updates_when_target_updates(self): target = TargetFactory() job = JobFactory(targets=[target]) snippet = job.snippet # Must refresh from db to get the actual datetime stored in db which # may be different by milliseconds from the original python datetime. snippet.refresh_from_db() old_modified = snippet.modified target.name = 'new name' target.save() snippet.refresh_from_db() new_modified = snippet.modified self.assertNotEqual(old_modified, new_modified)
def test_render(self): self.maxDiff = None job = JobFactory.create(weight=10, campaign__slug='demo-campaign', targets=[ TargetFactory(on_release=False, on_beta=False, on_esr=False, on_aurora=False, on_nightly=True, jexl_expr='(la==lo)'), TargetFactory(on_release=False, on_beta=True, on_esr=False, on_aurora=False, on_nightly=True), TargetFactory(on_release=False, on_beta=True, on_esr=False, on_aurora=False, on_nightly=True, jexl_expr='foo==bar'), ]) snippet_render = { 'template': 'simple_snippet', 'template_version': 'xx.xx', 'content': { 'block_button_text': 'Block me', 'text': 'This is text [[job_id]]', } } expected_output = copy.deepcopy(snippet_render) expected_output.update({ 'id': str(job.id), 'weight': 10, 'campaign': 'demo-campaign', 'targeting': '(la==lo) && foo==bar', 'content': { 'block_button_text': 'Block me', 'text': f'This is text {job.id}', } }) job.snippet.render = Mock() job.snippet.render.return_value = snippet_render generated_output = job.render() self.assertEqual(generated_output, expected_output)
def test_default_is_same_as_nightly(self): """ Make sure that default channel follows nightly. """ # Snippets matching nightly (and therefor should match default). nightly_snippet = ASRSnippetFactory.create(targets=[TargetFactory(on_nightly=True)]) # Snippets that don't match nightly ASRSnippetFactory.create(targets=[TargetFactory(on_beta=True)]) nightly_client = self._build_client(channel='nightly') nightly_snippets = ASRSnippet.objects.match_client(nightly_client) default_client = self._build_client(channel='default') default_snippets = ASRSnippet.objects.match_client(default_client) # Assert that both the snippets returned from nightly and from default # are the same snippets. Just `nightly_snippet` in this case. self.assertEqual(set([nightly_snippet]), set(nightly_snippets)) self.assertEqual(set([nightly_snippet]), set(default_snippets))
def test_match_client_multiple_locales_distinct(self): """ If a snippet has multiple locales and a client matches more than one of them, the snippet should only be included in the queryset once. """ params = {'locale': 'es-mx'} snippet = ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=['es', 'es-mx']) self._assert_client_matches_snippets(params, [snippet])
def test_render(self): snippet = ASRSnippetFactory.create( template_relation__text=( 'snippet id [[snippet_id]] and with ' '<a href="https://example.com/[[snippet_id]]/foo">link</a>'), targets=[ TargetFactory(jexl_expr='foo == bar'), TargetFactory(jexl_expr='lalo == true') ]) self.maxDiff = None generated_result = snippet.render() expected_result = { 'id': str(snippet.id), 'template': snippet.template_ng.code_name, 'template_version': snippet.template_ng.version, 'campaign': snippet.campaign.slug, 'weight': snippet.weight, 'content': { 'text': 'snippet id {} and with <link0>link</link0>'.format( snippet.id), 'links': { 'link0': { 'url': 'https://example.com/{}/foo'.format(snippet.id), } }, 'tall': False, 'icon': snippet.template_ng.icon.url, 'do_not_autoblock': False, 'block_button_text': 'Remove this', }, 'targeting': 'foo == bar && lalo == true' } self.assertEqual(generated_result, expected_result)
def test_render_always_eval_to_false(self): job = JobFactory.create(weight=10, campaign__slug='demo-campaign', targets=[ TargetFactory(on_release=False, on_beta=False, on_esr=False, on_aurora=False, on_nightly=True, jexl_expr='(la==lo)'), ]) job.snippet.render = Mock() job.snippet.render.return_value = {} generated_output = job.render(always_eval_to_false=True) self.assertEqual(generated_output['targeting'], '(la==lo) && false')
def test_render_preview_only(self): snippet = ASRSnippetFactory.create( template_relation__text='snippet id [[snippet_id]]', targets=[TargetFactory(jexl_expr='foo == bar')]) generated_result = snippet.render(preview=True) expected_result = { 'id': 'preview-{}'.format(snippet.id), 'template': snippet.template_ng.code_name, 'template_version': snippet.template_ng.version, 'campaign': 'preview-{}'.format(snippet.campaign.slug), 'weight': 100, 'content': { 'do_not_autoblock': True, 'text': 'snippet id {}'.format(snippet.id), 'links': {}, 'tall': False, 'icon': snippet.template_ng.icon.url, 'block_button_text': 'Remove this', } } self.assertEqual(generated_result, expected_result)
def test_delete_does_not_exist(self): target = TargetFactory(on_release=False, on_beta=False, on_nightly=True, on_esr=False, on_aurora=False) JobFactory( status=models.Job.COMPLETED, snippet__locale=',fr,', targets=[target], ) with patch( 'snippets.base.management.commands.generate_bundles.default_storage' ) as ds_mock: # Test that only removes if file exists. ds_mock.exists.return_value = False call_command('generate_bundles', stdout=Mock()) ds_mock.delete.assert_not_called() ds_mock.save.assert_not_called()
def test_delete(self): distribution = DistributionFactory() distribution_bundle = DistributionBundleFactory( code_name='foo', enabled=False, ) distribution_bundle.distributions.add(distribution) target = TargetFactory(on_release=False, on_beta=False, on_nightly=True, on_esr=False, on_aurora=False) JobFactory( status=models.Job.COMPLETED, snippet__locale=',fr,', targets=[target], ) # Still published, but belongs to a disabled distribution JobFactory( status=models.Job.PUBLISHED, snippet__locale=',fr,', targets=[target], distribution=distribution, ) with patch( 'snippets.base.management.commands.generate_bundles.default_storage' ) as ds_mock: # Test that only removes if file exists. ds_mock.exists.return_value = True call_command('generate_bundles', stdout=Mock()) ds_mock.delete.assert_has_calls([ call('pregen/Firefox/nightly/fr/default.json'), call('pregen/Firefox/nightly/fr/foo.json') ]) ds_mock.save.assert_not_called()
def test_match_client_base(self): client_match_rule_pass_1 = ClientMatchRuleFactory(channel='nightly') client_match_rule_pass_2 = ClientMatchRuleFactory(channel='/(beta|nightly)/') client_match_rule_fail = ClientMatchRuleFactory(channel='release') # Matching snippets. snippet_1 = ASRSnippetFactory.create( targets=[ TargetFactory(on_release=False, on_nightly=True, client_match_rules=[client_match_rule_pass_1]) ]) snippet_2 = ASRSnippetFactory.create( targets=[ TargetFactory(on_release=False, on_beta=True, on_nightly=True, client_match_rules=[client_match_rule_pass_2]) ]) snippet_3 = ASRSnippetFactory.create( targets=[TargetFactory(on_release=False, on_nightly=True)]) # Not matching snippets. ASRSnippetFactory.create(targets=[TargetFactory(on_release=False, on_beta=True)]) ASRSnippetFactory.create( targets=[ TargetFactory(on_nightly=True, client_match_rules=[client_match_rule_fail]) ]) ASRSnippetFactory.create( targets=[ TargetFactory(on_nightly=True, client_match_rules=[client_match_rule_fail, client_match_rule_pass_2]) ]) client = self._build_client(channel='nightly') snippets = ASRSnippet.objects.match_client(client) self.assertEqual(set(snippets), set([snippet_1, snippet_2, snippet_3]))
def test_is_custom(self): target = TargetFactory(on_release=True) self.assertTrue(target.is_custom) not_custom_target = TargetFactory(on_release=True, filtr_is_default_browser='true') self.assertFalse(not_custom_target.is_custom)
def test_match_client_not_matching_startpage(self): params = {'startpage_version': '0'} snippet = ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=['en-US']) self._assert_client_matches_snippets(params, [snippet])
def test_match_client_not_matching_locale(self): params = {'locale': 'en-US'} ASRSnippetFactory.create( targets=[TargetFactory(on_release=True, on_startpage_6=True)], locales=[]) self._assert_client_matches_snippets(params, [])
def test_generation(self): target = TargetFactory(on_release=True, on_beta=True, on_nightly=False, on_esr=False, on_aurora=False) # Draft, completed, scheduled or cancelled JobFactory( status=models.Job.DRAFT, snippet__locale=',en,', targets=[target], ) JobFactory( status=models.Job.COMPLETED, snippet__locale=',en,', targets=[target], ) JobFactory( status=models.Job.SCHEDULED, snippet__locale=',en,', targets=[target], ) JobFactory( status=models.Job.CANCELED, snippet__locale=',en,', targets=[target], ) JobFactory( status=models.Job.PUBLISHED, snippet__locale=',en,', targets=[target], distribution__name='not-default', ) # Jobs to be included in the bundle published_job_1 = JobFactory( status=models.Job.PUBLISHED, snippet__locale=',en,', targets=[target], ) published_job_2 = JobFactory( status=models.Job.PUBLISHED, snippet__locale=',en,', targets=[target], distribution__name='other-distribution-part-of-default-bundle', ) # Add Distribution to the Default DistributionBundle models.DistributionBundle.objects.get( name='Default').distributions.add( models.Distribution.objects.get( name='other-distribution-part-of-default-bundle')) with patch.multiple( 'snippets.base.management.commands.generate_bundles', json=DEFAULT, product_details=DEFAULT, default_storage=DEFAULT) as mock: mock['json'].dumps.return_value = '' mock['product_details'].languages.keys.return_value = [ 'fr', 'en-us', 'en-au' ] call_command('generate_bundles', stdout=Mock()) self.assertEqual(mock['default_storage'].save.call_count, 4) mock['default_storage'].save.assert_has_calls([ call('pregen/Firefox/release/en-us/default.json', ANY), call('pregen/Firefox/release/en-au/default.json', ANY), call('pregen/Firefox/beta/en-us/default.json', ANY), call('pregen/Firefox/beta/en-au/default.json', ANY), ], any_order=True) # Check that there's only one job included in the bundle and that it's # the correct one. self.assertEqual( len(mock['json'].dumps.call_args_list[0][0][0]['messages']), 2) self.assertEqual( set([ mock['json'].dumps.call_args_list[0][0][0]['messages'][0] ['id'], mock['json'].dumps.call_args_list[0][0][0]['messages'][1]['id'] ]), set([str(published_job_1.id), str(published_job_2.id)]))
def test_set_initial_jexl(self): data = self.data.copy() instance = TargetFactory(jexl={'filtr_is_default_browser': 'false'}) form = TargetAdminForm(data, instance=instance) self.assertEqual(form.fields['filtr_is_default_browser'].initial, 'false')
def test_publish_permission_check_asr(self): user = User.objects.create_user(username='******', email='*****@*****.**', password='******') perm_beta = Permission.objects.get(codename='publish_on_beta', content_type__model='asrsnippet') user.user_permissions.add(perm_beta) perm_nightly = Permission.objects.get(codename='publish_on_nightly', content_type__model='asrsnippet') user.user_permissions.add(perm_nightly) target_release = TargetFactory(on_release=True, on_beta=False, on_esr=False, on_nightly=False, on_aurora=False) target_beta = TargetFactory(on_release=False, on_beta=True, on_esr=False, on_nightly=False, on_aurora=False) target_nightly = TargetFactory(on_release=False, on_beta=False, on_esr=False, on_nightly=True, on_aurora=False) asrsnippet = ASRSnippetFactory(targets=[]) data = { 'name': 'Test', 'weight': 100, } # User should get an error trying to publish on Release new_data = data.copy() new_data['status'] = STATUS_CHOICES['Published'] new_data['targets'] = [target_release] form = ASRSnippetAdminForm(new_data, instance=asrsnippet) form.current_user = user self.assertFalse(form.is_valid()) self.assertTrue( 'You are not allowed to edit or publish on Release channel.' in form.errors['__all__'][0]) # User should get an error trying to edit or publish on Release even though Beta # is selected too. new_data = data.copy() new_data['status'] = STATUS_CHOICES['Published'] new_data['targets'] = [target_release, target_beta] form = ASRSnippetAdminForm(new_data, instance=asrsnippet) form.current_user = user self.assertFalse(form.is_valid()) self.assertTrue( 'You are not allowed to edit or publish on Release channel.' in form.errors['__all__'][0]) # Form is valid if user tries to edit or publish on Beta. new_data = data.copy() new_data['status'] = STATUS_CHOICES['Published'] new_data['targets'] = [target_beta] form = ASRSnippetAdminForm(new_data, instance=asrsnippet) form.current_user = user self.assertTrue(form.is_valid()) # Form is valid if user tries to publish or edit on Beta and Nightly. new_data = data.copy() new_data['status'] = STATUS_CHOICES['Published'] new_data['targets'] = [target_beta, target_nightly] form = ASRSnippetAdminForm(new_data, instance=asrsnippet) form.current_user = user self.assertTrue(form.is_valid()) # Form is invalid if user tries edit published Snippet on Release. instance = ASRSnippetFactory.create( status=STATUS_CHOICES['Published'], targets=[TargetFactory(on_release=True)]) new_data = data.copy() new_data['targets'] = [target_release, target_beta, target_nightly] form = ASRSnippetAdminForm(new_data, instance=instance) form.current_user = user self.assertFalse(form.is_valid()) self.assertTrue( 'You are not allowed to edit or publish on Release channel.' in form.errors['__all__'][0]) # User cannot unset Release channel and save. instance = ASRSnippetFactory.create( status=STATUS_CHOICES['Published'], targets=[TargetFactory(on_release=True)]) new_data = data.copy() new_data['targets'] = [target_beta, target_nightly] form = ASRSnippetAdminForm(new_data, instance=instance) form.current_user = user self.assertFalse(form.is_valid()) self.assertTrue( 'You are not allowed to edit or publish on Release channel.' in form.errors['__all__'][0]) # User can un-publish if they have permission on all channels. instance = ASRSnippetFactory.create(status=STATUS_CHOICES['Published'], targets=[ TargetFactory(on_release=False, on_beta=True, on_nightly=True) ]) new_data = data.copy() new_data['status'] = STATUS_CHOICES['Approved'] new_data['targets'] = [target_beta, target_nightly] form = ASRSnippetAdminForm(new_data, instance=instance) form.current_user = user self.assertTrue(form.is_valid()) # User cannot un-publish if they don't have permission on all channels. instance = ASRSnippetFactory.create( status=STATUS_CHOICES['Published'], targets=[TargetFactory(on_release=True, on_nightly=True)]) new_data = data.copy() new_data['status'] = STATUS_CHOICES['Approved'] new_data['targets'] = [target_release, target_nightly] form = ASRSnippetAdminForm(new_data, instance=instance) form.current_user = user self.assertFalse(form.is_valid()) self.assertTrue( 'You are not allowed to edit or publish on Release channel.' in form.errors['__all__'][0])