clients: cbc_proxy client has canary method

The CBC Proxy is essentially a lambda function which we invoke with
various arguments.

A way in which this can fail is that the notifications-api app invoking
the function may not be able, any longer, to invoke the function.

This could be caused by, for example:
* an egress restriction preventing access to eu-west-2.lambda.amazonaws.com
* a network partition preventing access to eu-west-2.lambda.amazonaws.com
* the app's credentials have been rotated or revoked

If we invoke a simple "canary" lambda function for which the app should
have access to invoke, and check it for failures, we will know quickly
if something is likely to be broken.

This is especially important for cell broadcasts compared to email/SMS
because we always have a baseline of traffic for email/SMS, and so any
failure is observed almost immediately. This is not true for CB where we
may expect to only see one CB message every week/month/quarter/year, as
opposed to every minute or second for email/SMS.

Signed-off-by: Toby Lorne <toby.lornewelch-richards@digital.cabinet-office.gov.uk>
Co-authored-by: Pea <pea.tyczynska@digital.cabinet-office.gov.uk>
This commit is contained in:
Toby Lorne
2020-10-26 17:14:08 +00:00
parent fbf3b96113
commit 052de84c9e
2 changed files with 112 additions and 0 deletions

View File

@@ -1,4 +1,5 @@
import json
import uuid
import pytest
@@ -165,3 +166,88 @@ def test_cbc_proxy_create_and_send_handles_function_error(mocker, cbc_proxy):
InvocationType='RequestResponse',
Payload=mocker.ANY,
)
def test_cbc_proxy_send_canary_invokes_function(mocker, cbc_proxy):
identifier = str(uuid.uuid4())
ld_client_mock = mocker.patch.object(
cbc_proxy,
'_lambda_client',
create=True,
)
ld_client_mock.invoke.return_value = {
'StatusCode': 200,
}
cbc_proxy.send_canary(
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
def test_cbc_proxy_send_canary_handles_invoke_error(mocker, cbc_proxy):
identifier = str(uuid.uuid4())
ld_client_mock = mocker.patch.object(
cbc_proxy,
'_lambda_client',
create=True,
)
ld_client_mock.invoke.return_value = {
'StatusCode': 400,
}
with pytest.raises(Exception) as e:
cbc_proxy.send_canary(
identifier=identifier,
)
assert e.match('Function exited with unhandled exception')
ld_client_mock.invoke.assert_called_once_with(
FunctionName='canary',
InvocationType='RequestResponse',
Payload=mocker.ANY,
)
def test_cbc_proxy_send_canary_handles_function_error(mocker, cbc_proxy):
identifier = str(uuid.uuid4())
ld_client_mock = mocker.patch.object(
cbc_proxy,
'_lambda_client',
create=True,
)
ld_client_mock.invoke.return_value = {
'StatusCode': 200,
'FunctionError': 'something',
}
with pytest.raises(Exception) as e:
cbc_proxy.send_canary(
identifier=identifier,
)
assert e.match('Could not invoke lambda')
ld_client_mock.invoke.assert_called_once_with(
FunctionName='canary',
InvocationType='RequestResponse',
Payload=mocker.ANY,
)