mirror of
https://github.com/GSA/notifications-api.git
synced 2025-12-22 08:21:13 -05:00
212 lines
6.7 KiB
Python
212 lines
6.7 KiB
Python
import json
|
|
from unittest import mock
|
|
from unittest.mock import ANY, Mock
|
|
|
|
import botocore
|
|
import pytest
|
|
|
|
from app import AwsSesStubClient, aws_ses_client
|
|
from app.clients.email import EmailClientNonRetryableException
|
|
from app.clients.email.aws_ses import (
|
|
AwsSesClientException,
|
|
AwsSesClientThrottlingSendRateException,
|
|
get_aws_responses,
|
|
)
|
|
from app.enums import NotificationStatus, StatisticsType
|
|
|
|
|
|
def test_should_return_correct_details_for_delivery():
|
|
response_dict = get_aws_responses("Delivery")
|
|
assert response_dict["message"] == "Delivered"
|
|
assert response_dict["notification_status"] == NotificationStatus.DELIVERED
|
|
assert response_dict["notification_statistics_status"] == StatisticsType.DELIVERED
|
|
assert response_dict["success"]
|
|
|
|
|
|
def test_should_return_correct_details_for_hard_bounced():
|
|
response_dict = get_aws_responses("Permanent")
|
|
assert response_dict["message"] == "Hard bounced"
|
|
assert response_dict["notification_status"] == NotificationStatus.PERMANENT_FAILURE
|
|
assert response_dict["notification_statistics_status"] == StatisticsType.FAILURE
|
|
assert not response_dict["success"]
|
|
|
|
|
|
def test_should_return_correct_details_for_soft_bounced():
|
|
response_dict = get_aws_responses("Temporary")
|
|
assert response_dict["message"] == "Soft bounced"
|
|
assert response_dict["notification_status"] == NotificationStatus.TEMPORARY_FAILURE
|
|
assert response_dict["notification_statistics_status"] == StatisticsType.FAILURE
|
|
assert not response_dict["success"]
|
|
|
|
|
|
def test_should_return_correct_details_for_complaint():
|
|
response_dict = get_aws_responses("Complaint")
|
|
assert response_dict["message"] == "Complaint"
|
|
assert response_dict["notification_status"] == NotificationStatus.DELIVERED
|
|
assert response_dict["notification_statistics_status"] == StatisticsType.DELIVERED
|
|
assert response_dict["success"]
|
|
|
|
|
|
def test_should_be_none_if_unrecognised_status_code():
|
|
with pytest.raises(KeyError) as e:
|
|
get_aws_responses("99")
|
|
assert "99" in str(e.value)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"reply_to_address, expected_value",
|
|
[
|
|
(None, []),
|
|
("foo@bar.com", ["foo@bar.com"]),
|
|
("føøøø@bååååår.com", ["føøøø@xn--br-yiaaaaa.com"]),
|
|
],
|
|
ids=["empty", "single_email", "punycode"],
|
|
)
|
|
def test_send_email_handles_reply_to_address(
|
|
notify_api, mocker, reply_to_address, expected_value
|
|
):
|
|
boto_mock = mocker.patch.object(aws_ses_client, "_client", create=True)
|
|
|
|
with notify_api.app_context():
|
|
aws_ses_client.send_email(
|
|
source=Mock(),
|
|
to_addresses="to@address.com",
|
|
subject=Mock(),
|
|
body=Mock(),
|
|
reply_to_address=reply_to_address,
|
|
)
|
|
|
|
boto_mock.send_email.assert_called_once_with(
|
|
Source=ANY, Destination=ANY, Message=ANY, ReplyToAddresses=expected_value
|
|
)
|
|
|
|
|
|
def test_send_email_handles_punycode_to_address(notify_api, mocker):
|
|
boto_mock = mocker.patch.object(aws_ses_client, "_client", create=True)
|
|
|
|
with notify_api.app_context():
|
|
aws_ses_client.send_email(
|
|
Mock(), to_addresses="føøøø@bååååår.com", subject=Mock(), body=Mock()
|
|
)
|
|
|
|
boto_mock.send_email.assert_called_once_with(
|
|
Source=ANY,
|
|
Destination={
|
|
"ToAddresses": ["føøøø@xn--br-yiaaaaa.com"],
|
|
"CcAddresses": [],
|
|
"BccAddresses": [],
|
|
},
|
|
Message=ANY,
|
|
ReplyToAddresses=ANY,
|
|
)
|
|
|
|
|
|
def test_send_email_raises_invalid_parameter_value_error_as_EmailClientNonRetryableException(
|
|
mocker,
|
|
):
|
|
boto_mock = mocker.patch.object(aws_ses_client, "_client", create=True)
|
|
error_response = {
|
|
"Error": {
|
|
"Code": "InvalidParameterValue",
|
|
"Message": "some error message from amazon",
|
|
"Type": "Sender",
|
|
}
|
|
}
|
|
boto_mock.send_email.side_effect = botocore.exceptions.ClientError(
|
|
error_response, "opname"
|
|
)
|
|
|
|
with pytest.raises(EmailClientNonRetryableException) as excinfo:
|
|
aws_ses_client.send_email(
|
|
source=Mock(),
|
|
to_addresses="definitely@invalid_email.com",
|
|
subject=Mock(),
|
|
body=Mock(),
|
|
)
|
|
|
|
assert "some error message from amazon" in str(excinfo.value)
|
|
|
|
|
|
def test_send_email_raises_send_rate_throttling_as_AwsSesClientThrottlingSendRateException(
|
|
mocker,
|
|
):
|
|
boto_mock = mocker.patch.object(aws_ses_client, "_client", create=True)
|
|
error_response = {
|
|
"Error": {
|
|
"Code": "Throttling",
|
|
"Message": "Maximum sending rate exceeded.",
|
|
"Type": "Sender",
|
|
}
|
|
}
|
|
boto_mock.send_email.side_effect = botocore.exceptions.ClientError(
|
|
error_response, "opname"
|
|
)
|
|
|
|
with pytest.raises(AwsSesClientThrottlingSendRateException):
|
|
aws_ses_client.send_email(
|
|
source=Mock(), to_addresses="foo@bar.com", subject=Mock(), body=Mock()
|
|
)
|
|
|
|
|
|
def test_send_email_does_not_raise_AwsSesClientThrottlingSendRateException_if_non_send_rate_throttling(
|
|
mocker,
|
|
):
|
|
boto_mock = mocker.patch.object(aws_ses_client, "_client", create=True)
|
|
error_response = {
|
|
"Error": {
|
|
"Code": "Throttling",
|
|
"Message": "Daily message quota exceeded",
|
|
"Type": "Sender",
|
|
}
|
|
}
|
|
boto_mock.send_email.side_effect = botocore.exceptions.ClientError(
|
|
error_response, "opname"
|
|
)
|
|
|
|
with pytest.raises(AwsSesClientException):
|
|
aws_ses_client.send_email(
|
|
source=Mock(), to_addresses="foo@bar.com", subject=Mock(), body=Mock()
|
|
)
|
|
|
|
|
|
def test_send_email_raises_other_errs_as_AwsSesClientException(mocker):
|
|
boto_mock = mocker.patch.object(aws_ses_client, "_client", create=True)
|
|
error_response = {
|
|
"Error": {
|
|
"Code": "ServiceUnavailable",
|
|
"Message": "some error message from amazon",
|
|
"Type": "Sender",
|
|
}
|
|
}
|
|
boto_mock.send_email.side_effect = botocore.exceptions.ClientError(
|
|
error_response, "opname"
|
|
)
|
|
|
|
with pytest.raises(AwsSesClientException) as excinfo:
|
|
aws_ses_client.send_email(
|
|
source=Mock(), to_addresses="foo@bar.com", subject=Mock(), body=Mock()
|
|
)
|
|
|
|
assert "some error message from amazon" in str(excinfo.value)
|
|
|
|
|
|
@mock.patch("app.clients.email.aws_ses_stub.request")
|
|
def test_send_email_stub(mock_request):
|
|
mock_request.return_value = FakeResponse()
|
|
stub = AwsSesStubClient()
|
|
stub.init_app("fake")
|
|
answer = stub.send_email(
|
|
"fake@fake.gov", "recipient@wherever.com", "TestTest", "TestBody"
|
|
)
|
|
print(answer)
|
|
assert answer == "SomeId"
|
|
|
|
|
|
class FakeResponse:
|
|
def __init__(self):
|
|
t = {"MessageId": "SomeId"}
|
|
self.text = json.dumps(t)
|
|
|
|
def raise_for_status(self):
|
|
print("raised for status")
|