def test_send_notification_on_change_only_with_no_changes(self): self.project.notification_strategy = Project.NOTIFY_ON_CHANGE self.project.save() self.project.subscriptions.create(email='*****@*****.**') status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(0, len(mail.outbox))
def test_no_recipients_no_email_mark_as_notified(self, diff): diff.return_value = fake_diff() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(0, len(mail.outbox)) status.refresh_from_db() self.assertTrue(status.notified)
def test_send_notification_on_regression_only_with_no_regressions(self): self.project.subscriptions.create( email='*****@*****.**', notification_strategy=Subscription.NOTIFY_ON_REGRESSION) status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(0, len(mail.outbox))
def test_send_notification_on_regression_only_with_no_regressions(self): self.project.subscriptions.create( email='*****@*****.**', notification_strategy=Subscription.NOTIFY_ON_REGRESSION) status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(0, len(mail.outbox))
def handle(self, *args, **options): g, p = options['PROJECT'].split('/') group = Group.objects.get(slug=g) project = group.projects.get(slug=p) build = project.builds.get(version=options['BUILD']) send_status_notification(build.status)
def handle(self, *args, **options): g, p = options['PROJECT'].split('/') group = Group.objects.get(slug=g) project = group.projects.get(slug=p) build = project.builds.get(version=options['BUILD']) send_status_notification(build.status)
def test_send_notification_on_regression_only(self, regressions): regressions.return_value = OrderedDict({'key': 'value'}) self.project.subscriptions.create( email='*****@*****.**', notification_strategy=Subscription.NOTIFY_ON_REGRESSION) status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_send_notification_on_change_only(self, diff): diff.return_value = fake_diff() self.project.subscriptions.create( email='*****@*****.**', notification_strategy=Subscription.NOTIFY_ON_CHANGE) status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_send_notification_on_regression_only(self, regressions): regressions.return_value = OrderedDict({'key': 'value'}) self.project.subscriptions.create( email='*****@*****.**', notification_strategy=Subscription.NOTIFY_ON_REGRESSION) status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_send_notification_on_change_only(self, diff): diff.return_value = fake_diff() self.project.subscriptions.create( email='*****@*****.**', notification_strategy=Subscription.NOTIFY_ON_CHANGE) status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_send_plain_text_only(self): self.project.subscriptions.create(email='*****@*****.**') self.project.html_mail = False self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertEqual(0, len(msg.alternatives))
def test_send_plain_text_only(self): self.project.subscriptions.create(email='*****@*****.**') self.project.html_mail = False self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertEqual(0, len(msg.alternatives))
def test_subject_from_custom_template(self): template = EmailTemplate.objects.create(subject='lalala', plain_text='foo', html='bar') self.project.custom_email_template = template self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertEqual('lalala', msg.subject)
def notify_project_status(self, status_id): try: status = ProjectStatus.objects.get(pk=status_id) send_status_notification(status) except ProjectStatus.DoesNotExist as not_found: last_id = ProjectStatus.objects.all().aggregate(Max('id'))['id__max'] if not last_id or status_id > last_id: # our id is larger than the latest, the object was probably created # by another process but not commited to the database yet. raise self.retry(exc=not_found, countdown=30) # retry in 30s
def notification_timeout(status_id): projectstatus = ProjectStatus.objects.get(pk=status_id) if not projectstatus.notified and not projectstatus.notified_on_timeout: send_status_notification(projectstatus) projectstatus.notified_on_timeout = True if projectstatus.build.project.force_finishing_builds_on_timeout: projectstatus.finished = True projectstatus.save()
def maybe_notify_project_status(status_id): """ This is invoked for every new TestRun a build receives. Notifications tasks work like the following: 1. First notification attempt with `maybe_notify_project_status`, it uses the attribute `Project.wait_before_notification` which waits for this number of seconds AFTER `Build.datetime`. This means that if the build date keeps changing, notification will delay accordingly. NOTE: the notification will be sent only if `ProjectStatus.finished=True`, even after timeout expiration. 2. Second notifcation attempt is achieved at `notification_timeout`, which waits for an absolute number of seconds, e.g. `Project.notification_timeout`, before trying to send the notification. This serves as a fallback option to send out notifications, even if `ProjectStatus.finished=False`. """ with transaction.atomic(): projectstatus = ProjectStatus.objects.select_for_update().get( pk=status_id) build = projectstatus.build project = build.project if projectstatus.notified_on_timeout is None and project.notification_timeout: notification_timeout.apply_async( args=[status_id], countdown=project.notification_timeout) projectstatus.notified_on_timeout = False projectstatus.save() if project.wait_before_notification: to_wait = project.wait_before_notification time_passed = timezone.now() - build.datetime if time_passed.seconds < to_wait: # wait time did not pass yet; try again later remaining_time = to_wait - time_passed.seconds + 1 maybe_notify_project_status.apply_async( args=[status_id], countdown=remaining_time, ) return if projectstatus.finished and not projectstatus.notified: # check if there are any outstanding PluginScratch objects if not projectstatus.build.pluginscratch_set.all(): send_status_notification(projectstatus) build_id = build.id with transaction.atomic(): atomic_build = Build.objects.select_for_update().get( pk=build_id) if atomic_build.patch_notified is False: notify_patch_build_finished.delay(build_id) atomic_build.patch_notified = True atomic_build.save()
def test_subject_from_custom_template(self): template = EmailTemplate.objects.create(subject='lalala', plain_text='foo', html='bar') self.project.use_custom_email_template = True self.project.custom_email_template = template self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertEqual('lalala', msg.subject)
def test_dont_html_escape_metadata_for_plain_text(self): self.project.subscriptions.create(email='*****@*****.**') self.project.html_mail = False self.project.save() env = self.project.environments.create(slug='myenv') self.build2.test_runs.create(environment=env, metadata_file='{"foo": "foo\'bar"}') status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertIn("foo'bar", msg.body)
def test_dont_html_escape_metadata_for_plain_text(self): self.project.subscriptions.create(email='*****@*****.**') self.project.html_mail = False self.project.save() env = self.project.environments.create(slug='myenv') self.build2.test_runs.create(environment=env, metadata_file='{"foo": "foo\'bar"}') status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertIn("foo'bar", msg.body)
def test_send_notification_for_all_builds(self, diff): self.project.subscriptions.create(email='*****@*****.**') diff.return_value = fake_diff() status1 = ProjectStatus.create_or_update(self.build2) send_status_notification(status1) self.assertEqual(1, len(mail.outbox)) t = timezone.now() - relativedelta(hours=2.5) build = self.project.builds.create(version='3', datetime=t) status2 = ProjectStatus.create_or_update(build) send_status_notification(status2) self.assertEqual(2, len(mail.outbox))
def test_send_notification_for_all_builds(self, diff): self.project.subscriptions.create(email='*****@*****.**') diff.return_value = fake_diff() status1 = ProjectStatus.create_or_update(self.build2) send_status_notification(status1) self.assertEqual(1, len(mail.outbox)) t = timezone.now() - relativedelta(hours=2.5) build = self.project.builds.create(version='3', datetime=t) status2 = ProjectStatus.create_or_update(build) send_status_notification(status2) self.assertEqual(2, len(mail.outbox))
def test_custom_template(self): template = EmailTemplate.objects.create(plain_text='foo', html='bar') self.project.custom_email_template = template self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] txt = msg.body html = msg.alternatives[0][0] self.assertEqual('foo', txt) self.assertEqual('bar', html)
def test_avoid_big_emails(self): _1MB = 1024 * 1024 self.project.subscriptions.create(email='*****@*****.**') template = EmailTemplate.objects.create(plain_text='dummy string' * _1MB) self.project.custom_email_template = template self.project.html_mail = False self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertNotIn('dummy string', msg.body) self.assertIn('The email got too big', msg.body)
def test_parse_metadata_list_of_ints(self): self.project.subscriptions.create(email='*****@*****.**') self.project.html_mail = False self.project.save() env = self.project.environments.create(slug='myenv') self.build2.test_runs.create(environment=env, metadata_file='{"duration": [11,22,33]}') status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertIn("11", msg.body) self.assertIn("22", msg.body) self.assertIn("33", msg.body)
def test_custom_template(self): template = EmailTemplate.objects.create(plain_text='foo', html='bar') self.project.use_custom_email_template = True self.project.custom_email_template = template self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] txt = msg.body html = msg.alternatives[0][0] self.assertEqual('foo', txt) self.assertEqual('bar', html)
def test_parse_metadata_list_of_lists(self): self.project.subscriptions.create(email='*****@*****.**') self.project.html_mail = False self.project.save() env = self.project.environments.create(slug='myenv') self.build2.test_runs.create( environment=env, metadata_file= '{"foo": [["list of list value 1"],["list of list value 2"]]}') status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] self.assertIn("[['list of list value 1'], ['list of list value 2']]", msg.body)
def test_send_notification_on_errors_only(self): backend = Backend.objects.create( url='http://example.com', username='******', token='mypassword', ) self.build2.test_jobs.create(backend=backend, target=self.project, job_status="Incomplete") self.project.project_settings = yaml.dump( {'CI_LAVA_JOB_ERROR_STATUS': "Incomplete"}) self.project.save() self.project.subscriptions.create( email='*****@*****.**', notification_strategy=Subscription.NOTIFY_ON_ERROR) status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_context_custom_template(self): expose_context_vars = """ build={{build.version}} important_metadata={{important_metadata}} metadata={{metadata}} notification={{notification}} previous_build={{previous_build}} regressions_grouped_by_suite={{regressions_grouped_by_suite}} fixes_grouped_by_suite={{fixes_grouped_by_suite}} known_issues={{known_issues}} regressions={{regressions}} fixes={{fixes}} thresholds={{thresholds}} settings={{settings}} summary={{summary}} metrics={{metrics}} """ template = EmailTemplate.objects.create(plain_text=expose_context_vars, html=expose_context_vars) self.project.use_custom_email_template = True self.project.custom_email_template = template self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] txt = msg.body self.assertIn('build=2', txt) self.assertIn('important_metadata={}', txt) self.assertIn('metadata=OrderedDict()', txt) self.assertIn('notification=<squad.core.notification.Notification', txt) self.assertIn('previous_build=1', txt) self.assertIn('regressions_grouped_by_suite=OrderedDict()', txt) self.assertIn('fixes_grouped_by_suite=OrderedDict()', txt) self.assertIn('known_issues=<QuerySet []>', txt) self.assertIn('regressions=OrderedDict()', txt) self.assertIn('fixes=OrderedDict()', txt) self.assertIn('thresholds=[]', txt) self.assertIn('settings=<Settings "test.settings">', txt) self.assertIn('summary=<squad.core.models.TestSummary', txt) self.assertIn('metrics=<QuerySet []>', txt)
def test_escaping_custom_template(self): template = EmailTemplate.objects.create( subject='subject: {{ project.name }}', plain_text='foo: {{ notification.project.name }}', html='{% autoescape True %}bar: {{ notification.project.name }}{% endautoescape %}') self.project.name = "Project's name" self.project.custom_email_template = template self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] subject = msg.subject txt = msg.body html = msg.alternatives[0][0] self.assertEqual("subject: Project's name", subject) self.assertEqual("foo: Project's name", txt) self.assertEqual("bar: Project's name", html)
def test_escaping_custom_template(self): template = EmailTemplate.objects.create( subject='subject: {{ project.name }}', plain_text='foo: {{ notification.project.name }}', html='{% autoescape True %}bar: {{ notification.project.name }}{% endautoescape %}') self.project.name = "Project's name" self.project.use_custom_email_template = True self.project.custom_email_template = template self.project.save() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) msg = mail.outbox[0] subject = msg.subject txt = msg.body html = msg.alternatives[0][0] self.assertEqual("subject: Project's name", subject) self.assertEqual("foo: Project's name", txt) self.assertEqual("bar: Project's name", html)
def maybe_notify_project_status(status_id): projectstatus = ProjectStatus.objects.get(pk=status_id) build = projectstatus.build project = build.project timeout = project.notification_timeout if timeout: notification_timeout.apply_async(args=[status_id], countdown=timeout) if project.wait_before_notification: to_wait = project.wait_before_notification time_passed = timezone.now() - build.datetime if time_passed.seconds < to_wait: # wait time did not pass yet; try again later remaining_time = to_wait - time_passed.seconds + 1 maybe_notify_project_status.apply_async( args=[status_id], countdown=remaining_time, ) return if projectstatus.finished and not projectstatus.notified: send_status_notification(projectstatus)
def maybe_notify_project_status(status_id): projectstatus = ProjectStatus.objects.get(pk=status_id) build = projectstatus.build project = build.project timeout = project.notification_timeout if timeout: notification_timeout.apply_async(args=[status_id], countdown=timeout) if project.wait_before_notification: to_wait = project.wait_before_notification time_passed = timezone.now() - build.datetime if time_passed.seconds < to_wait: # wait time did not pass yet; try again later remaining_time = to_wait - time_passed.seconds + 1 maybe_notify_project_status.apply_async( args=[status_id], countdown=remaining_time, ) return if projectstatus.finished and not projectstatus.notified: notify_patch_build_finished.delay(projectstatus.build_id) send_status_notification(projectstatus)
def notification_timeout(status_id): projectstatus = ProjectStatus.objects.get(pk=status_id) if not projectstatus.notified and not projectstatus.notified_on_timeout: send_status_notification(projectstatus) projectstatus.notified_on_timeout = True projectstatus.save()
def notify_project_status(status_id): projectstatus = ProjectStatus.objects.get(pk=status_id) send_status_notification(projectstatus)
def setUp(self): super(TestSendUnmoderatedNotification, self).setUp() send_status_notification(self.status)
def setUp(self): super(TestSendApprovedNotification, self).setUp() self.status.approved = True self.status.save() send_status_notification(self.status)
def notify_project_status(status_id): projectstatus = ProjectStatus.objects.get(pk=status_id) send_status_notification(projectstatus)
def test_dont_send_if_notifying_on_regression(self): self.subscription.notification_strategy = Subscription.NOTIFY_ON_REGRESSION self.subscription.save() status = ProjectStatus.create_or_update(self.build) send_status_notification(status) self.assertEqual(0, len(mail.outbox))
def test_send_a_single_notification_email(self): self.project.subscriptions.create(email='*****@*****.**') self.project.subscriptions.create(email='*****@*****.**') status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_send_a_single_notification_email(self): self.project.subscriptions.create(email='*****@*****.**') self.project.subscriptions.create(email='*****@*****.**') status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def setUp(self): super(TestSendUnmoderatedNotification, self).setUp() send_status_notification(self.status)
def test_send_notification_to_user(self, diff): self.project.subscriptions.create(user=self.user) diff.return_value = fake_diff() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_no_recipients_no_email(self, diff): diff.return_value = fake_diff() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(0, len(mail.outbox))
def setUp(self): super(TestSendApprovedNotification, self).setUp() self.status.approved = True self.status.save() send_status_notification(self.status)
def test_send_if_notifying_all_builds(self): status = ProjectStatus.create_or_update(self.build) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_send_if_notifying_all_builds(self): status = ProjectStatus.create_or_update(self.build) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_send_notification_to_user(self, diff): self.project.subscriptions.create(user=self.user) diff.return_value = fake_diff() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))
def test_dont_send_if_notifying_on_error(self): self.subscription.notification_strategy = Subscription.NOTIFY_ON_ERROR self.subscription.save() status = ProjectStatus.create_or_update(self.build) send_status_notification(status) self.assertEqual(0, len(mail.outbox))
def test_no_recipients_no_email(self, diff): diff.return_value = fake_diff() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(0, len(mail.outbox))
def notification_timeout(status_id): projectstatus = ProjectStatus.objects.get(pk=status_id) if not projectstatus.notified and not projectstatus.notified_on_timeout: send_status_notification(projectstatus) projectstatus.notified_on_timeout = True projectstatus.save()
def test_send_notification(self, diff): self.project.subscriptions.create(email='*****@*****.**') diff.return_value = fake_diff() status = ProjectStatus.create_or_update(self.build2) send_status_notification(status) self.assertEqual(1, len(mail.outbox))