mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-20 22:39:43 -04:00
Merge branch 'main' of https://github.com/GSA/notifications-api into invite-expiration-fix
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
import json
|
||||
from collections import namedtuple
|
||||
from datetime import timedelta
|
||||
from unittest import mock
|
||||
from unittest.mock import ANY, call
|
||||
from unittest.mock import ANY, MagicMock, call
|
||||
|
||||
import pytest
|
||||
|
||||
from app.celery import scheduled_tasks
|
||||
from app.celery.scheduled_tasks import (
|
||||
batch_insert_notifications,
|
||||
check_for_missing_rows_in_completed_jobs,
|
||||
check_for_services_with_high_failure_rates_or_sending_to_tv_numbers,
|
||||
check_job_status,
|
||||
delete_verify_codes,
|
||||
expire_or_delete_invitations,
|
||||
process_delivery_receipts,
|
||||
replay_created_notifications,
|
||||
run_scheduled_jobs,
|
||||
)
|
||||
@@ -308,10 +311,10 @@ def test_replay_created_notifications(notify_db_session, sample_service, mocker)
|
||||
|
||||
replay_created_notifications()
|
||||
email_delivery_queue.assert_called_once_with(
|
||||
[str(old_email.id)], queue="send-email-tasks"
|
||||
[str(old_email.id)], queue="send-email-tasks", countdown=60
|
||||
)
|
||||
sms_delivery_queue.assert_called_once_with(
|
||||
[str(old_sms.id)], queue="send-sms-tasks"
|
||||
[str(old_sms.id)], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
@@ -523,3 +526,101 @@ def test_check_for_services_with_high_failure_rates_or_sending_to_tv_numbers(
|
||||
technical_ticket=True,
|
||||
)
|
||||
mock_send_ticket_to_zendesk.assert_called_once()
|
||||
|
||||
|
||||
def test_batch_insert_with_valid_notifications(mocker):
|
||||
mocker.patch("app.celery.scheduled_tasks.dao_batch_insert_notifications")
|
||||
rs = MagicMock()
|
||||
mocker.patch("app.celery.scheduled_tasks.redis_store", rs)
|
||||
notifications = [
|
||||
{"id": 1, "notification_status": "pending"},
|
||||
{"id": 2, "notification_status": "pending"},
|
||||
]
|
||||
serialized_notifications = [json.dumps(n).encode("utf-8") for n in notifications]
|
||||
|
||||
pipeline_mock = MagicMock()
|
||||
|
||||
rs.pipeline.return_value.__enter__.return_value = pipeline_mock
|
||||
rs.llen.return_value = len(notifications)
|
||||
rs.lpop.side_effect = serialized_notifications
|
||||
|
||||
batch_insert_notifications()
|
||||
|
||||
rs.llen.assert_called_once_with("message_queue")
|
||||
rs.lpop.assert_called_with("message_queue")
|
||||
|
||||
|
||||
def test_batch_insert_with_expired_notifications(mocker):
|
||||
expired_time = utc_now() - timedelta(minutes=2)
|
||||
mocker.patch(
|
||||
"app.celery.scheduled_tasks.dao_batch_insert_notifications",
|
||||
side_effect=Exception("DB Error"),
|
||||
)
|
||||
rs = MagicMock()
|
||||
mocker.patch("app.celery.scheduled_tasks.redis_store", rs)
|
||||
notifications = [
|
||||
{
|
||||
"id": 1,
|
||||
"notification_status": "pending",
|
||||
"created_at": utc_now().isoformat(),
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"notification_status": "pending",
|
||||
"created_at": expired_time.isoformat(),
|
||||
},
|
||||
]
|
||||
serialized_notifications = [json.dumps(n).encode("utf-8") for n in notifications]
|
||||
|
||||
pipeline_mock = MagicMock()
|
||||
|
||||
rs.pipeline.return_value.__enter__.return_value = pipeline_mock
|
||||
rs.llen.return_value = len(notifications)
|
||||
rs.lpop.side_effect = serialized_notifications
|
||||
|
||||
batch_insert_notifications()
|
||||
|
||||
rs.llen.assert_called_once_with("message_queue")
|
||||
rs.rpush.assert_called_once()
|
||||
requeued_notification = json.loads(rs.rpush.call_args[0][1])
|
||||
assert requeued_notification["id"] == 1
|
||||
|
||||
|
||||
def test_batch_insert_with_malformed_notifications(mocker):
|
||||
rs = MagicMock()
|
||||
mocker.patch("app.celery.scheduled_tasks.redis_store", rs)
|
||||
malformed_data = b"not_a_valid_json"
|
||||
pipeline_mock = MagicMock()
|
||||
|
||||
rs.pipeline.return_value.__enter__.return_value = pipeline_mock
|
||||
rs.llen.return_value = 1
|
||||
rs.lpop.side_effect = [malformed_data]
|
||||
|
||||
with pytest.raises(json.JSONDecodeError):
|
||||
batch_insert_notifications()
|
||||
|
||||
rs.llen.assert_called_once_with("message_queue")
|
||||
rs.rpush.assert_not_called()
|
||||
|
||||
|
||||
def test_process_delivery_receipts_success(mocker):
|
||||
dao_update_mock = mocker.patch(
|
||||
"app.celery.scheduled_tasks.dao_update_delivery_receipts"
|
||||
)
|
||||
cloudwatch_mock = mocker.patch("app.celery.scheduled_tasks.AwsCloudwatchClient")
|
||||
cloudwatch_mock.return_value.check_delivery_receipts.return_value = (
|
||||
range(2000),
|
||||
range(500),
|
||||
)
|
||||
current_app_mock = mocker.patch("app.celery.scheduled_tasks.current_app")
|
||||
current_app_mock.return_value = MagicMock()
|
||||
processor = MagicMock()
|
||||
processor.process_delivery_receipts = process_delivery_receipts
|
||||
processor.retry = MagicMock()
|
||||
|
||||
processor.process_delivery_receipts()
|
||||
assert dao_update_mock.call_count == 3
|
||||
dao_update_mock.assert_any_call(list(range(1000)), True)
|
||||
dao_update_mock.assert_any_call(list(range(1000, 2000)), True)
|
||||
dao_update_mock.assert_any_call(list(range(500)), False)
|
||||
processor.retry.assert_not_called()
|
||||
|
||||
@@ -434,7 +434,7 @@ def test_should_send_template_to_correct_sms_task_and_persist(
|
||||
assert persisted_notification.personalisation == {}
|
||||
assert persisted_notification.notification_type == NotificationType.SMS
|
||||
mocked_deliver_sms.assert_called_once_with(
|
||||
[str(persisted_notification.id)], queue="send-sms-tasks"
|
||||
[str(persisted_notification.id)], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
@@ -470,7 +470,7 @@ def test_should_save_sms_if_restricted_service_and_valid_number(
|
||||
assert not persisted_notification.personalisation
|
||||
assert persisted_notification.notification_type == NotificationType.SMS
|
||||
provider_tasks.deliver_sms.apply_async.assert_called_once_with(
|
||||
[str(persisted_notification.id)], queue="send-sms-tasks"
|
||||
[str(persisted_notification.id)], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
@@ -598,7 +598,7 @@ def test_should_save_sms_template_to_and_persist_with_job_id(sample_job, mocker)
|
||||
assert persisted_notification.notification_type == NotificationType.SMS
|
||||
|
||||
provider_tasks.deliver_sms.apply_async.assert_called_once_with(
|
||||
[str(persisted_notification.id)], queue="send-sms-tasks"
|
||||
[str(persisted_notification.id)], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
@@ -938,7 +938,7 @@ def test_save_sms_uses_sms_sender_reply_to_text(mocker, notify_db_session):
|
||||
notification = _notification_json(template, to="2028675301")
|
||||
mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||||
|
||||
notification_id = uuid.uuid4()
|
||||
notification_id = str(uuid.uuid4())
|
||||
save_sms(
|
||||
service.id,
|
||||
notification_id,
|
||||
|
||||
@@ -263,7 +263,9 @@ def test_send_notification_to_queue(
|
||||
|
||||
send_notification_to_queue(notification=notification, queue=requested_queue)
|
||||
|
||||
mocked.assert_called_once_with([str(notification.id)], queue=expected_queue)
|
||||
mocked.assert_called_once_with(
|
||||
[str(notification.id)], queue=expected_queue, countdown=60
|
||||
)
|
||||
|
||||
|
||||
def test_send_notification_to_queue_throws_exception_deletes_notification(
|
||||
@@ -276,8 +278,7 @@ def test_send_notification_to_queue_throws_exception_deletes_notification(
|
||||
with pytest.raises(Boto3Error):
|
||||
send_notification_to_queue(sample_notification, False)
|
||||
mocked.assert_called_once_with(
|
||||
[(str(sample_notification.id))],
|
||||
queue="send-sms-tasks",
|
||||
[(str(sample_notification.id))], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
|
||||
assert _get_notification_query_count() == 0
|
||||
|
||||
@@ -73,7 +73,7 @@ def test_create_invited_org_user(
|
||||
# assert len(notification.personalisation["url"]) > len(expected_start_of_invite_url)
|
||||
|
||||
mocked.assert_called_once_with(
|
||||
[(str(notification.id))], queue="notify-internal-tasks"
|
||||
[(str(notification.id))], queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -150,7 +150,9 @@ def test_send_notification_with_placeholders_replaced(
|
||||
{"template_version": sample_email_template_with_placeholders.version}
|
||||
)
|
||||
|
||||
mocked.assert_called_once_with([notification_id], queue="send-email-tasks")
|
||||
mocked.assert_called_once_with(
|
||||
[notification_id], queue="send-email-tasks", countdown=60
|
||||
)
|
||||
assert response.status_code == 201
|
||||
assert response_data["body"] == "Hello Jo\nThis is an email from GOV.UK"
|
||||
assert response_data["subject"] == "Jo"
|
||||
@@ -420,7 +422,9 @@ def test_should_allow_valid_sms_notification(notify_api, sample_template, mocker
|
||||
response_data = json.loads(response.data)["data"]
|
||||
notification_id = response_data["notification"]["id"]
|
||||
|
||||
mocked.assert_called_once_with([notification_id], queue="send-sms-tasks")
|
||||
mocked.assert_called_once_with(
|
||||
[notification_id], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
assert response.status_code == 201
|
||||
assert notification_id
|
||||
assert "subject" not in response_data
|
||||
@@ -476,7 +480,7 @@ def test_should_allow_valid_email_notification(
|
||||
response_data = json.loads(response.get_data(as_text=True))["data"]
|
||||
notification_id = response_data["notification"]["id"]
|
||||
app.celery.provider_tasks.deliver_email.apply_async.assert_called_once_with(
|
||||
[notification_id], queue="send-email-tasks"
|
||||
[notification_id], queue="send-email-tasks", countdown=60
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
@@ -620,7 +624,7 @@ def test_should_send_email_if_team_api_key_and_a_service_user(
|
||||
)
|
||||
|
||||
app.celery.provider_tasks.deliver_email.apply_async.assert_called_once_with(
|
||||
[fake_uuid], queue="send-email-tasks"
|
||||
[fake_uuid], queue="send-email-tasks", countdown=60
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
@@ -658,7 +662,7 @@ def test_should_send_sms_to_anyone_with_test_key(
|
||||
],
|
||||
)
|
||||
app.celery.provider_tasks.deliver_sms.apply_async.assert_called_once_with(
|
||||
[fake_uuid], queue="send-sms-tasks"
|
||||
[fake_uuid], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
@@ -697,7 +701,7 @@ def test_should_send_email_to_anyone_with_test_key(
|
||||
)
|
||||
|
||||
app.celery.provider_tasks.deliver_email.apply_async.assert_called_once_with(
|
||||
[fake_uuid], queue="send-email-tasks"
|
||||
[fake_uuid], queue="send-email-tasks", countdown=60
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
@@ -735,7 +739,7 @@ def test_should_send_sms_if_team_api_key_and_a_service_user(
|
||||
)
|
||||
|
||||
app.celery.provider_tasks.deliver_sms.apply_async.assert_called_once_with(
|
||||
[fake_uuid], queue="send-sms-tasks"
|
||||
[fake_uuid], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
@@ -792,7 +796,7 @@ def test_should_persist_notification(
|
||||
],
|
||||
)
|
||||
|
||||
mocked.assert_called_once_with([fake_uuid], queue=queue_name)
|
||||
mocked.assert_called_once_with([fake_uuid], queue=queue_name, countdown=60)
|
||||
assert response.status_code == 201
|
||||
|
||||
notification = notifications_dao.get_notification_by_id(fake_uuid)
|
||||
@@ -853,7 +857,7 @@ def test_should_delete_notification_and_return_error_if_redis_fails(
|
||||
)
|
||||
assert str(e.value) == "failed to talk to redis"
|
||||
|
||||
mocked.assert_called_once_with([fake_uuid], queue=queue_name)
|
||||
mocked.assert_called_once_with([fake_uuid], queue=queue_name, countdown=60)
|
||||
assert not notifications_dao.get_notification_by_id(fake_uuid)
|
||||
assert not NotificationHistory.query.get(fake_uuid)
|
||||
|
||||
@@ -1185,7 +1189,9 @@ def test_should_allow_store_original_number_on_sms_notification(
|
||||
response_data = json.loads(response.data)["data"]
|
||||
notification_id = response_data["notification"]["id"]
|
||||
|
||||
mocked.assert_called_once_with([notification_id], queue="send-sms-tasks")
|
||||
mocked.assert_called_once_with(
|
||||
[notification_id], queue="send-sms-tasks", countdown=60
|
||||
)
|
||||
assert response.status_code == 201
|
||||
assert notification_id
|
||||
notifications = Notification.query.all()
|
||||
|
||||
@@ -3025,7 +3025,7 @@ def test_verify_reply_to_email_address_should_send_verification_email(
|
||||
assert notification.template_id == verify_reply_to_address_email_template.id
|
||||
assert response["data"] == {"id": str(notification.id)}
|
||||
mocked.assert_called_once_with(
|
||||
[str(notification.id)], queue="notify-internal-tasks"
|
||||
[str(notification.id)], queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
assert (
|
||||
notification.reply_to_text
|
||||
|
||||
@@ -90,7 +90,7 @@ def test_create_invited_user(
|
||||
)
|
||||
|
||||
mocked.assert_called_once_with(
|
||||
[(str(notification.id))], queue="notify-internal-tasks"
|
||||
[(str(notification.id))], queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -664,7 +664,7 @@ def test_send_already_registered_email(
|
||||
stmt = select(Notification)
|
||||
notification = db.session.execute(stmt).scalars().first()
|
||||
mocked.assert_called_once_with(
|
||||
([str(notification.id)]), queue="notify-internal-tasks"
|
||||
([str(notification.id)]), queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
assert (
|
||||
notification.reply_to_text
|
||||
@@ -703,7 +703,7 @@ def test_send_user_confirm_new_email_returns_204(
|
||||
stmt = select(Notification)
|
||||
notification = db.session.execute(stmt).scalars().first()
|
||||
mocked.assert_called_once_with(
|
||||
([str(notification.id)]), queue="notify-internal-tasks"
|
||||
([str(notification.id)]), queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
assert (
|
||||
notification.reply_to_text
|
||||
|
||||
@@ -231,7 +231,7 @@ def test_send_user_sms_code(client, sample_user, sms_code_template, mocker):
|
||||
assert notification.reply_to_text == notify_service.get_default_sms_sender()
|
||||
|
||||
app.celery.provider_tasks.deliver_sms.apply_async.assert_called_once_with(
|
||||
([str(notification.id)]), queue="notify-internal-tasks"
|
||||
([str(notification.id)]), queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ def test_send_user_code_for_sms_with_optional_to_field(
|
||||
notification = Notification.query.first()
|
||||
assert notification.to == "1"
|
||||
app.celery.provider_tasks.deliver_sms.apply_async.assert_called_once_with(
|
||||
([str(notification.id)]), queue="notify-internal-tasks"
|
||||
([str(notification.id)]), queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
@@ -349,7 +349,7 @@ def test_send_new_user_email_verification(
|
||||
notification = Notification.query.first()
|
||||
assert _get_verify_code_count() == 0
|
||||
mocked.assert_called_once_with(
|
||||
([str(notification.id)]), queue="notify-internal-tasks"
|
||||
([str(notification.id)]), queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
assert (
|
||||
notification.reply_to_text
|
||||
@@ -494,7 +494,9 @@ def test_send_user_email_code(
|
||||
)
|
||||
assert noti.to == "1"
|
||||
assert str(noti.template_id) == current_app.config["EMAIL_2FA_TEMPLATE_ID"]
|
||||
deliver_email.assert_called_once_with([str(noti.id)], queue="notify-internal-tasks")
|
||||
deliver_email.assert_called_once_with(
|
||||
[str(noti.id)], queue="notify-internal-tasks", countdown=60
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Broken email functionality")
|
||||
|
||||
Reference in New Issue
Block a user