mirror of
https://github.com/GSA/notifications-api.git
synced 2026-01-03 06:40:45 -05:00
1380 lines
47 KiB
Python
1380 lines
47 KiB
Python
import uuid
|
||
from unittest import mock
|
||
from unittest.mock import call
|
||
|
||
import botocore
|
||
import pytest
|
||
from flask import current_app, json
|
||
|
||
from app.dao import templates_dao
|
||
from app.dao.service_sms_sender_dao import dao_update_service_sms_sender
|
||
from app.models import (
|
||
EMAIL_TYPE,
|
||
INTERNATIONAL_SMS_TYPE,
|
||
NOTIFICATION_CREATED,
|
||
SMS_TYPE,
|
||
Notification,
|
||
)
|
||
from app.schema_validation import validate
|
||
from app.v2.errors import RateLimitError
|
||
from app.v2.notifications.notification_schemas import (
|
||
post_email_response,
|
||
post_sms_response,
|
||
)
|
||
from tests import create_service_authorization_header
|
||
from tests.app.db import (
|
||
create_api_key,
|
||
create_reply_to_email,
|
||
create_service,
|
||
create_service_sms_sender,
|
||
create_service_with_inbound_number,
|
||
create_template,
|
||
)
|
||
from tests.conftest import set_config_values
|
||
|
||
|
||
@pytest.mark.parametrize("reference", [None, "reference_from_client"])
|
||
def test_post_sms_notification_returns_201(
|
||
client, sample_template_with_placeholders, mocker, reference
|
||
):
|
||
mocked = mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
data = {
|
||
"phone_number": "+447700900855",
|
||
"template_id": str(sample_template_with_placeholders.id),
|
||
"personalisation": {" Name": "Jo"},
|
||
}
|
||
if reference:
|
||
data.update({"reference": reference})
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template_with_placeholders.service_id
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 201
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_sms_response) == resp_json
|
||
notifications = Notification.query.all()
|
||
assert len(notifications) == 1
|
||
assert notifications[0].status == NOTIFICATION_CREATED
|
||
notification_id = notifications[0].id
|
||
assert notifications[0].document_download_count is None
|
||
assert resp_json["id"] == str(notification_id)
|
||
assert resp_json["reference"] == reference
|
||
assert resp_json["content"][
|
||
"body"
|
||
] == sample_template_with_placeholders.content.replace("(( Name))", "Jo")
|
||
assert resp_json["content"]["from_number"] == current_app.config["FROM_NUMBER"]
|
||
assert "v2/notifications/{}".format(notification_id) in resp_json["uri"]
|
||
assert resp_json["template"]["id"] == str(sample_template_with_placeholders.id)
|
||
assert resp_json["template"]["version"] == sample_template_with_placeholders.version
|
||
assert (
|
||
"services/{}/templates/{}".format(
|
||
sample_template_with_placeholders.service_id,
|
||
sample_template_with_placeholders.id,
|
||
)
|
||
in resp_json["template"]["uri"]
|
||
)
|
||
assert not resp_json["scheduled_for"]
|
||
assert mocked.called
|
||
|
||
|
||
def test_post_sms_notification_uses_inbound_number_as_sender(
|
||
client, notify_db_session, mocker
|
||
):
|
||
service = create_service_with_inbound_number(inbound_number="1")
|
||
|
||
template = create_template(
|
||
service=service, content="Hello (( Name))\nYour thing is due soon"
|
||
)
|
||
mocked = mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
data = {
|
||
"phone_number": "+447700900855",
|
||
"template_id": str(template.id),
|
||
"personalisation": {" Name": "Jo"},
|
||
}
|
||
auth_header = create_service_authorization_header(service_id=service.id)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 201
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_sms_response) == resp_json
|
||
notifications = Notification.query.all()
|
||
assert len(notifications) == 1
|
||
notification_id = notifications[0].id
|
||
assert resp_json["id"] == str(notification_id)
|
||
assert resp_json["content"]["from_number"] == "1"
|
||
assert notifications[0].reply_to_text == "1"
|
||
mocked.assert_called_once_with([str(notification_id)], queue="send-sms-tasks")
|
||
|
||
|
||
def test_post_sms_notification_uses_inbound_number_reply_to_as_sender(
|
||
client, notify_db_session, mocker
|
||
):
|
||
service = create_service_with_inbound_number(inbound_number="2028675309")
|
||
|
||
template = create_template(
|
||
service=service, content="Hello (( Name))\nYour thing is due soon"
|
||
)
|
||
mocked = mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
data = {
|
||
"phone_number": "+447700900855",
|
||
"template_id": str(template.id),
|
||
"personalisation": {" Name": "Jo"},
|
||
}
|
||
auth_header = create_service_authorization_header(service_id=service.id)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 201
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_sms_response) == resp_json
|
||
notifications = Notification.query.all()
|
||
assert len(notifications) == 1
|
||
notification_id = notifications[0].id
|
||
assert resp_json["id"] == str(notification_id)
|
||
assert resp_json["content"]["from_number"] == "+12028675309"
|
||
assert notifications[0].reply_to_text == "+12028675309"
|
||
mocked.assert_called_once_with([str(notification_id)], queue="send-sms-tasks")
|
||
|
||
|
||
def test_post_sms_notification_returns_201_with_sms_sender_id(
|
||
client, sample_template_with_placeholders, mocker
|
||
):
|
||
sms_sender = create_service_sms_sender(
|
||
service=sample_template_with_placeholders.service, sms_sender="123456"
|
||
)
|
||
mocked = mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
data = {
|
||
"phone_number": "+447700900855",
|
||
"template_id": str(sample_template_with_placeholders.id),
|
||
"personalisation": {" Name": "Jo"},
|
||
"sms_sender_id": str(sms_sender.id),
|
||
}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template_with_placeholders.service_id
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 201
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_sms_response) == resp_json
|
||
assert resp_json["content"]["from_number"] == sms_sender.sms_sender
|
||
notifications = Notification.query.all()
|
||
assert len(notifications) == 1
|
||
assert notifications[0].reply_to_text == sms_sender.sms_sender
|
||
mocked.assert_called_once_with([resp_json["id"]], queue="send-sms-tasks")
|
||
|
||
|
||
def test_post_sms_notification_uses_sms_sender_id_reply_to(
|
||
client, sample_template_with_placeholders, mocker
|
||
):
|
||
sms_sender = create_service_sms_sender(
|
||
service=sample_template_with_placeholders.service, sms_sender="2028675309"
|
||
)
|
||
mocked = mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
data = {
|
||
"phone_number": "+447700900855",
|
||
"template_id": str(sample_template_with_placeholders.id),
|
||
"personalisation": {" Name": "Jo"},
|
||
"sms_sender_id": str(sms_sender.id),
|
||
}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template_with_placeholders.service_id
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 201
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_sms_response) == resp_json
|
||
assert resp_json["content"]["from_number"] == "+12028675309"
|
||
notifications = Notification.query.all()
|
||
assert len(notifications) == 1
|
||
assert notifications[0].reply_to_text == "+12028675309"
|
||
mocked.assert_called_once_with([resp_json["id"]], queue="send-sms-tasks")
|
||
|
||
|
||
def test_notification_reply_to_text_is_original_value_if_sender_is_changed_after_post_notification(
|
||
client, sample_template, mocker
|
||
):
|
||
sms_sender = create_service_sms_sender(
|
||
service=sample_template.service, sms_sender="123456", is_default=False
|
||
)
|
||
mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
data = {
|
||
"phone_number": "+12028675309",
|
||
"template_id": str(sample_template.id),
|
||
"sms_sender_id": str(sms_sender.id),
|
||
}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template.service_id
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
dao_update_service_sms_sender(
|
||
service_id=sample_template.service_id,
|
||
service_sms_sender_id=sms_sender.id,
|
||
is_default=sms_sender.is_default,
|
||
sms_sender="updated",
|
||
)
|
||
|
||
assert response.status_code == 201
|
||
notifications = Notification.query.all()
|
||
assert len(notifications) == 1
|
||
assert notifications[0].reply_to_text == "123456"
|
||
|
||
|
||
def test_should_cache_template_lookups_in_memory(mocker, client, sample_template):
|
||
mock_get_template = mocker.patch(
|
||
"app.dao.templates_dao.dao_get_template_by_id_and_service_id",
|
||
wraps=templates_dao.dao_get_template_by_id_and_service_id,
|
||
)
|
||
mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
|
||
data = {
|
||
"phone_number": "2028675309",
|
||
"template_id": str(sample_template.id),
|
||
}
|
||
|
||
for _ in range(5):
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template.service_id
|
||
)
|
||
client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert mock_get_template.call_count == 1
|
||
assert mock_get_template.call_args_list == [
|
||
call(
|
||
service_id=str(sample_template.service_id),
|
||
template_id=str(sample_template.id),
|
||
version=None,
|
||
)
|
||
]
|
||
assert Notification.query.count() == 5
|
||
|
||
|
||
def test_should_cache_template_and_service_in_redis(mocker, client, sample_template):
|
||
from app.schemas import service_schema, template_schema
|
||
|
||
mock_redis_get = mocker.patch(
|
||
"app.redis_store.get",
|
||
return_value=None,
|
||
)
|
||
mock_redis_set = mocker.patch(
|
||
"app.redis_store.set",
|
||
)
|
||
|
||
mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
|
||
data = {
|
||
"phone_number": "+447700900855",
|
||
"template_id": str(sample_template.id),
|
||
}
|
||
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template.service_id
|
||
)
|
||
client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
expected_service_key = f"service-{sample_template.service_id}"
|
||
expected_templates_key = f"service-{sample_template.service_id}-template-{sample_template.id}-version-None"
|
||
|
||
assert mock_redis_get.call_args_list == [
|
||
call(expected_service_key),
|
||
call(expected_templates_key),
|
||
]
|
||
|
||
service_dict = service_schema.dump(sample_template.service)
|
||
template_dict = template_schema.dump(sample_template)
|
||
|
||
assert len(mock_redis_set.call_args_list) == 2
|
||
|
||
service_call, templates_call = mock_redis_set.call_args_list
|
||
|
||
assert service_call[0][0] == expected_service_key
|
||
assert json.loads(service_call[0][1]) == {"data": service_dict}
|
||
assert service_call[1]["ex"] == 604_800
|
||
|
||
assert templates_call[0][0] == expected_templates_key
|
||
assert json.loads(templates_call[0][1]) == {"data": template_dict}
|
||
assert templates_call[1]["ex"] == 604_800
|
||
|
||
|
||
def test_should_return_template_if_found_in_redis(mocker, client, sample_template):
|
||
from app.schemas import service_schema, template_schema
|
||
|
||
service_dict = service_schema.dump(sample_template.service)
|
||
template_dict = template_schema.dump(sample_template)
|
||
|
||
mocker.patch(
|
||
"app.redis_store.get",
|
||
side_effect=[
|
||
json.dumps({"data": service_dict}).encode("utf-8"),
|
||
json.dumps({"data": template_dict}).encode("utf-8"),
|
||
],
|
||
)
|
||
mock_get_template = mocker.patch(
|
||
"app.dao.templates_dao.dao_get_template_by_id_and_service_id"
|
||
)
|
||
mock_get_service = mocker.patch("app.dao.services_dao.dao_fetch_service_by_id")
|
||
|
||
mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
|
||
data = {
|
||
"phone_number": "+16615555555",
|
||
"template_id": str(sample_template.id),
|
||
}
|
||
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template.service_id
|
||
)
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 201
|
||
assert mock_get_template.called is False
|
||
assert mock_get_service.called is False
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"notification_type, key_send_to, send_to",
|
||
[
|
||
("sms", "phone_number", "+447700900855"),
|
||
("email", "email_address", "sample@email.com"),
|
||
],
|
||
)
|
||
def test_post_notification_returns_400_and_missing_template(
|
||
client, sample_service, notification_type, key_send_to, send_to
|
||
):
|
||
data = {key_send_to: send_to, "template_id": str(uuid.uuid4())}
|
||
auth_header = create_service_authorization_header(service_id=sample_service.id)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 400
|
||
assert response.headers["Content-type"] == "application/json"
|
||
|
||
error_json = json.loads(response.get_data(as_text=True))
|
||
assert error_json["status_code"] == 400
|
||
assert error_json["errors"] == [
|
||
{"error": "BadRequestError", "message": "Template not found"}
|
||
]
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"notification_type, key_send_to, send_to",
|
||
[
|
||
("sms", "phone_number", "+447700900855"),
|
||
("email", "email_address", "sample@email.com"),
|
||
],
|
||
)
|
||
def test_post_notification_returns_401_and_well_formed_auth_error(
|
||
client, sample_template, notification_type, key_send_to, send_to
|
||
):
|
||
data = {key_send_to: send_to, "template_id": str(sample_template.id)}
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json")],
|
||
)
|
||
|
||
assert response.status_code == 401
|
||
assert response.headers["Content-type"] == "application/json"
|
||
error_resp = json.loads(response.get_data(as_text=True))
|
||
assert error_resp["status_code"] == 401
|
||
assert error_resp["errors"] == [
|
||
{
|
||
"error": "AuthError",
|
||
"message": "Unauthorized: authentication token must be provided",
|
||
}
|
||
]
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"notification_type, key_send_to, send_to",
|
||
[
|
||
("sms", "phone_number", "+447700900855"),
|
||
("email", "email_address", "sample@email.com"),
|
||
],
|
||
)
|
||
def test_notification_returns_400_and_for_schema_problems(
|
||
client, sample_template, notification_type, key_send_to, send_to
|
||
):
|
||
data = {key_send_to: send_to, "template": str(sample_template.id)}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template.service_id
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 400
|
||
assert response.headers["Content-type"] == "application/json"
|
||
error_resp = json.loads(response.get_data(as_text=True))
|
||
assert error_resp["status_code"] == 400
|
||
assert {
|
||
"error": "ValidationError",
|
||
"message": "template_id is a required property",
|
||
} in error_resp["errors"]
|
||
assert {
|
||
"error": "ValidationError",
|
||
"message": "Additional properties are not allowed (template was unexpected)",
|
||
} in error_resp["errors"]
|
||
|
||
|
||
@pytest.mark.parametrize("reference", [None, "reference_from_client"])
|
||
def test_post_email_notification_returns_201(
|
||
client, sample_email_template_with_placeholders, mocker, reference
|
||
):
|
||
mocked = mocker.patch("app.celery.provider_tasks.deliver_email.apply_async")
|
||
data = {
|
||
"email_address": sample_email_template_with_placeholders.service.users[
|
||
0
|
||
].email_address,
|
||
"template_id": sample_email_template_with_placeholders.id,
|
||
"personalisation": {"name": "Bob"},
|
||
}
|
||
if reference:
|
||
data.update({"reference": reference})
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_email_template_with_placeholders.service_id
|
||
)
|
||
response = client.post(
|
||
path="v2/notifications/email",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 201
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_email_response) == resp_json
|
||
notification = Notification.query.one()
|
||
assert notification.status == NOTIFICATION_CREATED
|
||
assert resp_json["id"] == str(notification.id)
|
||
assert resp_json["reference"] == reference
|
||
assert notification.reference is None
|
||
assert notification.reply_to_text is None
|
||
assert notification.document_download_count is None
|
||
assert resp_json["content"][
|
||
"body"
|
||
] == sample_email_template_with_placeholders.content.replace("((name))", "Bob")
|
||
assert resp_json["content"][
|
||
"subject"
|
||
] == sample_email_template_with_placeholders.subject.replace("((name))", "Bob")
|
||
assert resp_json["content"]["from_email"] == "{}@{}".format(
|
||
sample_email_template_with_placeholders.service.email_from,
|
||
current_app.config["NOTIFY_EMAIL_DOMAIN"],
|
||
)
|
||
assert "v2/notifications/{}".format(notification.id) in resp_json["uri"]
|
||
assert resp_json["template"]["id"] == str(
|
||
sample_email_template_with_placeholders.id
|
||
)
|
||
assert (
|
||
resp_json["template"]["version"]
|
||
== sample_email_template_with_placeholders.version
|
||
)
|
||
assert (
|
||
"services/{}/templates/{}".format(
|
||
str(sample_email_template_with_placeholders.service_id),
|
||
str(sample_email_template_with_placeholders.id),
|
||
)
|
||
in resp_json["template"]["uri"]
|
||
)
|
||
assert not resp_json["scheduled_for"]
|
||
assert mocked.called
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"recipient, notification_type",
|
||
[
|
||
("simulate-delivered@notifications.service.gov.uk", EMAIL_TYPE),
|
||
("simulate-delivered-2@notifications.service.gov.uk", EMAIL_TYPE),
|
||
("simulate-delivered-3@notifications.service.gov.uk", EMAIL_TYPE),
|
||
("2028675000", "sms"),
|
||
("2028675111", "sms"),
|
||
("2028675222", "sms"),
|
||
],
|
||
)
|
||
def test_should_not_persist_or_send_notification_if_simulated_recipient(
|
||
client, recipient, notification_type, sample_email_template, sample_template, mocker
|
||
):
|
||
apply_async = mocker.patch(
|
||
"app.celery.provider_tasks.deliver_{}.apply_async".format(notification_type)
|
||
)
|
||
|
||
if notification_type == "sms":
|
||
data = {"phone_number": recipient, "template_id": str(sample_template.id)}
|
||
else:
|
||
data = {
|
||
"email_address": recipient,
|
||
"template_id": str(sample_email_template.id),
|
||
}
|
||
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_email_template.service_id
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 201
|
||
apply_async.assert_not_called()
|
||
assert json.loads(response.get_data(as_text=True))["id"]
|
||
assert Notification.query.count() == 0
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"notification_type, key_send_to, send_to",
|
||
[
|
||
("sms", "phone_number", "2028675309"),
|
||
("email", "email_address", "sample@email.com"),
|
||
],
|
||
)
|
||
def test_send_notification_uses_priority_queue_when_template_is_marked_as_priority(
|
||
client, sample_service, mocker, notification_type, key_send_to, send_to
|
||
):
|
||
mocker.patch(
|
||
"app.celery.provider_tasks.deliver_{}.apply_async".format(notification_type)
|
||
)
|
||
|
||
sample = create_template(
|
||
service=sample_service, template_type=notification_type, process_type="priority"
|
||
)
|
||
mocked = mocker.patch(
|
||
"app.celery.provider_tasks.deliver_{}.apply_async".format(notification_type)
|
||
)
|
||
|
||
data = {key_send_to: send_to, "template_id": str(sample.id)}
|
||
|
||
auth_header = create_service_authorization_header(service_id=sample.service_id)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
notification_id = json.loads(response.data)["id"]
|
||
|
||
assert response.status_code == 201
|
||
mocked.assert_called_once_with([notification_id], queue="priority-tasks")
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"notification_type, key_send_to, send_to",
|
||
[
|
||
("sms", "phone_number", "2028675309"),
|
||
("email", "email_address", "sample@email.com"),
|
||
],
|
||
)
|
||
def test_returns_a_429_limit_exceeded_if_rate_limit_exceeded(
|
||
client, sample_service, mocker, notification_type, key_send_to, send_to
|
||
):
|
||
sample = create_template(service=sample_service, template_type=notification_type)
|
||
persist_mock = mocker.patch(
|
||
"app.v2.notifications.post_notifications.persist_notification"
|
||
)
|
||
deliver_mock = mocker.patch(
|
||
"app.v2.notifications.post_notifications.send_notification_to_queue_detached"
|
||
)
|
||
mocker.patch(
|
||
"app.v2.notifications.post_notifications.check_rate_limiting",
|
||
side_effect=RateLimitError("LIMIT", "INTERVAL", "TYPE"),
|
||
)
|
||
|
||
data = {key_send_to: send_to, "template_id": str(sample.id)}
|
||
|
||
auth_header = create_service_authorization_header(service_id=sample.service_id)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
error = json.loads(response.data)["errors"][0]["error"]
|
||
message = json.loads(response.data)["errors"][0]["message"]
|
||
status_code = json.loads(response.data)["status_code"]
|
||
assert response.status_code == 429
|
||
assert error == "RateLimitError"
|
||
assert (
|
||
message
|
||
== "Exceeded rate limit for key type TYPE of LIMIT requests per INTERVAL seconds"
|
||
)
|
||
assert status_code == 429
|
||
|
||
assert not persist_mock.called
|
||
assert not deliver_mock.called
|
||
|
||
|
||
def test_post_sms_notification_returns_400_if_not_allowed_to_send_int_sms(
|
||
client,
|
||
notify_db_session,
|
||
):
|
||
service = create_service(service_permissions=[SMS_TYPE])
|
||
template = create_template(service=service)
|
||
|
||
data = {"phone_number": "+20-12-1234-1234", "template_id": template.id}
|
||
auth_header = create_service_authorization_header(service_id=service.id)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 400
|
||
assert response.headers["Content-type"] == "application/json"
|
||
|
||
error_json = json.loads(response.get_data(as_text=True))
|
||
assert error_json["status_code"] == 400
|
||
assert error_json["errors"] == [
|
||
{
|
||
"error": "BadRequestError",
|
||
"message": "Cannot send to international mobile numbers",
|
||
}
|
||
]
|
||
|
||
|
||
def test_post_sms_notification_with_archived_reply_to_id_returns_400(
|
||
client, sample_template, mocker
|
||
):
|
||
archived_sender = create_service_sms_sender(
|
||
sample_template.service, "12345", is_default=False, archived=True
|
||
)
|
||
mocker.patch("app.celery.provider_tasks.deliver_email.apply_async")
|
||
data = {
|
||
"phone_number": "+447700900855",
|
||
"template_id": sample_template.id,
|
||
"sms_sender_id": archived_sender.id,
|
||
}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template.service_id
|
||
)
|
||
response = client.post(
|
||
path="v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 400
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert (
|
||
"sms_sender_id {} does not exist in database for service id {}".format(
|
||
archived_sender.id, sample_template.service_id
|
||
)
|
||
in resp_json["errors"][0]["message"]
|
||
)
|
||
assert "BadRequestError" in resp_json["errors"][0]["error"]
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"recipient,label,permission_type, notification_type,expected_error",
|
||
[
|
||
("2028675309", "phone_number", "email", "sms", "text messages"),
|
||
("someone@test.com", "email_address", "sms", "email", "emails"),
|
||
],
|
||
)
|
||
def test_post_sms_notification_returns_400_if_not_allowed_to_send_notification(
|
||
notify_db_session,
|
||
client,
|
||
recipient,
|
||
label,
|
||
permission_type,
|
||
notification_type,
|
||
expected_error,
|
||
):
|
||
service = create_service(service_permissions=[permission_type])
|
||
sample_template_without_permission = create_template(
|
||
service=service, template_type=notification_type
|
||
)
|
||
data = {label: recipient, "template_id": sample_template_without_permission.id}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template_without_permission.service.id
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(
|
||
sample_template_without_permission.template_type
|
||
),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 400
|
||
assert response.headers["Content-type"] == "application/json"
|
||
|
||
error_json = json.loads(response.get_data(as_text=True))
|
||
assert error_json["status_code"] == 400
|
||
assert error_json["errors"] == [
|
||
{
|
||
"error": "BadRequestError",
|
||
"message": "Service is not allowed to send {}".format(expected_error),
|
||
}
|
||
]
|
||
|
||
|
||
@pytest.mark.parametrize("restricted", [True, False])
|
||
def test_post_sms_notification_returns_400_if_number_not_in_guest_list(
|
||
notify_db_session, client, restricted
|
||
):
|
||
service = create_service(
|
||
restricted=restricted, service_permissions=[SMS_TYPE, INTERNATIONAL_SMS_TYPE]
|
||
)
|
||
template = create_template(service=service)
|
||
create_api_key(service=service, key_type="team")
|
||
|
||
data = {
|
||
"phone_number": "+327700900855",
|
||
"template_id": template.id,
|
||
}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=service.id, key_type="team"
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 400
|
||
error_json = json.loads(response.get_data(as_text=True))
|
||
assert error_json["status_code"] == 400
|
||
assert error_json["errors"] == [
|
||
{
|
||
"error": "BadRequestError",
|
||
"message": "Can’t send to this recipient using a team-only API key",
|
||
}
|
||
]
|
||
|
||
|
||
def test_post_sms_notification_returns_201_if_allowed_to_send_int_sms(
|
||
sample_service,
|
||
sample_template,
|
||
client,
|
||
mocker,
|
||
):
|
||
mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
|
||
data = {"phone_number": "+20-12-1234-1234", "template_id": sample_template.id}
|
||
auth_header = create_service_authorization_header(service_id=sample_service.id)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 201
|
||
assert response.headers["Content-type"] == "application/json"
|
||
|
||
|
||
def test_post_sms_should_persist_supplied_sms_number(
|
||
client, sample_template_with_placeholders, mocker
|
||
):
|
||
mocked = mocker.patch("app.celery.provider_tasks.deliver_sms.apply_async")
|
||
data = {
|
||
"phone_number": "+(44) 77009-00855",
|
||
"template_id": str(sample_template_with_placeholders.id),
|
||
"personalisation": {" Name": "Jo"},
|
||
}
|
||
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_template_with_placeholders.service_id
|
||
)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/sms",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 201
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
notifications = Notification.query.all()
|
||
assert len(notifications) == 1
|
||
notification_id = notifications[0].id
|
||
assert "+(44) 77009-00855" == notifications[0].to
|
||
assert resp_json["id"] == str(notification_id)
|
||
assert mocked.called
|
||
|
||
|
||
def test_post_notification_raises_bad_request_if_not_valid_notification_type(
|
||
client, sample_service
|
||
):
|
||
auth_header = create_service_authorization_header(service_id=sample_service.id)
|
||
response = client.post(
|
||
"/v2/notifications/foo",
|
||
data="{}",
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 404
|
||
error_json = json.loads(response.get_data(as_text=True))
|
||
assert "The requested URL was not found on the server." in error_json["message"]
|
||
|
||
|
||
@pytest.mark.parametrize("notification_type", ["sms", "email"])
|
||
def test_post_notification_with_wrong_type_of_sender(
|
||
client, sample_template, sample_email_template, notification_type, fake_uuid
|
||
):
|
||
if notification_type == EMAIL_TYPE:
|
||
template = sample_email_template
|
||
form_label = "sms_sender_id"
|
||
data = {
|
||
"email_address": "test@test.com",
|
||
"template_id": str(sample_email_template.id),
|
||
form_label: fake_uuid,
|
||
}
|
||
elif notification_type == SMS_TYPE:
|
||
template = sample_template
|
||
form_label = "email_reply_to_id"
|
||
data = {
|
||
"phone_number": "+447700900855",
|
||
"template_id": str(template.id),
|
||
form_label: fake_uuid,
|
||
}
|
||
auth_header = create_service_authorization_header(service_id=template.service_id)
|
||
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 400
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert (
|
||
"Additional properties are not allowed ({} was unexpected)".format(form_label)
|
||
in resp_json["errors"][0]["message"]
|
||
)
|
||
assert "ValidationError" in resp_json["errors"][0]["error"]
|
||
|
||
|
||
def test_post_email_notification_with_valid_reply_to_id_returns_201(
|
||
client, sample_email_template, mocker
|
||
):
|
||
reply_to_email = create_reply_to_email(
|
||
sample_email_template.service, "test@test.com"
|
||
)
|
||
mocked = mocker.patch("app.celery.provider_tasks.deliver_email.apply_async")
|
||
data = {
|
||
"email_address": sample_email_template.service.users[0].email_address,
|
||
"template_id": sample_email_template.id,
|
||
"email_reply_to_id": reply_to_email.id,
|
||
}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_email_template.service_id
|
||
)
|
||
response = client.post(
|
||
path="v2/notifications/email",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 201
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_email_response) == resp_json
|
||
notification = Notification.query.first()
|
||
assert notification.reply_to_text == "test@test.com"
|
||
assert resp_json["id"] == str(notification.id)
|
||
assert mocked.called
|
||
|
||
assert notification.reply_to_text == reply_to_email.email_address
|
||
|
||
|
||
def test_post_email_notification_with_invalid_reply_to_id_returns_400(
|
||
client, sample_email_template, mocker, fake_uuid
|
||
):
|
||
mocker.patch("app.celery.provider_tasks.deliver_email.apply_async")
|
||
data = {
|
||
"email_address": sample_email_template.service.users[0].email_address,
|
||
"template_id": sample_email_template.id,
|
||
"email_reply_to_id": fake_uuid,
|
||
}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_email_template.service_id
|
||
)
|
||
response = client.post(
|
||
path="v2/notifications/email",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 400
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert (
|
||
"email_reply_to_id {} does not exist in database for service id {}".format(
|
||
fake_uuid, sample_email_template.service_id
|
||
)
|
||
in resp_json["errors"][0]["message"]
|
||
)
|
||
assert "BadRequestError" in resp_json["errors"][0]["error"]
|
||
|
||
|
||
def test_post_email_notification_with_archived_reply_to_id_returns_400(
|
||
client, sample_email_template, mocker
|
||
):
|
||
archived_reply_to = create_reply_to_email(
|
||
sample_email_template.service,
|
||
"reply_to@test.com",
|
||
is_default=False,
|
||
archived=True,
|
||
)
|
||
mocker.patch("app.celery.provider_tasks.deliver_email.apply_async")
|
||
data = {
|
||
"email_address": "test@test.com",
|
||
"template_id": sample_email_template.id,
|
||
"email_reply_to_id": archived_reply_to.id,
|
||
}
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_email_template.service_id
|
||
)
|
||
response = client.post(
|
||
path="v2/notifications/email",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 400
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert (
|
||
"email_reply_to_id {} does not exist in database for service id {}".format(
|
||
archived_reply_to.id, sample_email_template.service_id
|
||
)
|
||
in resp_json["errors"][0]["message"]
|
||
)
|
||
assert "BadRequestError" in resp_json["errors"][0]["error"]
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"csv_param",
|
||
(
|
||
{"is_csv": None},
|
||
{"is_csv": False},
|
||
{"is_csv": True},
|
||
{},
|
||
),
|
||
)
|
||
def test_post_notification_with_document_upload(
|
||
client, notify_db_session, mocker, csv_param
|
||
):
|
||
service = create_service(service_permissions=[EMAIL_TYPE])
|
||
service.contact_link = "contact.me@gov.uk"
|
||
template = create_template(
|
||
service=service,
|
||
template_type="email",
|
||
content="Document 1: ((first_link)). Document 2: ((second_link))",
|
||
)
|
||
|
||
mocker.patch("app.celery.provider_tasks.deliver_email.apply_async")
|
||
document_download_mock = mocker.patch(
|
||
"app.v2.notifications.post_notifications.document_download_client"
|
||
)
|
||
document_download_mock.upload_document.side_effect = (
|
||
lambda service_id, content, is_csv: f"{content}-link"
|
||
)
|
||
|
||
data = {
|
||
"email_address": service.users[0].email_address,
|
||
"template_id": template.id,
|
||
"personalisation": {
|
||
"first_link": {"file": "abababab", **csv_param},
|
||
"second_link": {"file": "cdcdcdcd", **csv_param},
|
||
},
|
||
}
|
||
|
||
auth_header = create_service_authorization_header(service_id=service.id)
|
||
response = client.post(
|
||
path="v2/notifications/email",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 201, response.get_data(as_text=True)
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_email_response) == resp_json
|
||
|
||
assert document_download_mock.upload_document.call_args_list == [
|
||
call(str(service.id), "abababab", csv_param.get("is_csv")),
|
||
call(str(service.id), "cdcdcdcd", csv_param.get("is_csv")),
|
||
]
|
||
|
||
notification = Notification.query.one()
|
||
assert notification.status == NOTIFICATION_CREATED
|
||
assert notification.personalisation == {
|
||
"first_link": "abababab-link",
|
||
"second_link": "cdcdcdcd-link",
|
||
}
|
||
assert notification.document_download_count == 2
|
||
|
||
assert (
|
||
resp_json["content"]["body"]
|
||
== "Document 1: abababab-link. Document 2: cdcdcdcd-link"
|
||
)
|
||
|
||
|
||
def test_post_notification_with_document_upload_simulated(
|
||
client, notify_db_session, mocker
|
||
):
|
||
service = create_service(service_permissions=[EMAIL_TYPE])
|
||
service.contact_link = "contact.me@gov.uk"
|
||
template = create_template(
|
||
service=service, template_type="email", content="Document: ((document))"
|
||
)
|
||
|
||
mocker.patch("app.celery.provider_tasks.deliver_email.apply_async")
|
||
document_download_mock = mocker.patch(
|
||
"app.v2.notifications.post_notifications.document_download_client"
|
||
)
|
||
document_download_mock.get_upload_url.return_value = "https://document-url"
|
||
|
||
data = {
|
||
"email_address": "simulate-delivered@notifications.service.gov.uk",
|
||
"template_id": template.id,
|
||
"personalisation": {"document": {"file": "abababab"}},
|
||
}
|
||
|
||
auth_header = create_service_authorization_header(service_id=service.id)
|
||
response = client.post(
|
||
path="v2/notifications/email",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 201, response.get_data(as_text=True)
|
||
resp_json = json.loads(response.get_data(as_text=True))
|
||
assert validate(resp_json, post_email_response) == resp_json
|
||
|
||
assert (
|
||
resp_json["content"]["body"] == "Document: https://document-url/test-document"
|
||
)
|
||
|
||
|
||
def test_post_notification_without_document_upload_permission(
|
||
client, notify_db_session, mocker
|
||
):
|
||
service = create_service(service_permissions=[EMAIL_TYPE])
|
||
template = create_template(
|
||
service=service, template_type="email", content="Document: ((document))"
|
||
)
|
||
|
||
mocker.patch("app.celery.provider_tasks.deliver_email.apply_async")
|
||
document_download_mock = mocker.patch(
|
||
"app.v2.notifications.post_notifications.document_download_client"
|
||
)
|
||
document_download_mock.upload_document.return_value = "https://document-url/"
|
||
|
||
data = {
|
||
"email_address": service.users[0].email_address,
|
||
"template_id": template.id,
|
||
"personalisation": {"document": {"file": "abababab"}},
|
||
}
|
||
|
||
auth_header = create_service_authorization_header(service_id=service.id)
|
||
response = client.post(
|
||
path="v2/notifications/email",
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 400, response.get_data(as_text=True)
|
||
|
||
|
||
def test_post_notification_returns_400_when_get_json_throws_exception(
|
||
client, sample_email_template
|
||
):
|
||
auth_header = create_service_authorization_header(
|
||
service_id=sample_email_template.service_id
|
||
)
|
||
response = client.post(
|
||
path="v2/notifications/email",
|
||
data="[",
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
assert response.status_code == 400
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"notification_type, content_type",
|
||
[
|
||
("email", "application/json"),
|
||
("email", "application/text"),
|
||
("sms", "application/json"),
|
||
("sms", "application/text"),
|
||
],
|
||
)
|
||
def test_post_notification_when_payload_is_invalid_json_returns_400(
|
||
client, sample_service, notification_type, content_type
|
||
):
|
||
auth_header = create_service_authorization_header(service_id=sample_service.id)
|
||
payload_not_json = {
|
||
"template_id": "dont-convert-to-json",
|
||
}
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=payload_not_json,
|
||
headers=[("Content-Type", content_type), auth_header],
|
||
)
|
||
|
||
assert response.status_code == 400
|
||
error_msg = json.loads(response.get_data(as_text=True))["errors"][0]["message"]
|
||
|
||
assert error_msg == "Invalid JSON supplied in POST data"
|
||
|
||
|
||
@pytest.mark.parametrize("notification_type", ["email", "sms"])
|
||
def test_post_notification_returns_201_when_content_type_is_missing_but_payload_is_valid_json(
|
||
client, sample_service, notification_type, mocker
|
||
):
|
||
template = create_template(service=sample_service, template_type=notification_type)
|
||
mocker.patch(
|
||
"app.celery.provider_tasks.deliver_{}.apply_async".format(notification_type)
|
||
)
|
||
auth_header = create_service_authorization_header(service_id=sample_service.id)
|
||
|
||
valid_json = {
|
||
"template_id": str(template.id),
|
||
}
|
||
if notification_type == "email":
|
||
valid_json.update({"email_address": sample_service.users[0].email_address})
|
||
else:
|
||
valid_json.update({"phone_number": "+447700900855"})
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(valid_json),
|
||
headers=[auth_header],
|
||
)
|
||
assert response.status_code == 201
|
||
|
||
|
||
@pytest.mark.parametrize("notification_type", ["email", "sms"])
|
||
def test_post_email_notification_when_data_is_empty_returns_400(
|
||
client, sample_service, notification_type
|
||
):
|
||
auth_header = create_service_authorization_header(service_id=sample_service.id)
|
||
data = None
|
||
response = client.post(
|
||
path="/v2/notifications/{}".format(notification_type),
|
||
data=json.dumps(data),
|
||
headers=[("Content-Type", "application/json"), auth_header],
|
||
)
|
||
error_msg = json.loads(response.get_data(as_text=True))["errors"][0]["message"]
|
||
assert response.status_code == 400
|
||
if notification_type == "sms":
|
||
assert error_msg == "phone_number is a required property"
|
||
else:
|
||
assert error_msg == "email_address is a required property"
|
||
|
||
|
||
@pytest.mark.parametrize("notification_type", ("email", "sms"))
|
||
def test_post_notifications_saves_email_or_sms_to_queue(
|
||
client, notify_db_session, mocker, notification_type
|
||
):
|
||
save_task = mocker.patch(
|
||
f"app.celery.tasks.save_api_{notification_type}.apply_async"
|
||
)
|
||
mock_send_task = mocker.patch(
|
||
f"app.celery.provider_tasks.deliver_{notification_type}.apply_async"
|
||
)
|
||
|
||
service = create_service(
|
||
service_name="high volume service",
|
||
)
|
||
with set_config_values(
|
||
current_app,
|
||
{
|
||
"HIGH_VOLUME_SERVICE": [str(service.id)],
|
||
},
|
||
):
|
||
template = create_template(
|
||
service=service, content="((message))", template_type=notification_type
|
||
)
|
||
data = {
|
||
"template_id": template.id,
|
||
"personalisation": {"message": "Dear citizen, have a nice day"},
|
||
}
|
||
data.update(
|
||
{"email_address": "joe.citizen@example.com"}
|
||
) if notification_type == EMAIL_TYPE else data.update(
|
||
{"phone_number": "+447700900855"}
|
||
)
|
||
|
||
response = client.post(
|
||
path=f"/v2/notifications/{notification_type}",
|
||
data=json.dumps(data),
|
||
headers=[
|
||
("Content-Type", "application/json"),
|
||
create_service_authorization_header(service_id=service.id),
|
||
],
|
||
)
|
||
|
||
json_resp = response.get_json()
|
||
|
||
assert response.status_code == 201
|
||
assert json_resp["id"]
|
||
assert json_resp["content"]["body"] == "Dear citizen, have a nice day"
|
||
assert json_resp["template"]["id"] == str(template.id)
|
||
save_task.assert_called_once_with(
|
||
[mock.ANY], queue=f"save-api-{notification_type}-tasks"
|
||
)
|
||
assert not mock_send_task.called
|
||
assert len(Notification.query.all()) == 0
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"exception",
|
||
[
|
||
botocore.exceptions.ClientError({"some": "json"}, "some opname"),
|
||
botocore.parsers.ResponseParserError("exceeded max HTTP body length"),
|
||
],
|
||
)
|
||
@pytest.mark.parametrize("notification_type", ("email", "sms"))
|
||
def test_post_notifications_saves_email_or_sms_normally_if_saving_to_queue_fails(
|
||
client, notify_db_session, mocker, notification_type, exception
|
||
):
|
||
save_task = mocker.patch(
|
||
f"app.celery.tasks.save_api_{notification_type}.apply_async",
|
||
side_effect=exception,
|
||
)
|
||
mock_send_task = mocker.patch(
|
||
f"app.celery.provider_tasks.deliver_{notification_type}.apply_async"
|
||
)
|
||
|
||
service = create_service(
|
||
service_name="high volume service",
|
||
)
|
||
with set_config_values(
|
||
current_app,
|
||
{
|
||
"HIGH_VOLUME_SERVICE": [str(service.id)],
|
||
},
|
||
):
|
||
template = create_template(
|
||
service=service, content="((message))", template_type=notification_type
|
||
)
|
||
data = {
|
||
"template_id": template.id,
|
||
"personalisation": {"message": "Dear citizen, have a nice day"},
|
||
}
|
||
data.update(
|
||
{"email_address": "joe.citizen@example.com"}
|
||
) if notification_type == EMAIL_TYPE else data.update(
|
||
{"phone_number": "+447700900855"}
|
||
)
|
||
|
||
response = client.post(
|
||
path=f"/v2/notifications/{notification_type}",
|
||
data=json.dumps(data),
|
||
headers=[
|
||
("Content-Type", "application/json"),
|
||
create_service_authorization_header(service_id=service.id),
|
||
],
|
||
)
|
||
|
||
json_resp = response.get_json()
|
||
|
||
assert response.status_code == 201
|
||
assert json_resp["id"]
|
||
assert json_resp["content"]["body"] == "Dear citizen, have a nice day"
|
||
assert json_resp["template"]["id"] == str(template.id)
|
||
save_task.assert_called_once_with(
|
||
[mock.ANY], queue=f"save-api-{notification_type}-tasks"
|
||
)
|
||
mock_send_task.assert_called_once_with(
|
||
[json_resp["id"]], queue=f"send-{notification_type}-tasks"
|
||
)
|
||
assert Notification.query.count() == 1
|
||
|
||
|
||
@pytest.mark.parametrize("notification_type", ("email", "sms"))
|
||
def test_post_notifications_doesnt_use_save_queue_for_test_notifications(
|
||
client, notify_db_session, mocker, notification_type
|
||
):
|
||
save_task = mocker.patch(
|
||
f"app.celery.tasks.save_api_{notification_type}.apply_async"
|
||
)
|
||
mock_send_task = mocker.patch(
|
||
f"app.celery.provider_tasks.deliver_{notification_type}.apply_async"
|
||
)
|
||
service = create_service(
|
||
service_name="high volume service",
|
||
)
|
||
with set_config_values(
|
||
current_app,
|
||
{
|
||
"HIGH_VOLUME_SERVICE": [str(service.id)],
|
||
},
|
||
):
|
||
template = create_template(
|
||
service=service, content="((message))", template_type=notification_type
|
||
)
|
||
data = {
|
||
"template_id": template.id,
|
||
"personalisation": {"message": "Dear citizen, have a nice day"},
|
||
}
|
||
data.update(
|
||
{"email_address": "joe.citizen@example.com"}
|
||
) if notification_type == EMAIL_TYPE else data.update(
|
||
{"phone_number": "+447700900855"}
|
||
)
|
||
response = client.post(
|
||
path=f"/v2/notifications/{notification_type}",
|
||
data=json.dumps(data),
|
||
headers=[
|
||
("Content-Type", "application/json"),
|
||
create_service_authorization_header(
|
||
service_id=service.id, key_type="test"
|
||
),
|
||
],
|
||
)
|
||
|
||
json_resp = response.get_json()
|
||
|
||
assert response.status_code == 201
|
||
assert json_resp["id"]
|
||
assert json_resp["content"]["body"] == "Dear citizen, have a nice day"
|
||
assert json_resp["template"]["id"] == str(template.id)
|
||
assert mock_send_task.called
|
||
assert not save_task.called
|
||
assert len(Notification.query.all()) == 1
|