"""Lambda test module.""" from unittest import mock import pytest import index # noqa REMOVE_EVENTS = { 'Records': [{ 'eventID': 'id', 'eventName': 'REMOVE', 'eventVersion': '1.1', 'eventSource': 'aws:dynamodb', 'awsRegion': 'us-east-1', 'dynamodb': { 'ApproximateCreationDateTime': 1520429040.0, 'Keys': { 'principalId_status': { 'S': 'AWS:AIDAJYYLCNJ52WSTX4MME_FAIL'}, 'event_time': {'S': '2018-02-12T15:28:11.610Z'}}, 'OldImage': { 'file_version': {'S': 'GB2B7KQkqN8wtNtcfB5aN_5fIR9_.iYb'}, 'principalId_status': { 'S': 'AWS:AIDAJYYLCNJ52WSTX4MME_FAIL'}, 'file_key': { 'S': 'dev-statement-attachments/25824_227_1mb.doc'}, 'file_name': { 'S': 'dev-statement-attachments/25824_227_1mb.doc'}, 'bucket_name': {'S': 'dev-orchdbucket'}, 'etag': {'S': '109965a0cf0d8618105d8038065f9233'}, 'principalId': {'S': 'asd'}, 'message': {'M': { 'Records': { 'L': [{'M': { 'EventSource': {'S': 'aws:sns'}, 'Sns': { 'M': {'some': 'message'}}, 'EventVersion': {'S': '1.0'}, 'EventSubscriptionArn': { 'S': 'asd'}}}]}}}, 'event_time': {'S': '2018-02-12T15:28:11.610Z'}, 'file_size': {'N': '1053696'}, 'status': {'S': 'FAIL'}}, 'SizeBytes': 2627, 'StreamViewType': 'NEW_AND_OLD_IMAGES'}, 'eventSourceARN': 'asd'}, { 'eventID': 'id', 'eventName': 'REMOVE', 'eventVersion': '1.1', 'eventSource': 'aws:dynamodb', 'awsRegion': 'us-east-1', 'dynamodb': { 'ApproximateCreationDateTime': 1520429040.0, 'Keys': { 'principalId_status': { 'S': 'AWS:AIDAJYYLCNJ52WSTX4MME_FAIL'}, 'event_time': {'S': '2018-02-13T11:08:12.483Z'}}, 'OldImage': { 'file_version': {'S': 'r2.YOdC9HKj5MXSTHAKuozEg9fjFpMp5'}, 'principalId_status': { 'S': 'AWS:AIDAJYYLCNJ52WSTX4MME_FAIL'}, 'file_key': { 'S': 'dev-statement-attachments/25825_227_1mb.doc'}, 'file_name': { 'S': 'dev-statement-attachments/25825_227_1mb.doc'}, 'bucket_name': {'S': 'dev-orchdbucket'}, 'etag': {'S': '123'}, 'principalId': {'S': 'asd'}, 'message': {'M': { 'Records': { 'L': [{'M': {'EventSource': {'S': 'aws:sns'}, 'Sns': {'some': 'message'}, 'EventVersion': {'S': '1.0'}, 'EventSubscriptionArn': { 'S': 'asd'}}}]}}}, 'event_time': {'S': '2018-02-13T11:08:12.483Z'}, 'file_size': {'N': '1053696'}, 'status': {'S': 'FAIL'}}, 'SequenceNumber': '99260500000000031259434675', 'SizeBytes': 2627, 'StreamViewType': 'NEW_AND_OLD_IMAGES'}, 'eventSourceARN': 'asd'}]} INSERT_EVENTS = { 'Records': [{ 'eventID': 'id', 'eventName': 'INSERT', 'eventVersion': '1.1', 'eventSource': 'aws:dynamodb', 'awsRegion': 'us-east-1', 'dynamodb': { 'ApproximateCreationDateTime': 1520429940.0, 'Keys': { 'principalId_status': { 'S': 'AWS:AIDAJYYLCNJ52WSTX4MMM_FAIL'}, 'event_time': {'S': '2018-02-13T11:11:42.695Z'}}, 'NewImage': { 'file_version': {'S': '5Iq0eBvzoE8M3tBi1TMu8j8VMRb4awBq'}, 'principalId_status': { 'S': 'AWS:AIDAJYYLCNJ52WSTX4MMM_FAIL'}, 'file_key': { 'S': 'dev-statement-attachments/L25824_227_1mb.txt'}, 'file_name': {'S': '1mb.txt'}, 'bucket_name': {'S': 'dev-orchdbucket'}, 'etag': {'S': '275cfd7491ce1ce4960697ac96ad951e'}, 'principalId': {'S': 'AWS:AIDAJYYLCNJ52WSTX4MME'}, 'message': {'M': { 'Records': { 'L': [{'M': {'EventSource': {'S': 'aws:sns'}, 'Sns': {'some': 'message'}, 'EventSubscriptionArn': { 'S': 'asd'}, 'EventVersion': {'S': '1.0'}}}]}}}, 'event_time': {'S': '2018-02-13T11:11:42.695Z'}, 'file_size': {'N': '1049999'}, 'status': {'S': 'FAIL'}}, 'SequenceNumber': '99260600000000031260423385', 'SizeBytes': 2675, 'StreamViewType': 'NEW_AND_OLD_IMAGES'}, 'eventSourceARN': 'arn:'}]} @mock.patch('index.process_dynamodb_events') @mock.patch('index.s3') @mock.patch('index.common_config') def test_handler(common_config, s3, process_dynamodb_events): """Test handler function.""" bucket_name = 'test_bucket_name' common_config.S3_BUCKET_NAME = bucket_name common_config.IGNORE_ALL_EVENTS = None s3.delete_objects.return_value = { 'ResponseMetadata': {'HTTPStatusCode': 200}} expected_keys = ['k1', 'k2'] process_dynamodb_events.return_value = expected_keys index.handler(REMOVE_EVENTS, None) process_dynamodb_events.assert_called_once_with(REMOVE_EVENTS['Records']) s3.delete_objects.assert_called_once_with( bucket=bucket_name, keys=expected_keys, quiet=True) @mock.patch('index.process_dynamodb_events') @mock.patch('index.s3') @mock.patch('index.common_config') def test_handler_ignore_all_events(common_config, s3, process_dynamodb_events): """Test handler function.""" bucket_name = 'test_bucket_name' common_config.S3_BUCKET_NAME = bucket_name common_config.IGNORE_ALL_EVENTS = '1' s3.delete_objects.return_value = { 'ResponseMetadata': {'HTTPStatusCode': 200}} expected_keys = ['k1', 'k2'] process_dynamodb_events.return_value = expected_keys assert index.handler(REMOVE_EVENTS, None) is None assert process_dynamodb_events.call_count == 0 assert s3.delete_objects.call_count == 0 def test_process_dynamodb_event(): """Test process_dynamodb_event utility function.""" bucket_name = 'test_bucket' key = 'directory/file.key' remove_event = { 'eventName': 'REMOVE', 'dynamodb': { 'OldImage': { 'bucket_name': {'S': bucket_name}, 'file_key': {'S': key} } } } expected_result = (bucket_name, key) assert index.process_dynamodb_event(remove_event) == expected_result @pytest.mark.parametrize('records, expected_keys', [ ([], []), (['bucket/attachments-key1'], ['attachments-key1']), (['bucket/attachments-key1', 'bucket/attachments-key2'], ['attachments-key1', 'attachments-key2']), (['bucket1/attachments-key1'], []), (['bucket/att-key1', 'bucket/attachments-key2'], ['attachments-key2']), ]) @mock.patch('index.process_dynamodb_event') @mock.patch('index.common_config') def test_process_dynamodb_events( common_config, process_dynamodb_event, records, expected_keys): """Test process_dynamodb_events utility function.""" bucket_name = 'bucket' bucket_folder = 'attachments' common_config.S3_BUCKET_NAME = bucket_name common_config.S3_BUCKET_FOLDER = bucket_folder process_dynamodb_event_returns = [rec.split('/') for rec in records] process_dynamodb_event.side_effect = process_dynamodb_event_returns records = [{'eventName': 'REMOVE', 'data': record} for record in records] result = index.process_dynamodb_events(records) assert result == expected_keys expected_process_dynamodb_event_calls = [ mock.call(item) for item in records] if expected_process_dynamodb_event_calls: process_dynamodb_event.assert_has_calls( expected_process_dynamodb_event_calls) else: process_dynamodb_event.assert_not_called() @mock.patch('index.process_dynamodb_event') @mock.patch('index.common_config') def test_process_dynamodb_events_not_called_on_insert( common_config, process_dynamodb_event): """Test process_dynamodb_events utility function ignores INSERT.""" result = index.process_dynamodb_events(INSERT_EVENTS['Records']) assert result == [] process_dynamodb_event.assert_not_called()