"""Lambda test module.""" from unittest.mock import patch import pytest from freezegun import freeze_time from constants import email from constants import errors from constants import general import index @pytest.fixture def event_data(): """Fixture for the incoming event.""" return { 'function': 'test-lambda-function', 'status': 400, 's3_object': { 'key': 'test_file.txt', 'bucket': 'bucket-test' }, 'error_code': 'test_error_code', 'error_description': 'Test error description' } @pytest.mark.parametrize( 'code_received, expected_subject, expected_message_body', [ ( 'wrong_file_size_error', 'Uploaded file "test_file.txt" validation failed', 'File "test_file.txt" validation failed due to file size ' 'limit excess.\nPlease split the file into 2 or more of up ' 'to 450 MB and try again.'), ( 'wrong_file_type_error', 'Uploaded file "test_file.txt" validation failed', 'File "test_file.txt" validation failed due to invalid file ' 'type.\nSupported file types are ".TXT", ".CSV" and ".TSV" only.'), ( 'missing_data', 'Sales file "test_file.txt" processing failed', 'File "test_file.txt" processing failed due to missing data.\n' 'Please make sure that file has a data in it and upload it ' 'again.'), ( 'invalid_file_structure', 'Sales file "test_file.txt" processing failed', 'File "test_file.txt" processing failed due to invalid file ' 'structure.\nPlease make sure that file contains all the ' 'necessary fields and upload it again.'), ( 'encoding_not_identified', 'Sales file "test_file.txt" processing failed', 'File "test_file.txt" processing failed due to encoding issue.\n' 'Please check the file, re-save it with "UTF-8", ' '"windows1252" or "iso-8859-1" encoding, and upload again. ' 'If issue persists, contact IT department.'), ( 'database_error', 'Sales file "test_file.txt" processing failed', 'File "test_file.txt" processing failed due to system issue.\n' 'Please try again. If issue persists, contact IT department.'), ( 'file_processing_error', 'Sales file "test_file.txt" processing failed', 'File "test_file.txt" processing failed due to system issue.\n' 'Please try again. If issue persists, contact IT department.'), ( 'processing_succeeded', 'Sales file "test_file.txt" has been processed successfully', 'File "test_file.txt" has been processed successfully. Data from ' 'the file is now available in the DB.') ]) def test_prepare_message( code_received, expected_subject, expected_message_body): """Test prepare_message function.""" file_name = 'test_file.txt' subject, message_body = index.prepare_message(file_name, code_received) assert subject == expected_subject assert message_body == expected_message_body @patch('index.prepare_message') @patch( 'common_config.EMAIL_RECIPIENTS', 'test_email@test.com test_email_two@test.com') @patch( 'common_config.EMAIL_SENDER', 'test_sender@test.com') @patch('ses.send_email') def test_handler( send_email_mock, prepare_message_mock, event_data): """Test handler function.""" test_subject = 'Test subject.' test_message = 'Test message.' prepare_message_mock.return_value = test_subject, test_message result = index.handler(event_data, None) prepare_message_mock.assert_called_once_with( event_data['s3_object']['key'], event_data['error_code'], None) send_email_mock.assert_called_once_with( recipients=['test_email@test.com', 'test_email_two@test.com'], sender='test_sender@test.com', subject=test_subject, message=test_message ) assert result == { 'function': general.LAMBDA_NAME, 'status': 200, 's3_object': { 'key': event_data['s3_object']['key'], 'bucket': event_data['s3_object']['bucket'] } } @patch( 'common_config.EMAIL_RECIPIENTS', 'test_email@test.com test_email_two@test.com') @patch( 'common_config.EMAIL_SENDER', 'test_sender@test.com') @patch('ses.send_email') def test_handler_event_with_internal_lambda_error( send_email_mock, event_data): """Test handler function.""" event_data['error'] = {'error': 'data'} test_subject = 'Sales file "test_file.txt" processing failed' test_message = 'File "test_file.txt" processing failed due to system' \ ' issue.\nPlease try again. If issue persists,' \ ' contact IT department.' result = index.handler(event_data, None) send_email_mock.assert_called_once_with( recipients=['test_email@test.com', 'test_email_two@test.com'], sender='test_sender@test.com', subject=test_subject, message=test_message) assert result == { 'function': general.LAMBDA_NAME, 'status': 200, 's3_object': { 'key': event_data['s3_object']['key'], 'bucket': event_data['s3_object']['bucket'] } } @patch('index.prepare_message') @patch( 'common_config.EMAIL_RECIPIENTS', 'test_email@test.com test_email_two@test.com') @patch( 'common_config.EMAIL_SENDER', 'test_sender@test.com') @patch('ses.send_email') @patch('status.send_failure_status') def test_handler_failure( send_failure_status_mock, send_email_mock, prepare_message_mock, event_data): """Test handler with exception.""" test_subject = 'Test subject.' test_message = 'Test message.' prepare_message_mock.return_value = test_subject, test_message exception_msg = 'error message' error_msg = errors.ERROR_MESSAGES[ errors.EMAIL_SENDING_ERROR_CODE].format(message=exception_msg) send_email_mock.side_effect = Exception(exception_msg) result = index.handler(event_data, None) prepare_message_mock.assert_called_once_with( event_data['s3_object']['key'], event_data['error_code'], None) send_email_mock.assert_called_once_with( recipients=['test_email@test.com', 'test_email_two@test.com'], sender='test_sender@test.com', subject=test_subject, message=test_message ) send_failure_status_mock.assert_called_once_with( general.LAMBDA_NAME, errors.INTERNAL_ERROR_STATUS, event_data['s3_object']['key'], errors.EMAIL_SENDING_ERROR_CODE, error_msg, event_data['s3_object']['bucket']) assert result == { 'function': general.LAMBDA_NAME, 'status': 500, 's3_object': { 'key': event_data['s3_object']['key'], 'bucket': event_data['s3_object']['bucket'] }, 'error_code': 'email_sending_error', 'error_description': ['error message'] } @patch('status.send_failure_status') def test_handler_incorrect_event_data(send_failure_status_mock): """Test handler with incorrect event data.""" incorrect_event_data = {'incorrect_event_data': 'some_data'} error_msg = errors.ERROR_MESSAGES[ errors.MISSING_FILE_PATH_CODE] result = index.handler(incorrect_event_data, None) send_failure_status_mock.assert_called_once_with( general.LAMBDA_NAME, errors.INVALID_DATA_ERROR_STATUS, None, errors.MISSING_FILE_PATH_CODE, error_msg, None) assert result == { 'function': general.LAMBDA_NAME, 'status': 400, 'error_code': 'file_path_is_missing', 'error_description': ( ['An error occurred: the uploaded file path is missing.']) } def test_compose_partial_processing_errors_text(): """Test compose_partial_processing_errors_text function.""" received_errors = { 'content_does_not_match_headers': { 'line_numbers': [1, 2, 3, 4, 5] }, 'missing_mandatory_fields': { '22': ['field_one', 'field_two', 'field_three'], '33': ['field_two', 'field_five']}, 'partial_processing_errors': { 'first_unknown_error': [22, 33], 'second_unknown_error': [44, 55, 66] } } result = index.compose_partial_processing_errors_text(received_errors) assert result == [ 'Error: Number of fields in the row doesn\'t match the number of ' 'fields in the header.\nSkipped rows:\n1\n2\n3\n4\n5', 'Error: Mandatory field value is missing.\nSkipped rows:\n' 'Row 22: field_one, field_two, field_three.\n' 'Row 33: field_two, field_five.', 'Error: Unexpected error in the row.\nSkipped ' 'rows:\n22\n33\n44\n55\n66'] @freeze_time('2018-01-18') def test_compose_partial_processing_fix_text(): """Test compose_partial_processing_fix_text function.""" test_file_name = 'test_file.txt' test_notification = ( email.ERROR_CODE_TEXT_MAPPING['processing_partially_succeeded']) test_fix_text = test_notification.fix_text result = index.compose_partial_processing_fix_text( test_fix_text, test_file_name) assert result == ( 'Correct the records manually and either reupload the file ' '"test_file.txt" or create a new file with corrected records only and ' 'upload it with new name (for example, "test_file_20180118.txt" ' 'or "test_file_1.txt")')