2020-10-20 14:00:53 +01:00
|
|
|
import json
|
2020-10-26 17:14:08 +00:00
|
|
|
import uuid
|
2020-12-11 18:52:54 +00:00
|
|
|
from collections import namedtuple
|
2020-12-18 17:22:11 +00:00
|
|
|
from datetime import datetime
|
2021-01-11 15:06:24 +00:00
|
|
|
from unittest.mock import Mock, call
|
2020-10-20 14:00:53 +01:00
|
|
|
|
2020-10-20 13:33:51 +01:00
|
|
|
import pytest
|
|
|
|
|
|
2021-01-14 11:44:46 +00:00
|
|
|
from app.clients.cbc_proxy import (
|
retry sending broadcasts
Retry tasks if they fail to send a broadcast event. Note that each task
tries the regular proxy and the failover proxy for that provider. This
runs a bit differently than our other retries:
Retry with exponential backoff. Our other tasks retry with a fixed delay
of 5 minutes between tries. If we can't send a broadcast, we want to try
immediately. So instead, implement an exponential backoff (1, 2, 4, 8,
... seconds delay). We can't delay for longer than 310 seconds due to
visibility timeout settings in SQS, so cap the delay at that amount.
Normally we give up retrying after a set amount of retries (often 4
hours). As broadcast content is much more important than normal
notifications, we don't ever want to give up on sending them to phones...
...UNLESS WE DO!
Sometimes we do want to give up sending a broadcast though! Broadcasts
have an expiry time, when they stop showing up on peoples devices, so if
that has passed then we don't need to send the broadcast out.
Broadcast events can also be superceded by updates or cancels. Check
that the event is the most recent event for that broadcast message, if
not, give up, as we don't want to accidentally send out two conflicting
events for the same message.
2021-01-19 10:05:48 +00:00
|
|
|
CBCProxyClient, CBCProxyRetryableException, CBCProxyEE, CBCProxyCanary, CBCProxyVodafone, CBCProxyThree, CBCProxyO2
|
2021-01-14 11:44:46 +00:00
|
|
|
)
|
2020-12-18 17:39:35 +00:00
|
|
|
from app.utils import DATETIME_FORMAT
|
2020-10-20 13:33:51 +01:00
|
|
|
|
2021-01-11 15:40:37 +00:00
|
|
|
EXAMPLE_AREAS = [{
|
|
|
|
|
'description': 'london',
|
|
|
|
|
'polygon': [
|
|
|
|
|
[51.12, -1.2],
|
|
|
|
|
[51.12, 1.2],
|
|
|
|
|
[51.74, 1.2],
|
|
|
|
|
[51.74, -1.2],
|
|
|
|
|
[51.12, -1.2],
|
|
|
|
|
],
|
|
|
|
|
}]
|
|
|
|
|
|
2020-10-20 13:33:51 +01:00
|
|
|
|
|
|
|
|
@pytest.fixture(scope='function')
|
2020-11-17 12:35:22 +00:00
|
|
|
def cbc_proxy_client(client, mocker):
|
2020-10-20 13:33:51 +01:00
|
|
|
client = CBCProxyClient()
|
|
|
|
|
current_app = mocker.Mock(config={
|
|
|
|
|
'CBC_PROXY_AWS_ACCESS_KEY_ID': 'cbc-proxy-aws-access-key-id',
|
|
|
|
|
'CBC_PROXY_AWS_SECRET_ACCESS_KEY': 'cbc-proxy-aws-secret-access-key',
|
2020-11-25 17:39:32 +00:00
|
|
|
'CBC_PROXY_ENABLED': True,
|
2020-10-20 13:33:51 +01:00
|
|
|
})
|
|
|
|
|
client.init_app(current_app)
|
|
|
|
|
return client
|
|
|
|
|
|
|
|
|
|
|
2020-11-17 12:35:22 +00:00
|
|
|
@pytest.fixture
|
|
|
|
|
def cbc_proxy_ee(cbc_proxy_client):
|
|
|
|
|
return cbc_proxy_client.get_proxy('ee')
|
2020-10-20 13:33:51 +01:00
|
|
|
|
2020-12-09 11:13:50 +00:00
|
|
|
@pytest.fixture
|
|
|
|
|
def cbc_proxy_vodafone(cbc_proxy_client):
|
|
|
|
|
return cbc_proxy_client.get_proxy('vodafone')
|
|
|
|
|
|
|
|
|
|
|
2020-11-17 12:35:22 +00:00
|
|
|
@pytest.mark.parametrize('provider_name, expected_provider_class', [
|
|
|
|
|
('ee', CBCProxyEE),
|
2021-01-14 11:44:46 +00:00
|
|
|
('three', CBCProxyThree),
|
2021-01-26 11:11:44 +00:00
|
|
|
('o2', CBCProxyO2),
|
2021-01-14 11:44:46 +00:00
|
|
|
('vodafone', CBCProxyVodafone),
|
2020-11-17 12:35:22 +00:00
|
|
|
('canary', CBCProxyCanary),
|
|
|
|
|
])
|
|
|
|
|
def test_cbc_proxy_client_returns_correct_client(provider_name, expected_provider_class):
|
|
|
|
|
mock_lambda = Mock()
|
|
|
|
|
cbc_proxy_client = CBCProxyClient()
|
|
|
|
|
cbc_proxy_client._lambda_client = mock_lambda
|
|
|
|
|
|
|
|
|
|
ret = cbc_proxy_client.get_proxy(provider_name)
|
|
|
|
|
|
|
|
|
|
assert type(ret) == expected_provider_class
|
|
|
|
|
assert ret._lambda_client == mock_lambda
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_cbc_proxy_lambda_client_has_correct_region(cbc_proxy_ee):
|
|
|
|
|
assert cbc_proxy_ee._lambda_client._client_config.region_name == 'eu-west-2'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_cbc_proxy_lambda_client_has_correct_keys(cbc_proxy_ee):
|
|
|
|
|
key = cbc_proxy_ee._lambda_client._request_signer._credentials.access_key
|
|
|
|
|
secret = cbc_proxy_ee._lambda_client._request_signer._credentials.secret_key
|
2020-10-20 13:33:51 +01:00
|
|
|
|
|
|
|
|
assert key == 'cbc-proxy-aws-access-key-id'
|
|
|
|
|
assert secret == 'cbc-proxy-aws-secret-access-key'
|
2020-10-20 14:00:53 +01:00
|
|
|
|
|
|
|
|
|
2020-12-24 15:09:41 +00:00
|
|
|
@pytest.mark.parametrize('description, expected_language', (
|
|
|
|
|
('my-description', 'en-GB'),
|
|
|
|
|
('mŷ-description', 'cy-GB'),
|
|
|
|
|
))
|
2021-01-25 14:28:40 +00:00
|
|
|
@pytest.mark.parametrize('cbc', ['ee', 'three', 'o2'])
|
2021-01-14 11:44:46 +00:00
|
|
|
def test_cbc_proxy_one_2_many_create_and_send_invokes_function(
|
2020-12-24 15:09:41 +00:00
|
|
|
mocker,
|
2021-01-26 11:11:44 +00:00
|
|
|
cbc_proxy_client,
|
2020-12-24 15:09:41 +00:00
|
|
|
description,
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc,
|
2020-12-24 15:09:41 +00:00
|
|
|
expected_language,
|
|
|
|
|
):
|
2021-01-25 14:28:40 +00:00
|
|
|
cbc_proxy = cbc_proxy_client.get_proxy(cbc)
|
2021-01-14 11:44:46 +00:00
|
|
|
|
2020-10-20 14:00:53 +01:00
|
|
|
identifier = 'my-identifier'
|
|
|
|
|
headline = 'my-headline'
|
|
|
|
|
|
2020-10-28 11:26:38 +00:00
|
|
|
sent = 'a-passed-through-sent-value'
|
|
|
|
|
expires = 'a-passed-through-expires-value'
|
|
|
|
|
|
2020-10-20 14:00:53 +01:00
|
|
|
ld_client_mock = mocker.patch.object(
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc_proxy,
|
2020-10-22 12:22:11 +01:00
|
|
|
'_lambda_client',
|
2020-10-20 14:00:53 +01:00
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
2020-10-20 15:18:11 +01:00
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc_proxy.create_and_send_broadcast(
|
2020-10-20 14:00:53 +01:00
|
|
|
identifier=identifier,
|
2020-12-04 17:29:12 +00:00
|
|
|
message_number='0000007b',
|
2020-10-20 14:00:53 +01:00
|
|
|
headline=headline,
|
|
|
|
|
description=description,
|
2021-01-11 15:40:37 +00:00
|
|
|
areas=EXAMPLE_AREAS,
|
2021-01-29 11:54:12 +00:00
|
|
|
sent=sent,
|
|
|
|
|
expires=expires,
|
|
|
|
|
channel="severe",
|
2020-10-20 14:00:53 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.assert_called_once_with(
|
2021-01-14 11:44:46 +00:00
|
|
|
FunctionName=f'{cbc}-1-proxy',
|
2020-10-20 14:00:53 +01:00
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
kwargs = ld_client_mock.invoke.mock_calls[0][-1]
|
|
|
|
|
payload_bytes = kwargs['Payload']
|
|
|
|
|
payload = json.loads(payload_bytes)
|
|
|
|
|
|
|
|
|
|
assert payload['identifier'] == identifier
|
2020-12-09 11:13:50 +00:00
|
|
|
assert 'message_number' not in payload
|
2020-12-09 17:10:40 +00:00
|
|
|
assert payload['message_format'] == 'cap'
|
2020-10-27 14:44:04 +00:00
|
|
|
assert payload['message_type'] == 'alert'
|
2020-10-20 14:00:53 +01:00
|
|
|
assert payload['headline'] == headline
|
|
|
|
|
assert payload['description'] == description
|
2021-01-11 15:40:37 +00:00
|
|
|
assert payload['areas'] == EXAMPLE_AREAS
|
2020-10-28 11:26:38 +00:00
|
|
|
assert payload['sent'] == sent
|
|
|
|
|
assert payload['expires'] == expires
|
2020-12-24 15:09:41 +00:00
|
|
|
assert payload['language'] == expected_language
|
2021-01-29 11:54:12 +00:00
|
|
|
assert payload['channel'] == 'severe'
|
2020-10-20 15:18:24 +01:00
|
|
|
|
|
|
|
|
|
2021-01-25 14:28:40 +00:00
|
|
|
@pytest.mark.parametrize('cbc', ['ee', 'three', 'o2'])
|
2021-01-26 11:11:44 +00:00
|
|
|
def test_cbc_proxy_one_2_many_cancel_invokes_function(mocker, cbc_proxy_client, cbc):
|
2021-01-25 14:28:40 +00:00
|
|
|
cbc_proxy = cbc_proxy_client.get_proxy(cbc)
|
2021-01-14 11:44:46 +00:00
|
|
|
|
2020-12-11 18:52:54 +00:00
|
|
|
identifier = 'my-identifier'
|
2020-12-18 17:22:11 +00:00
|
|
|
MockProviderMessage = namedtuple(
|
|
|
|
|
'BroadcastProviderMessage', ['id', 'message_number', 'created_at']
|
|
|
|
|
)
|
2020-12-11 18:52:54 +00:00
|
|
|
|
|
|
|
|
provider_messages = [
|
2020-12-18 17:22:11 +00:00
|
|
|
MockProviderMessage(uuid.uuid4(), '0000007b', datetime(2020, 12, 16)),
|
|
|
|
|
MockProviderMessage(uuid.uuid4(), '0000004e', datetime(2020, 12, 17))
|
2020-12-11 18:52:54 +00:00
|
|
|
]
|
2020-12-18 17:22:11 +00:00
|
|
|
sent = '2020-12-17 14:19:44.130585'
|
2020-12-11 18:52:54 +00:00
|
|
|
|
|
|
|
|
ld_client_mock = mocker.patch.object(
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc_proxy,
|
2020-12-11 18:52:54 +00:00
|
|
|
'_lambda_client',
|
|
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc_proxy.cancel_broadcast(
|
2020-12-11 18:52:54 +00:00
|
|
|
identifier=identifier,
|
|
|
|
|
message_number='00000050',
|
|
|
|
|
previous_provider_messages=provider_messages,
|
|
|
|
|
sent=sent
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.assert_called_once_with(
|
2021-01-14 11:44:46 +00:00
|
|
|
FunctionName=f'{cbc}-1-proxy',
|
2020-12-11 18:52:54 +00:00
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
kwargs = ld_client_mock.invoke.mock_calls[0][-1]
|
|
|
|
|
payload_bytes = kwargs['Payload']
|
|
|
|
|
payload = json.loads(payload_bytes)
|
|
|
|
|
|
|
|
|
|
assert payload['identifier'] == identifier
|
|
|
|
|
assert 'message_number' not in payload
|
|
|
|
|
assert payload['message_format'] == 'cap'
|
|
|
|
|
assert payload['message_type'] == 'cancel'
|
|
|
|
|
assert payload['references'] == [
|
|
|
|
|
{
|
|
|
|
|
"message_id": str(provider_messages[0].id),
|
2020-12-18 17:22:11 +00:00
|
|
|
"sent": provider_messages[0].created_at.strftime(DATETIME_FORMAT)
|
2020-12-11 18:52:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"message_id": str(provider_messages[1].id),
|
2020-12-18 17:22:11 +00:00
|
|
|
"sent": provider_messages[1].created_at.strftime(DATETIME_FORMAT)
|
2020-12-11 18:52:54 +00:00
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
assert payload['sent'] == sent
|
|
|
|
|
|
|
|
|
|
|
2020-12-24 15:09:41 +00:00
|
|
|
@pytest.mark.parametrize('description, expected_language', (
|
|
|
|
|
('my-description', 'English'),
|
|
|
|
|
('mŷ-description', 'Welsh'),
|
|
|
|
|
))
|
|
|
|
|
def test_cbc_proxy_vodafone_create_and_send_invokes_function(
|
|
|
|
|
mocker,
|
|
|
|
|
cbc_proxy_vodafone,
|
|
|
|
|
description,
|
|
|
|
|
expected_language,
|
|
|
|
|
):
|
2020-12-09 11:13:50 +00:00
|
|
|
identifier = 'my-identifier'
|
|
|
|
|
headline = 'my-headline'
|
|
|
|
|
|
|
|
|
|
sent = 'a-passed-through-sent-value'
|
|
|
|
|
expires = 'a-passed-through-expires-value'
|
|
|
|
|
|
|
|
|
|
ld_client_mock = mocker.patch.object(
|
|
|
|
|
cbc_proxy_vodafone,
|
|
|
|
|
'_lambda_client',
|
|
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cbc_proxy_vodafone.create_and_send_broadcast(
|
|
|
|
|
identifier=identifier,
|
|
|
|
|
message_number='0000007b',
|
|
|
|
|
headline=headline,
|
|
|
|
|
description=description,
|
2021-01-11 15:40:37 +00:00
|
|
|
areas=EXAMPLE_AREAS,
|
2021-01-29 11:54:12 +00:00
|
|
|
sent=sent,
|
|
|
|
|
expires=expires,
|
|
|
|
|
channel="test",
|
2020-12-09 11:13:50 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.assert_called_once_with(
|
|
|
|
|
FunctionName='vodafone-1-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
kwargs = ld_client_mock.invoke.mock_calls[0][-1]
|
|
|
|
|
payload_bytes = kwargs['Payload']
|
|
|
|
|
payload = json.loads(payload_bytes)
|
|
|
|
|
|
|
|
|
|
assert payload['identifier'] == identifier
|
|
|
|
|
assert payload['message_number'] == '0000007b'
|
|
|
|
|
assert payload['message_format'] == 'ibag'
|
|
|
|
|
assert payload['message_type'] == 'alert'
|
|
|
|
|
assert payload['headline'] == headline
|
|
|
|
|
assert payload['description'] == description
|
2021-01-11 15:40:37 +00:00
|
|
|
assert payload['areas'] == EXAMPLE_AREAS
|
2020-12-09 11:13:50 +00:00
|
|
|
assert payload['sent'] == sent
|
|
|
|
|
assert payload['expires'] == expires
|
2020-12-24 15:09:41 +00:00
|
|
|
assert payload['language'] == expected_language
|
2021-01-27 15:19:41 +00:00
|
|
|
assert payload['channel'] == 'test'
|
2020-12-09 11:13:50 +00:00
|
|
|
|
|
|
|
|
|
2020-12-11 18:52:54 +00:00
|
|
|
def test_cbc_proxy_vodafone_cancel_invokes_function(mocker, cbc_proxy_vodafone):
|
|
|
|
|
identifier = 'my-identifier'
|
2020-12-18 17:22:11 +00:00
|
|
|
MockProviderMessage = namedtuple(
|
|
|
|
|
'BroadcastProviderMessage',
|
|
|
|
|
['id', 'message_number', 'created_at']
|
|
|
|
|
)
|
2020-12-11 18:52:54 +00:00
|
|
|
|
|
|
|
|
provider_messages = [
|
2020-12-18 17:22:11 +00:00
|
|
|
MockProviderMessage(uuid.uuid4(), 78, datetime(2020, 12, 16)),
|
|
|
|
|
MockProviderMessage(uuid.uuid4(), 123, datetime(2020, 12, 17))
|
2020-12-11 18:52:54 +00:00
|
|
|
]
|
2020-12-18 17:22:11 +00:00
|
|
|
sent = '2020-12-18 14:19:44.130585'
|
2020-12-11 18:52:54 +00:00
|
|
|
|
|
|
|
|
ld_client_mock = mocker.patch.object(
|
|
|
|
|
cbc_proxy_vodafone,
|
|
|
|
|
'_lambda_client',
|
|
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cbc_proxy_vodafone.cancel_broadcast(
|
|
|
|
|
identifier=identifier,
|
|
|
|
|
message_number='00000050',
|
|
|
|
|
previous_provider_messages=provider_messages,
|
|
|
|
|
sent=sent
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.assert_called_once_with(
|
|
|
|
|
FunctionName='vodafone-1-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
kwargs = ld_client_mock.invoke.mock_calls[0][-1]
|
|
|
|
|
payload_bytes = kwargs['Payload']
|
|
|
|
|
payload = json.loads(payload_bytes)
|
|
|
|
|
|
|
|
|
|
assert payload['identifier'] == identifier
|
|
|
|
|
assert payload['message_number'] == '00000050'
|
|
|
|
|
assert payload['message_format'] == 'ibag'
|
|
|
|
|
assert payload['message_type'] == 'cancel'
|
|
|
|
|
assert payload['references'] == [
|
|
|
|
|
{
|
|
|
|
|
"message_id": str(provider_messages[0].id),
|
2020-12-14 17:52:08 +00:00
|
|
|
"message_number": '0000004e',
|
2020-12-18 17:22:11 +00:00
|
|
|
"sent": provider_messages[0].created_at.strftime(DATETIME_FORMAT)
|
2020-12-11 18:52:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"message_id": str(provider_messages[1].id),
|
2020-12-14 17:52:08 +00:00
|
|
|
"message_number": '0000007b',
|
2020-12-18 17:22:11 +00:00
|
|
|
"sent": provider_messages[1].created_at.strftime(DATETIME_FORMAT)
|
2020-12-11 18:52:54 +00:00
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
assert payload['sent'] == sent
|
|
|
|
|
|
|
|
|
|
|
2021-01-25 14:28:40 +00:00
|
|
|
@pytest.mark.parametrize('cbc', ['ee', 'vodafone', 'three', 'o2'])
|
2021-01-12 12:22:13 +00:00
|
|
|
def test_cbc_proxy_will_failover_to_second_lambda_if_function_error(
|
|
|
|
|
mocker,
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc_proxy_client,
|
2021-01-12 12:22:13 +00:00
|
|
|
cbc
|
|
|
|
|
):
|
2021-01-25 14:28:40 +00:00
|
|
|
cbc_proxy = cbc_proxy_client.get_proxy(cbc)
|
2020-10-20 15:18:24 +01:00
|
|
|
|
2021-01-12 12:22:13 +00:00
|
|
|
ld_client_mock = mocker.patch.object(
|
|
|
|
|
cbc_proxy,
|
|
|
|
|
'_lambda_client',
|
|
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.side_effect = [
|
|
|
|
|
{
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
'FunctionError': 'Handled',
|
|
|
|
|
'Payload': {
|
|
|
|
|
"errorMessage": "",
|
|
|
|
|
"errorType": "CBCNewConnectionError"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'StatusCode': 200
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
cbc_proxy.create_and_send_broadcast(
|
|
|
|
|
identifier='my-identifier',
|
|
|
|
|
message_number='0000007b',
|
|
|
|
|
headline='my-headline',
|
|
|
|
|
description='test-description',
|
|
|
|
|
areas=EXAMPLE_AREAS,
|
|
|
|
|
sent='a-passed-through-sent-value',
|
|
|
|
|
expires='a-passed-through-expires-value',
|
2021-01-29 11:54:12 +00:00
|
|
|
channel="severe",
|
2021-01-12 12:22:13 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert ld_client_mock.invoke.call_args_list == [
|
|
|
|
|
call(
|
|
|
|
|
FunctionName=f'{cbc}-1-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
),
|
|
|
|
|
call(
|
|
|
|
|
FunctionName=f'{cbc}-2-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
2021-01-25 14:28:40 +00:00
|
|
|
@pytest.mark.parametrize('cbc', ['ee', 'vodafone', 'three', 'o2'])
|
2021-01-12 12:22:13 +00:00
|
|
|
def test_cbc_proxy_will_failover_to_second_lambda_if_invoke_error(
|
|
|
|
|
mocker,
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc_proxy_client,
|
2021-01-12 12:22:13 +00:00
|
|
|
cbc
|
|
|
|
|
):
|
2021-01-25 14:28:40 +00:00
|
|
|
cbc_proxy = cbc_proxy_client.get_proxy(cbc)
|
2020-10-28 11:26:38 +00:00
|
|
|
|
2020-10-20 15:18:24 +01:00
|
|
|
ld_client_mock = mocker.patch.object(
|
2021-01-12 12:22:13 +00:00
|
|
|
cbc_proxy,
|
|
|
|
|
'_lambda_client',
|
|
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.side_effect = [
|
|
|
|
|
{
|
|
|
|
|
'StatusCode': 400
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'StatusCode': 200
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
cbc_proxy.create_and_send_broadcast(
|
|
|
|
|
identifier='my-identifier',
|
|
|
|
|
message_number='0000007b',
|
|
|
|
|
headline='my-headline',
|
|
|
|
|
description='test-description',
|
|
|
|
|
areas=EXAMPLE_AREAS,
|
|
|
|
|
sent='a-passed-through-sent-value',
|
|
|
|
|
expires='a-passed-through-expires-value',
|
2021-01-29 11:54:12 +00:00
|
|
|
channel="test",
|
2021-01-12 12:22:13 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert ld_client_mock.invoke.call_args_list == [
|
|
|
|
|
call(
|
|
|
|
|
FunctionName=f'{cbc}-1-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
),
|
|
|
|
|
call(
|
|
|
|
|
FunctionName=f'{cbc}-2-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
2021-01-25 14:28:40 +00:00
|
|
|
@pytest.mark.parametrize('cbc', ['ee', 'vodafone', 'three', 'o2'])
|
2021-01-12 12:22:13 +00:00
|
|
|
def test_cbc_proxy_create_and_send_tries_failover_lambda_on_invoke_error_and_raises_if_both_invoke_error(
|
2021-01-14 11:44:46 +00:00
|
|
|
mocker, cbc_proxy_client, cbc
|
2021-01-12 12:22:13 +00:00
|
|
|
):
|
2021-01-25 14:28:40 +00:00
|
|
|
cbc_proxy = cbc_proxy_client.get_proxy(cbc)
|
2021-01-12 12:22:13 +00:00
|
|
|
|
|
|
|
|
ld_client_mock = mocker.patch.object(
|
|
|
|
|
cbc_proxy,
|
2020-10-22 12:22:11 +01:00
|
|
|
'_lambda_client',
|
2020-10-20 15:18:24 +01:00
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 400,
|
|
|
|
|
}
|
|
|
|
|
|
retry sending broadcasts
Retry tasks if they fail to send a broadcast event. Note that each task
tries the regular proxy and the failover proxy for that provider. This
runs a bit differently than our other retries:
Retry with exponential backoff. Our other tasks retry with a fixed delay
of 5 minutes between tries. If we can't send a broadcast, we want to try
immediately. So instead, implement an exponential backoff (1, 2, 4, 8,
... seconds delay). We can't delay for longer than 310 seconds due to
visibility timeout settings in SQS, so cap the delay at that amount.
Normally we give up retrying after a set amount of retries (often 4
hours). As broadcast content is much more important than normal
notifications, we don't ever want to give up on sending them to phones...
...UNLESS WE DO!
Sometimes we do want to give up sending a broadcast though! Broadcasts
have an expiry time, when they stop showing up on peoples devices, so if
that has passed then we don't need to send the broadcast out.
Broadcast events can also be superceded by updates or cancels. Check
that the event is the most recent event for that broadcast message, if
not, give up, as we don't want to accidentally send out two conflicting
events for the same message.
2021-01-19 10:05:48 +00:00
|
|
|
with pytest.raises(CBCProxyRetryableException) as e:
|
2021-01-12 12:22:13 +00:00
|
|
|
cbc_proxy.create_and_send_broadcast(
|
|
|
|
|
identifier='my-identifier',
|
2020-12-04 17:29:12 +00:00
|
|
|
message_number='0000007b',
|
2021-01-12 12:22:13 +00:00
|
|
|
headline='my-headline',
|
|
|
|
|
description='my-description',
|
2021-01-11 15:40:37 +00:00
|
|
|
areas=EXAMPLE_AREAS,
|
2021-01-12 12:22:13 +00:00
|
|
|
sent='a-passed-through-sent-value',
|
|
|
|
|
expires='a-passed-through-expires-value',
|
2021-01-29 11:54:12 +00:00
|
|
|
channel="test",
|
2020-10-20 15:18:24 +01:00
|
|
|
)
|
|
|
|
|
|
2021-01-12 12:22:13 +00:00
|
|
|
assert e.match(f'Lambda failed for both {cbc}-1-proxy and {cbc}-2-proxy')
|
2020-10-20 15:18:24 +01:00
|
|
|
|
2021-01-12 12:22:13 +00:00
|
|
|
assert ld_client_mock.invoke.call_args_list == [
|
|
|
|
|
call(
|
|
|
|
|
FunctionName=f'{cbc}-1-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
),
|
|
|
|
|
call(
|
|
|
|
|
FunctionName=f'{cbc}-2-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
]
|
2020-10-20 15:18:24 +01:00
|
|
|
|
|
|
|
|
|
2021-01-25 14:28:40 +00:00
|
|
|
@pytest.mark.parametrize('cbc', ['ee', 'vodafone', 'three', 'o2'])
|
2021-01-12 12:22:13 +00:00
|
|
|
def test_cbc_proxy_create_and_send_tries_failover_lambda_on_function_error_and_raises_if_both_function_error(
|
2021-01-14 11:44:46 +00:00
|
|
|
mocker, cbc_proxy_client, cbc
|
2021-01-12 12:22:13 +00:00
|
|
|
):
|
2021-01-25 14:28:40 +00:00
|
|
|
cbc_proxy = cbc_proxy_client.get_proxy(cbc)
|
2020-10-28 11:26:38 +00:00
|
|
|
|
2020-10-20 15:18:24 +01:00
|
|
|
ld_client_mock = mocker.patch.object(
|
2021-01-12 12:22:13 +00:00
|
|
|
cbc_proxy,
|
2020-10-22 12:22:11 +01:00
|
|
|
'_lambda_client',
|
2020-10-20 15:18:24 +01:00
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
'FunctionError': 'something',
|
2021-01-11 15:06:24 +00:00
|
|
|
'Payload': {
|
|
|
|
|
'errorMessage': 'some message',
|
|
|
|
|
'errorType': 'SomeErrorType'
|
|
|
|
|
}
|
2020-10-20 15:18:24 +01:00
|
|
|
}
|
|
|
|
|
|
retry sending broadcasts
Retry tasks if they fail to send a broadcast event. Note that each task
tries the regular proxy and the failover proxy for that provider. This
runs a bit differently than our other retries:
Retry with exponential backoff. Our other tasks retry with a fixed delay
of 5 minutes between tries. If we can't send a broadcast, we want to try
immediately. So instead, implement an exponential backoff (1, 2, 4, 8,
... seconds delay). We can't delay for longer than 310 seconds due to
visibility timeout settings in SQS, so cap the delay at that amount.
Normally we give up retrying after a set amount of retries (often 4
hours). As broadcast content is much more important than normal
notifications, we don't ever want to give up on sending them to phones...
...UNLESS WE DO!
Sometimes we do want to give up sending a broadcast though! Broadcasts
have an expiry time, when they stop showing up on peoples devices, so if
that has passed then we don't need to send the broadcast out.
Broadcast events can also be superceded by updates or cancels. Check
that the event is the most recent event for that broadcast message, if
not, give up, as we don't want to accidentally send out two conflicting
events for the same message.
2021-01-19 10:05:48 +00:00
|
|
|
with pytest.raises(CBCProxyRetryableException) as e:
|
2021-01-12 12:22:13 +00:00
|
|
|
cbc_proxy.create_and_send_broadcast(
|
|
|
|
|
identifier='my-identifier',
|
2020-12-04 17:29:12 +00:00
|
|
|
message_number='0000007b',
|
2021-01-12 12:22:13 +00:00
|
|
|
headline='my-headline',
|
|
|
|
|
description='my-description',
|
2021-01-11 15:40:37 +00:00
|
|
|
areas=EXAMPLE_AREAS,
|
2021-01-12 12:22:13 +00:00
|
|
|
sent='a-passed-through-sent-value',
|
|
|
|
|
expires='a-passed-through-expires-value',
|
2021-01-29 11:54:12 +00:00
|
|
|
channel="severe",
|
2020-10-20 15:18:24 +01:00
|
|
|
)
|
|
|
|
|
|
2021-01-12 12:22:13 +00:00
|
|
|
assert e.match(f'Lambda failed for both {cbc}-1-proxy and {cbc}-2-proxy')
|
2020-10-20 15:18:24 +01:00
|
|
|
|
2021-01-12 12:22:13 +00:00
|
|
|
assert ld_client_mock.invoke.call_args_list == [
|
|
|
|
|
call(
|
|
|
|
|
FunctionName=f'{cbc}-1-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
),
|
|
|
|
|
call(
|
|
|
|
|
FunctionName=f'{cbc}-2-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
]
|
2020-10-26 17:14:08 +00:00
|
|
|
|
|
|
|
|
|
2020-11-17 12:35:22 +00:00
|
|
|
def test_cbc_proxy_send_canary_invokes_function(mocker, cbc_proxy_client):
|
2020-10-26 17:14:08 +00:00
|
|
|
identifier = str(uuid.uuid4())
|
|
|
|
|
|
2020-11-17 12:35:22 +00:00
|
|
|
canary_client = cbc_proxy_client.get_proxy('canary')
|
|
|
|
|
|
2020-10-26 17:14:08 +00:00
|
|
|
ld_client_mock = mocker.patch.object(
|
2020-11-17 12:35:22 +00:00
|
|
|
canary_client,
|
2020-10-26 17:14:08 +00:00
|
|
|
'_lambda_client',
|
|
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-17 12:35:22 +00:00
|
|
|
canary_client.send_canary(
|
2020-10-26 17:14:08 +00:00
|
|
|
identifier=identifier,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.assert_called_once_with(
|
|
|
|
|
FunctionName='canary',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
kwargs = ld_client_mock.invoke.mock_calls[0][-1]
|
|
|
|
|
payload_bytes = kwargs['Payload']
|
|
|
|
|
payload = json.loads(payload_bytes)
|
|
|
|
|
|
|
|
|
|
assert payload['identifier'] == identifier
|
|
|
|
|
|
|
|
|
|
|
2021-01-25 14:28:40 +00:00
|
|
|
@pytest.mark.parametrize('cbc', ['ee', 'three', 'o2'])
|
2021-01-26 11:11:44 +00:00
|
|
|
def test_cbc_proxy_one_2_many_send_link_test_invokes_function(mocker, cbc_proxy_client, cbc):
|
2021-01-25 14:28:40 +00:00
|
|
|
cbc_proxy = cbc_proxy_client.get_proxy(cbc)
|
2021-01-14 11:44:46 +00:00
|
|
|
|
2020-10-26 17:14:08 +00:00
|
|
|
identifier = str(uuid.uuid4())
|
|
|
|
|
|
|
|
|
|
ld_client_mock = mocker.patch.object(
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc_proxy,
|
2020-10-26 17:14:08 +00:00
|
|
|
'_lambda_client',
|
|
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 11:44:46 +00:00
|
|
|
cbc_proxy.send_link_test(
|
2020-10-27 14:44:04 +00:00
|
|
|
identifier=identifier,
|
2020-12-08 11:12:48 +00:00
|
|
|
sequential_number='0000007b',
|
2020-10-27 14:44:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.assert_called_once_with(
|
2021-01-14 11:44:46 +00:00
|
|
|
FunctionName=f'{cbc}-1-proxy',
|
2020-10-27 14:44:04 +00:00
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
kwargs = ld_client_mock.invoke.mock_calls[0][-1]
|
|
|
|
|
payload_bytes = kwargs['Payload']
|
|
|
|
|
payload = json.loads(payload_bytes)
|
|
|
|
|
|
|
|
|
|
assert payload['identifier'] == identifier
|
|
|
|
|
assert payload['message_type'] == 'test'
|
2020-12-09 11:13:50 +00:00
|
|
|
assert 'message_number' not in payload
|
2020-12-09 17:10:40 +00:00
|
|
|
assert payload['message_format'] == 'cap'
|
2020-12-09 11:13:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_cbc_proxy_vodafone_send_link_test_invokes_function(mocker, cbc_proxy_vodafone):
|
|
|
|
|
identifier = str(uuid.uuid4())
|
|
|
|
|
|
|
|
|
|
ld_client_mock = mocker.patch.object(
|
|
|
|
|
cbc_proxy_vodafone,
|
|
|
|
|
'_lambda_client',
|
|
|
|
|
create=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.return_value = {
|
|
|
|
|
'StatusCode': 200,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cbc_proxy_vodafone.send_link_test(
|
|
|
|
|
identifier=identifier,
|
|
|
|
|
sequential_number='0000007b',
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ld_client_mock.invoke.assert_called_once_with(
|
|
|
|
|
FunctionName='vodafone-1-proxy',
|
|
|
|
|
InvocationType='RequestResponse',
|
|
|
|
|
Payload=mocker.ANY,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
kwargs = ld_client_mock.invoke.mock_calls[0][-1]
|
|
|
|
|
payload_bytes = kwargs['Payload']
|
|
|
|
|
payload = json.loads(payload_bytes)
|
|
|
|
|
|
|
|
|
|
assert payload['identifier'] == identifier
|
|
|
|
|
assert payload['message_type'] == 'test'
|
|
|
|
|
assert payload['message_number'] == '0000007b'
|
|
|
|
|
assert payload['message_format'] == 'ibag'
|