import socket from unittest.mock import patch import pytest from django.core import mail from django.core.mail.backends.locmem import EmailBackend from apps.base.models import UserNotificationPolicy, UserNotificationPolicyLogRecord from apps.email.alert_rendering import build_subject_and_message from apps.email.models import EmailMessage from apps.email.tasks import get_from_email, notify_user_async from apps.user_management.subscription_strategy.free_public_beta_subscription_strategy import ( FreePublicBetaSubscriptionStrategy, ) @pytest.mark.django_db def test_notify_user( settings, make_organization, make_user_for_organization, make_token_for_organization, make_alert_receive_channel, make_alert_group, make_alert, make_user_notification_policy, ): settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" settings.EMAIL_HOST = "test" organization = make_organization() user = make_user_for_organization(organization) alert_receive_channel = make_alert_receive_channel(organization) alert_group = make_alert_group(alert_receive_channel) make_alert(alert_group=alert_group, raw_request_data=alert_receive_channel.config.example_payload) notification_policy = make_user_notification_policy( user, UserNotificationPolicy.Step.NOTIFY, notify_by=8, important=False, ) notify_user_async(user.pk, alert_group.pk, notification_policy.pk) assert len(mail.outbox) == 1 log_record = notification_policy.personal_log_records.last() assert log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_SUCCESS @pytest.mark.django_db def test_notify_empty_email_host( settings, make_organization, make_user_for_organization, make_token_for_organization, make_alert_receive_channel, make_alert_group, make_alert, make_user_notification_policy, ): settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" settings.EMAIL_HOST = None organization = make_organization() user = make_user_for_organization(organization) alert_receive_channel = make_alert_receive_channel(organization) alert_group = make_alert_group(alert_receive_channel) make_alert(alert_group=alert_group, raw_request_data=alert_receive_channel.config.example_payload) notification_policy = make_user_notification_policy( user, UserNotificationPolicy.Step.NOTIFY, notify_by=8, important=False, ) notify_user_async(user.pk, alert_group.pk, notification_policy.pk) assert len(mail.outbox) == 0 log_record = notification_policy.personal_log_records.last() assert log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED @pytest.mark.django_db def test_notify_user_bad_smtp_host( settings, make_organization, make_user_for_organization, make_token_for_organization, make_alert_receive_channel, make_alert_group, make_alert, make_user_notification_policy, ): settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" settings.EMAIL_HOST = "test" organization = make_organization() user = make_user_for_organization(organization) alert_receive_channel = make_alert_receive_channel(organization) alert_group = make_alert_group(alert_receive_channel) make_alert(alert_group=alert_group, raw_request_data=alert_receive_channel.config.example_payload) notification_policy = make_user_notification_policy( user, UserNotificationPolicy.Step.NOTIFY, notify_by=8, important=False, ) with patch.object(EmailBackend, "send_messages", side_effect=socket.gaierror): notify_user_async(user.pk, alert_group.pk, notification_policy.pk) assert len(mail.outbox) == 0 log_record = notification_policy.personal_log_records.last() assert log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED @pytest.mark.django_db def test_notify_user_no_emails_left( settings, make_organization, make_user_for_organization, make_token_for_organization, make_alert_receive_channel, make_alert_group, make_alert, make_user_notification_policy, ): settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" settings.EMAIL_HOST = "test" organization = make_organization() user = make_user_for_organization(organization) alert_receive_channel = make_alert_receive_channel(organization) alert_group = make_alert_group(alert_receive_channel) make_alert(alert_group=alert_group, raw_request_data=alert_receive_channel.config.example_payload) notification_policy = make_user_notification_policy( user, UserNotificationPolicy.Step.NOTIFY, notify_by=8, important=False, ) with patch.object(FreePublicBetaSubscriptionStrategy, "emails_left", return_value=0): notify_user_async(user.pk, alert_group.pk, notification_policy.pk) assert len(mail.outbox) == 0 log_record = notification_policy.personal_log_records.last() assert log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED assert log_record.notification_error_code == UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_MAIL_LIMIT_EXCEEDED @pytest.mark.django_db @pytest.mark.parametrize( "license_name,email_host_user,email_from_address,expected", [ ("Cloud", "user", "from_address", "from_address"), ("OpenSource", "user", "from_address", "from_address"), ("Cloud", "user", None, "oncall@slug.grafana.net"), ("Cloud", None, None, "oncall@slug.grafana.net"), ("OpenSource", "user", None, "user"), ("OpenSource", None, None, None), ], ) def test_get_from_email( settings, make_organization, make_user_for_organization, license_name, email_host_user, email_from_address, expected, ): settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" settings.EMAIL_HOST = "test" settings.EMAIL_HOST_PASSWORD = "password" settings.LICENSE = license_name settings.EMAIL_HOST_USER = email_host_user settings.EMAIL_FROM_ADDRESS = email_from_address organization = make_organization(stack_slug="slug") user = make_user_for_organization(organization) assert get_from_email(user) == expected @pytest.mark.django_db def test_subject_newlines_removed( make_organization, make_alert_receive_channel, make_alert_group, make_alert, ): organization = make_organization() alert_receive_channel = make_alert_receive_channel( organization, messaging_backends_templates={"EMAIL": {"title": "test\nnewlines"}} ) alert_group = make_alert_group(alert_receive_channel) make_alert(alert_group, raw_request_data={}) subject, _ = build_subject_and_message(alert_group, 1) assert subject == "testnewlines" @pytest.mark.django_db def test_notify_user_fallback_default_policy( settings, make_organization, make_user_for_organization, make_token_for_organization, make_alert_receive_channel, make_alert_group, make_alert, make_user_notification_policy, ): settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" settings.EMAIL_HOST = "test" organization = make_organization() user = make_user_for_organization(organization) alert_receive_channel = make_alert_receive_channel(organization) alert_group = make_alert_group(alert_receive_channel) make_alert(alert_group=alert_group, raw_request_data=alert_receive_channel.config.example_payload) notify_user_async(user.pk, alert_group.pk, None) assert len(mail.outbox) == 1 log_record = UserNotificationPolicyLogRecord.objects.filter(author=user, alert_group=alert_group).first() assert log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_SUCCESS EmailMessage.objects.get(receiver=user, represents_alert_group=alert_group, notification_policy=None)