def test_action_delete_job(self):
        to_get_deleted = [
            JobFactory.create(status=Job.DRAFT),
            JobFactory.create(status=Job.DRAFT),
        ]
        to_remain = [
            JobFactory(status=Job.CANCELED),
            JobFactory(status=Job.COMPLETED),
            JobFactory(status=Job.PUBLISHED),
        ]
        queryset = Job.objects.filter(id__in=[x.id for x in to_get_deleted + to_remain])

        request = Mock()
        request.user = UserFactory.create()
        with patch.multiple('snippets.base.admin.adminmodels.messages',
                            warning=DEFAULT_MOCK,
                            success=DEFAULT_MOCK) as message_mocks:
            JobAdmin(Job, None).action_delete_job(request, queryset)

        self.assertEqual(
            set(Job.objects.all()),
            set(to_remain)
        )
        self.assertTrue(message_mocks['warning'].called)
        self.assertTrue(message_mocks['success'].called)
    def test_action_cancel_job(self):
        to_get_canceled = [
            JobFactory.create(status=Job.PUBLISHED),
            JobFactory.create(status=Job.SCHEDULED),
        ]
        already_cancelled = JobFactory(status=Job.CANCELED)
        completed = JobFactory(status=Job.COMPLETED)
        JobFactory.create_batch(2, status=Job.DRAFT)

        queryset = Job.objects.filter(id__in=[
            to_get_canceled[0].id,
            to_get_canceled[1].id,
            already_cancelled.id,
            completed.id,
        ])

        request = Mock()
        request.user = UserFactory.create()
        with patch.multiple('snippets.base.admin.adminmodels.messages',
                            warning=DEFAULT_MOCK,
                            success=DEFAULT_MOCK) as message_mocks:
            JobAdmin(Job, None).action_cancel_job(request, queryset)

        self.assertEqual(
            set(Job.objects.filter(status=Job.CANCELED)),
            set(to_get_canceled + [already_cancelled])
        )
        self.assertTrue(message_mocks['warning'].called)
        self.assertTrue(message_mocks['success'].called)
Exemple #3
0
 def test_base(self):
     job1, job2 = JobFactory.create_batch(2)
     job4 = JobFactory.create(publish_end=datetime(2019, 2, 2))
     job3 = JobFactory.create(publish_start=datetime(2019, 1, 1),
                              publish_end=datetime(2019, 2, 2))
     filtr = JobFilter(QueryDict(query_string='only_scheduled=all'),
                       queryset=models.Job.objects.all())
     self.assertEqual(set([job1, job2, job3, job4]), set(filtr.qs))
Exemple #4
0
 def test_locale(self):
     job = JobFactory.create(snippet__locale='fr')
     JobFactory.create(snippet__locale='de')
     JobFactory.create(snippet__locale='xx')
     locale = job.snippet.locale
     filtr = JobFilter(
         QueryDict(query_string=f'only_scheduled=all&locale={locale.id}'),
         queryset=models.Job.objects.all())
     self.assertEqual(set([job]), set(filtr.qs))
Exemple #5
0
 def test_only_scheduled_true(self):
     job1 = JobFactory.create(publish_end=datetime(2019, 2, 2))
     job2 = JobFactory.create(publish_end=datetime(2019, 2, 2))
     job3 = JobFactory.create(publish_start=datetime(2019, 2, 2),
                              publish_end=datetime(2019, 2, 3))
     JobFactory.create(publish_start=None, publish_end=None)
     filtr = JobFilter(QueryDict(query_string='only_scheduled=true'),
                       queryset=models.Job.objects.all())
     self.assertEqual(set([job1, job2, job3]), set(filtr.qs))
    def test_clean(self):
        job_clean = JobFactory.create(
            publish_start=datetime.utcnow() + timedelta(days=1),
            publish_end=datetime.utcnow() + timedelta(days=2))
        job_clean.clean()

        job_dirty = JobFactory.create(
            publish_start=datetime.utcnow() + timedelta(days=3),
            publish_end=datetime.utcnow() + timedelta(days=2))

        self.assertRaisesMessage(
            ValidationError, 'Publish start must come before publish end.',
            job_dirty.clean)
 def test_get_admin_url(self):
     job = JobFactory.create()
     self.assertEqual(
         job.get_admin_url(),
         f'http://example.com/admin/base/job/{job.id}/change/')
     self.assertEqual(job.get_admin_url(full=False),
                      f'/admin/base/job/{job.id}/change/')
    def test_change_status_to_completed(self):
        job = JobFactory.create(status=Job.DRAFT)
        with patch('snippets.base.models.datetime') as datetime_mock:
            datetime_mock.utcnow.return_value = datetime(2019, 1, 1, 0, 0)
            job.change_status(status=Job.COMPLETED,
                              user=None,
                              send_slack=False)

        job.refresh_from_db()
        self.assertEqual(job.status, Job.COMPLETED)
        self.assertEqual(job.completed_on, datetime(2019, 1, 1, 0, 0))
    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_change_status(self):
        job = JobFactory.create(status=Job.DRAFT)
        with patch('snippets.base.models.slack') as slack_mock:
            with patch('snippets.base.models.LogEntry') as log_entry_mock:
                job.change_status(status=Job.SCHEDULED,
                                  user=job.creator,
                                  send_slack=True)

        job.refresh_from_db()

        self.assertEqual(job.status, Job.SCHEDULED)
        log_entry_mock.objects.log_action.assert_called()
        slack_mock._send_slack.assert_called()
 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(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_duplicate(self):
        user = UserFactory.create()
        job = JobFactory.create(status=Job.PUBLISHED,
                                metric_impressions=500,
                                metric_clicks=500,
                                metric_blocks=500,
                                completed_on=datetime.utcnow())
        duplicate_job = job.duplicate(user)
        job.refresh_from_db()

        for attr in ['id', 'creator', 'created', 'modified', 'uuid']:
            self.assertNotEqual(getattr(job, attr),
                                getattr(duplicate_job, attr))

        self.assertEqual(duplicate_job.status, Job.DRAFT)
        self.assertEqual(duplicate_job.metric_impressions, 0)
        self.assertEqual(duplicate_job.metric_clicks, 0)
        self.assertEqual(duplicate_job.metric_blocks, 0)
        self.assertEqual(duplicate_job.completed_on, None)
Exemple #14
0
    def test_name(self):
        JobFactory.create(id=2990, snippet__id=20000, snippet__name='foo 1')
        JobFactory.create(id=2991, snippet__id=20001, snippet__name='foo 2')
        job = JobFactory.create(id=2992,
                                snippet__id=20002,
                                snippet__name='bar 1')
        JobFactory.create(id=2993, snippet__name='foo lala foo')
        filtr = JobFilter(
            QueryDict(query_string='only_scheduled=all&name=bar'),
            queryset=models.Job.objects.all())
        self.assertEqual(set([job]), set(filtr.qs))

        # Test search with Job ID
        filtr = JobFilter(
            QueryDict(query_string=f'only_scheduled=all&name={job.id}'),
            queryset=models.Job.objects.all())

        self.assertEqual(set([job]), set(filtr.qs))

        # Test search with Snippet ID
        filtr = JobFilter(QueryDict(
            query_string=f'only_scheduled=all&name={job.snippet.id}'),
                          queryset=models.Job.objects.all())
        self.assertEqual(set([job]), set(filtr.qs))
    def test_render_client_limits(self):
        # Combined
        job = JobFactory.create(
            client_limit_lifetime=100,
            client_limit_per_hour=10,
            client_limit_per_month=100,
            campaign__slug='demo_campaign',
        )
        expected_output = {
            'id': str(job.id),
            'weight': 100,
            'campaign': 'demo_campaign',
            'targeting': '',
            'frequency': {
                'lifetime':
                100,
                'custom': [{
                    'period': 3600000,
                    'cap': 10
                }, {
                    'period': 2592000000,
                    'cap': 100
                }]
            }
        }
        job.snippet.render = Mock()
        job.snippet.render.return_value = {}
        generated_output = job.render()
        self.assertEqual(generated_output, expected_output)

        # Lifetime limit only
        job = JobFactory.create(
            client_limit_lifetime=100,
            campaign__slug='demo_campaign_1',
        )
        expected_output = {
            'id': str(job.id),
            'weight': 100,
            'campaign': 'demo_campaign_1',
            'targeting': '',
            'frequency': {
                'lifetime': 100,
            }
        }
        job.snippet.render = Mock()
        job.snippet.render.return_value = {}
        generated_output = job.render()
        self.assertEqual(generated_output, expected_output)

        # Custom limits only

        # Lifetime limit only
        job = JobFactory.create(
            client_limit_per_week=9,
            client_limit_per_fortnight=99,
            campaign__slug='demo_campaign_2',
        )
        expected_output = {
            'id': str(job.id),
            'weight': 100,
            'campaign': 'demo_campaign_2',
            'targeting': '',
            'frequency': {
                'custom': [{
                    'period': 604800000,
                    'cap': 9
                }, {
                    'period': 1296000000,
                    'cap': 99
                }]
            }
        }
        job.snippet.render = Mock()
        job.snippet.render.return_value = {}
        generated_output = job.render()
        self.assertEqual(generated_output, expected_output)
    def test_base(self):
        JobFactory.create(
            id=1000,
            status=Job.COMPLETED,
            publish_start=date(2020, 1, 1),
            completed_on=date(2020, 1, 10),
        )
        JobFactory.create(id=2000)
        JobDailyPerformance(date=date(2020, 1, 9),
                            impression=100,
                            job=Job.objects.get(id=1000)).save()

        rows = [
            [
                {
                    'message_id': '1000',
                    'event_context': '{}',
                    'event': 'CLICK_BUTTON',
                    'channel': 'release',
                    'country_code': 'GR',
                    'counts': 5,
                    'no_clients': 2,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '1000',
                    'event_context': '{}',
                    'event': 'IMPRESSION',
                    'channel': 'release',
                    'country_code': 'ES',
                    'counts': 30,
                    'no_clients': 10,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '1000',
                    'event_context': '{}',
                    'event': 'IMPRESSION',
                    'channel': 'release',
                    'country_code': 'IT',
                    'counts': 50,
                    'no_clients': 20,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '1000',
                    'event_context': '{}',
                    'event': 'BLOCK',
                    'channel': 'releases',
                    'country_code': 'UK',
                    'counts': 23,
                    'no_clients': 9,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '1000',
                    'event_context': '{}',
                    'event': 'BLOCK',
                    'channel': 'beta-test',
                    'country_code': 'SW',
                    'counts': 27,
                    'no_clients': 50,
                    'no_clients_total': 0,
                },
                # To be discarded
                {
                    'message_id': '500',
                    'event_context': '{}',
                    'event': 'CLICK',
                    'channel': 'demo',
                    'country_code': 'GR',
                    'counts': 5,
                    'no_clients': 10,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '1000',
                    'event_context': '',
                    'event': 'CLICK',
                    'channel': 'release',
                    'country_code': 'GR',
                    'counts': 6,
                    'no_clients': 10,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '2000',
                    'event_context': '{}',
                    'event': 'CLICK_BUTTON',
                    'additional_properties':
                    '{"value": "scene1-button-learn-more", "foo": "bar"}',
                    'channel': 'release',
                    'country_code': 'GR',
                    'counts': 44,
                    'no_clients': 33,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '2000',
                    'event_context': '{}',
                    'event': 'CLICK_BUTTON',
                    'channel': 'release',
                    'country_code': 'BG',
                    'counts': 3,
                    'no_clients': 10,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '2000',
                    'event_context': '{}',
                    'event': 'CLICK_BUTTON',
                    'channel': 'release',
                    'country_code': 'AL',
                    'counts': 1,
                    'no_clients': 10,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '2000',
                    'event_context': 'conversion-subscribe-activation',
                    'event': 'CLICK_BUTTON',
                    'additional_properties': '{"foo": "bar"}',
                    'channel': 'release',
                    'country_code': 'GR',
                    'counts': 5,
                    'no_clients': 8,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '2000',
                    'event_context': 'subscribe-error',
                    'event': 'CLICK_BUTTON',
                    'additional_properties': '{"foo": "bar"}',
                    'channel': 'release',
                    'country_code': 'GR',
                    'counts': 3,
                    'no_clients': 4,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '2000',
                    'event_context': 'subscribe-success',
                    'event': 'CLICK_BUTTON',
                    'channel': 'release',
                    'country_code': 'ERROR',
                    'counts': 9,
                    'no_clients': 57,
                    'no_clients_total': 0,
                },
                {
                    'message_id': '2000',
                    'event_context': '',
                    'event': 'DISMISS',
                    'channel': 'beta',
                    'country_code': 'ERROR',
                    'counts': 1,
                    'no_clients': 1,
                    'no_clients_total': 0,
                },
            ],
            [
                {
                    'message_id': '1000',
                    'event_context': '',
                    'event': 'IMPRESSION',
                    'channel': 'release',
                    'country_code': 'ES',
                    'counts': 0,
                    'no_clients': 0,
                    'no_clients_total': 232,
                },
                {
                    'message_id': '1000',
                    'event_context': '',
                    'event': 'IMPRESSION',
                    'channel': 'release',
                    'country_code': 'IT',
                    'counts': 0,
                    'no_clients': 0,
                    'no_clients_total': 421,
                },
            ],
        ]

        with patch('snippets.base.etl.redash_rows') as redash_rows_mock:
            redash_rows_mock.side_effect = rows
            result = etl.update_job_metrics(date(2020, 1, 10))

        self.assertEqual(redash_rows_mock.call_count, 2)
        self.assertTrue(result)
        self.assertEqual(JobDailyPerformance.objects.count(), 3)

        jdp1 = JobDailyPerformance.objects.filter(
            job_id=1000).order_by('-id')[0]
        self.assertEqual(jdp1.impression, 80)
        self.assertEqual(jdp1.impression_no_clients, 30)
        self.assertEqual(jdp1.impression_no_clients_total, 653)
        self.assertEqual(jdp1.click, 11)
        self.assertEqual(jdp1.click_no_clients, 12)
        self.assertEqual(jdp1.click_no_clients_total, 0)
        self.assertEqual(jdp1.block, 50)
        self.assertEqual(jdp1.block_no_clients, 59)
        self.assertEqual(jdp1.block_no_clients_total, 0)
        self.assertEqual(jdp1.dismiss, 0)
        self.assertEqual(jdp1.dismiss_no_clients, 0)
        self.assertEqual(jdp1.dismiss_no_clients_total, 0)
        self.assertEqual(jdp1.go_to_scene2, 0)
        self.assertEqual(jdp1.go_to_scene2_no_clients, 0)
        self.assertEqual(jdp1.go_to_scene2_no_clients_total, 0)
        self.assertEqual(jdp1.subscribe_error, 0)
        self.assertEqual(jdp1.subscribe_error_no_clients, 0)
        self.assertEqual(jdp1.subscribe_error_no_clients_total, 0)
        self.assertEqual(jdp1.subscribe_success, 0)
        self.assertEqual(jdp1.subscribe_success_no_clients, 0)
        self.assertEqual(jdp1.subscribe_success_no_clients_total, 0)
        self.assertEqual(jdp1.other_click, 0)
        self.assertEqual(jdp1.other_click_no_clients, 0)
        self.assertEqual(jdp1.other_click_no_clients_total, 0)
        self.assertEqual(len(jdp1.details), 5)
        for detail in [{
                'event': 'click',
                'counts': 11,
                'channel': 'release',
                'country': 'GR',
                'no_clients': 12,
                'no_clients_total': 0
        }, {
                'event': 'impression',
                'counts': 30,
                'channel': 'release',
                'country': 'ES',
                'no_clients': 10,
                'no_clients_total': 232
        }, {
                'event': 'impression',
                'counts': 50,
                'channel': 'release',
                'country': 'IT',
                'no_clients': 20,
                'no_clients_total': 421
        }, {
                'event': 'block',
                'counts': 23,
                'channel': 'release',
                'country': 'UK',
                'no_clients': 9,
                'no_clients_total': 0
        }, {
                'event': 'block',
                'counts': 27,
                'channel': 'beta',
                'country': 'SW',
                'no_clients': 50,
                'no_clients_total': 0
        }]:
            self.assertTrue(detail in jdp1.details)

        jdp2 = JobDailyPerformance.objects.get(job_id=2000)
        self.assertEqual(jdp2.impression, 0)
        self.assertEqual(jdp2.impression_no_clients, 0)
        self.assertEqual(jdp2.impression_no_clients_total, 0)
        self.assertEqual(jdp2.click, 5)
        self.assertEqual(jdp2.click_no_clients, 8)
        self.assertEqual(jdp2.click_no_clients_total, 0)
        self.assertEqual(jdp2.block, 0)
        self.assertEqual(jdp2.block_no_clients, 0)
        self.assertEqual(jdp2.block_no_clients_total, 0)
        self.assertEqual(jdp2.dismiss, 1)
        self.assertEqual(jdp2.dismiss_no_clients, 1)
        self.assertEqual(jdp2.dismiss_no_clients_total, 0)
        self.assertEqual(jdp2.go_to_scene2, 44)
        self.assertEqual(jdp2.go_to_scene2_no_clients, 33)
        self.assertEqual(jdp2.go_to_scene2_no_clients_total, 0)
        self.assertEqual(jdp2.subscribe_error, 3)
        self.assertEqual(jdp2.subscribe_error_no_clients, 4)
        self.assertEqual(jdp2.subscribe_error_no_clients_total, 0)
        self.assertEqual(jdp2.subscribe_success, 9)
        self.assertEqual(jdp2.subscribe_success_no_clients, 57)
        self.assertEqual(jdp2.subscribe_success_no_clients_total, 0)
        self.assertEqual(jdp2.other_click, 4)
        self.assertEqual(jdp2.other_click_no_clients, 20)
        self.assertEqual(jdp2.other_click_no_clients_total, 0)
        self.assertEqual(len(jdp2.details), 7)
        for detail in [{
                'event': 'go_to_scene2',
                'counts': 44,
                'channel': 'release',
                'country': 'GR',
                'no_clients': 33,
                'no_clients_total': 0
        }, {
                'event': 'other_click',
                'counts': 3,
                'channel': 'release',
                'country': 'BG',
                'no_clients': 10,
                'no_clients_total': 0
        }, {
                'event': 'other_click',
                'counts': 1,
                'channel': 'release',
                'country': 'AL',
                'no_clients': 10,
                'no_clients_total': 0
        }, {
                'event': 'click',
                'counts': 5,
                'channel': 'release',
                'country': 'GR',
                'no_clients': 8,
                'no_clients_total': 0
        }, {
                'event': 'subscribe_error',
                'counts': 3,
                'channel': 'release',
                'country': 'GR',
                'no_clients': 4,
                'no_clients_total': 0
        }, {
                'event': 'subscribe_success',
                'counts': 9,
                'channel': 'release',
                'country': 'XX',
                'no_clients': 57,
                'no_clients_total': 0
        }, {
                'event': 'dismiss',
                'counts': 1,
                'channel': 'beta',
                'country': 'XX',
                'no_clients': 1,
                'no_clients_total': 0
        }]:
            self.assertTrue(detail in jdp2.details)