"""Lambda test module.""" from copy import deepcopy import datetime import json from unittest.mock import patch import botocore from src import app as index from src.common import lambda_exceptions import pytest test_filename = 'test_filename' test_bucket = 'test_bucket' test_config = { 'config': { 'output_bucket_name': 'test_bucket', 'preview_bucket_name': 'test_bucket', 'elastic_transcoder_id': '123' } } asset_metadata = { 'Metadata': { 'asset_type': 'image', 'object_id': '123', 'object_type': 'episode', 'original_filename': 'original_filename.ext' } } event_mock = { 'detail': { 'requestParameters': { 'bucketName': test_bucket, 'key': test_filename } } } @patch('src.common.s3.client') @patch('src.common.status.client') @patch('owsrequest.request.process') @patch('src.common.status.datetime') def test_handler_success(datetime_mock, process, sns_client, s3_client): """Test handler function.""" datetime_mock.datetime.now.return_value = datetime.datetime(2020, 1, 1) process.return_value.status_code = 200 process.return_value.json.return_value = test_config s3_client.head_object.return_value = asset_metadata result = index.handler(event_mock, None) assert result == { 'key': test_filename, 'bucket': test_bucket, 'config': test_config['config'] } sns_client.publish.call_count == 2 sns_client.publish.assert_any_call( TopicArn='general-topic-arn', Message=json.dumps({ 'function': 'asset-transcoder-acknowledge', 'status': 'upload_complete', 'filename': 'test_filename', 'bucket': 'test_bucket', 'status_time': '2020-01-01T00:00:00.000000Z', }) ) sns_client.publish.assert_called_with( TopicArn='general-topic-arn', Message=json.dumps({ 'function': 'asset-transcoder-acknowledge', 'status': 'acknowledge_complete', 'filename': 'test_filename', 'bucket': 'test_bucket', 'status_time': '2020-01-01T00:00:00.000000Z', }) ) @patch('src.common.status.client') def test_handler_cloudwatch_event_error(sns_client): """Test handler function with an invalid cloudwatch event.""" bad_event = deepcopy(event_mock) del bad_event['detail']['requestParameters']['bucketName'] with pytest.raises(lambda_exceptions.CloudwatchEventError) as err: index.handler(bad_event, None) assert err.value.error_code == 'cloudwatch_event_error' assert str(err.value) == 'Cloudwatch event does not have the key or bucketName provided: {event}'.format( event=json.dumps(bad_event) ) sns_client.publish.assert_not_called() @patch('src.common.s3.client') @patch('src.common.status.client') @patch('src.common.status.datetime') def test_handler_object_not_found(datetime_mock, sns_client, s3_client): """Test handler function with an object that does not exist.""" datetime_mock.datetime.now.return_value = datetime.datetime(2020, 1, 1) error = {'Error': {'Code': '404', 'Message': 'Not found'}, 'ResponseMetadata': {'HTTPStatusCode': 404}} s3_client.head_object.side_effect = botocore.exceptions.ClientError(error, 'HeadObject') with pytest.raises(lambda_exceptions.S3Error) as err: index.handler(event_mock, None) sns_client.publish.assert_called_with( TopicArn='general-topic-arn', Message=json.dumps({ 'function': 'asset-transcoder-acknowledge', 'status': 'acknowledge_error', 'filename': 'test_filename', 'bucket': 'test_bucket', 'status_time': '2020-01-01T00:00:00.000000Z', 'errors': err.value.errors }) ) @patch('src.common.s3.client') @patch('src.common.status.client') @patch('src.common.status.datetime') def test_handler_invalid_metadata(datetime_mock, sns_client, s3_client): """Test handler function with an s3 object that has invalid metadata.""" datetime_mock.datetime.now.return_value = datetime.datetime(2020, 1, 1) s3_client.head_object.return_value = {} with pytest.raises(lambda_exceptions.S3Error) as err: index.handler(event_mock, None) sns_client.publish.assert_called_with( TopicArn='general-topic-arn', Message=json.dumps({ 'function': 'asset-transcoder-acknowledge', 'status': 'acknowledge_error', 'filename': 'test_filename', 'bucket': 'test_bucket', 'status_time': '2020-01-01T00:00:00.000000Z', 'errors': err.value.errors }) ) @patch('src.common.s3.client') @patch('src.common.status.client') @patch('owsrequest.request.process') @patch('src.common.status.datetime') def test_handler_post_invalid_response(datetime_mock, process, sns_client, s3_client): """Test handler function with a service response containing an invalid asset config.""" datetime_mock.datetime.now.return_value = datetime.datetime(2020, 1, 1) process.return_value.status_code = 200 bad_config = deepcopy(test_config) del bad_config['config']['elastic_transcoder_id'] process.return_value.json.return_value = bad_config s3_client.head_object.return_value = asset_metadata with pytest.raises(lambda_exceptions.AssetConfigError) as err: index.handler(event_mock, None) sns_client.publish.assert_called_with( TopicArn='general-topic-arn', Message=json.dumps({ 'function': 'asset-transcoder-acknowledge', 'status': 'acknowledge_error', 'filename': 'test_filename', 'bucket': 'test_bucket', 'status_time': '2020-01-01T00:00:00.000000Z', 'errors': err.value.errors }) ) @patch('src.common.s3.client') @patch('src.common.status.client') @patch('owsrequest.request.process') @patch('src.common.status.datetime') def test_handler_post_not_found_response(datetime_mock, process, sns_client, s3_client): """Test handler function with a 404 response from the service.""" datetime_mock.datetime.now.return_value = datetime.datetime(2020, 1, 1) process.return_value.status_code = 404 s3_client.head_object.return_value = asset_metadata with pytest.raises(lambda_exceptions.PostAssetNotFoundError): index.handler(event_mock, None) sns_client.publish.call_count == 1 # only the upload complete status is sent. @patch('src.common.s3.client') @patch('src.common.status.client') @patch('owsrequest.request.process') @patch('src.common.status.datetime') def test_handler_post_error_response(datetime_mock, process, sns_client, s3_client): """Test handler function with a 400 response from the service.""" datetime_mock.datetime.now.return_value = datetime.datetime(2020, 1, 1) process.return_value.status_code = 400 process.return_value.text = 'Validation error from microserivce' s3_client.head_object.return_value = asset_metadata with pytest.raises(lambda_exceptions.PostAssetError) as err: index.handler(event_mock, None) sns_client.publish.assert_called_with( TopicArn='general-topic-arn', Message=json.dumps({ 'function': 'asset-transcoder-acknowledge', 'status': 'acknowledge_error', 'filename': 'test_filename', 'bucket': 'test_bucket', 'status_time': '2020-01-01T00:00:00.000000Z', 'errors': err.value.errors }) )