"""Lambda test module.""" from segment import analytics from botocore.exceptions import ClientError import json import pytest from unittest.mock import patch from src import app as index from config import AWS_REGION from config import ENVIRONMENT from ..fixtures.lambda_events import generate_records from ..fixtures.sns_endpoints import generate_attributes """ NOTE: not using moto to mock SNS because get_endpoint_attributes() does not correctly return CustomUserData in response """ @pytest.mark.parametrize(('ows_response', 'failure'), [ (204, False), (404, False), (500, True) ]) @patch('boto3.client') @patch('owsrequest.request.process') @patch.object(analytics, 'track') def test_index(mock_track, ows_request, boto3_client, ows_response, failure): """Full function handler. Args: ows_request (MagicMock): owsrequest.request.process function call boto3_client (MagicMock): boto3.client function call Returns: None """ sns_client = boto3_client.return_value sns_client.get_endpoint_attributes.return_value =\ generate_attributes('{"device_id": "d123", "identity_id": "i123"}') ows_request.return_value.status_code = ows_response if failure: with pytest.raises(Exception) as e: index.handler( generate_records([('arn', 'DeliveryFailure')]), None ) assert e.message ==\ f'unexpected HTTP response status {ows_response}' else: index.handler( generate_records([('arn', 'DeliveryFailure')]), None ) assert boto3_client.call_count == 1 args, kwargs = boto3_client.call_args assert args == ('sns',) assert kwargs == {'region_name': AWS_REGION} assert sns_client.get_endpoint_attributes.call_count == 1 assert ows_request.call_count == 1 args, _ = ows_request.call_args assert args == ( 'lambda-notifications-push-delivery-failure', ENVIRONMENT, 'DELETE', 'ows-users', '/users/identity/i123/device/d123' ) @pytest.mark.parametrize(('error_code', 'fatal'), [ ('NotFound', False), ('PermissionDenied', True) ]) @patch('boto3.client') def test_not_found_endpoint( boto3_client, error_code, fatal): """Test SNS Endpoint not existing. Args: boto3_client (MagicMock): boto3.client function call error_code (str): boto3 error code string fatal (bool): if a ClientError should be thrown Returns: None """ sns_client = boto3_client.return_value sns_client.get_endpoint_attributes.side_effect = ClientError( {'Error': {'Code': error_code}}, 'operation' ) raised = False try: index.handler(generate_records([('arn', 'DeliveryFailure')]), None) except ClientError: raised = True assert raised == fatal def test_extract_messages(): """Test behavior handling event inputs.""" # Empty records from integration tests messages = index.extract_messages({}) assert messages == [] # KeyError on bad input structure with pytest.raises(KeyError): index.extract_messages({ 'Records': [{ 'nope': '' }] }) with pytest.raises(KeyError): index.extract_messages({ 'Records': [{ 'Sns': {} }] }) # JSONDecodeError no KeyError with pytest.raises(json.decoder.JSONDecodeError): index.extract_messages({ 'Records': [{ 'Sns': { 'Message': 'test' } }] }) # filtering mixed event types result = index.extract_messages(generate_records([ ('arn1', 'DeliveryFailure'), ('arn2', 'EndpointCreated'), ('arn3', 'EndpointDeleted'), ('arn4', 'EndpointUpdated') ])) assert len(result) == 1 assert len(result[0].keys()) == 3 assert result[0]['endpoint_arn'] == 'arn1' assert result[0]['event_type'] == 'DeliveryFailure' assert 'id' in result[0] def test_extract_endpoint_attributes(): """Test behavior when extracting CustomUserData from SNS Endpoint.""" # KeyError on Attributes (device_id, identity_id, brand) = index.extract_endpoint_attributes({}) assert device_id is None assert identity_id is None assert brand is None # KeyError on Attributes->CustomUserData (device_id, identity_id, brand) = index.extract_endpoint_attributes( generate_attributes()) assert device_id is None assert identity_id is None assert brand is None # JSONDecodeError on CustomUserData (device_id, identity_id, brand) = index.extract_endpoint_attributes( generate_attributes(custom_user_data='not valid JSON')) assert device_id is None assert identity_id is None assert brand is None # extract data from valid JSON (device_id, identity_id, brand) = index.extract_endpoint_attributes( generate_attributes(custom_user_data='{"device_id" : "d123", "identity_id" : "i123"}')) # noqa:E501 assert device_id == 'd123' assert identity_id == 'i123' assert brand is None # extract data from valid JSON with brand (device_id, identity_id, brand) = index.extract_endpoint_attributes( generate_attributes(custom_user_data='{"device_id" : "d123", "identity_id" : "i123", "brand" : "awal"}')) # noqa:E501 assert device_id == 'd123' assert identity_id == 'i123' assert brand == 'awal'