"""Test cases for common utility functions.""" from collections import namedtuple from unittest import mock import pytest from src.constants.constants import Error from src.constants.constants import Status from src.utils.functions import format_quarter_file_name from src.utils.functions import get_attachment_primary_key_value from src.utils.functions import get_file_name_from_key from src.utils.functions import get_quarter_periods_by_period from src.utils.functions import parse_file_key from src.utils.functions import s3_event_get_attachment_details from src.utils.functions import validate_extension from src.utils.functions import validate_file from src.utils.functions import validate_path from src.utils.functions import validate_size Response = namedtuple('Response', 'status message') @pytest.mark.parametrize( 'key, expected_result', [ ( 'L10303_217_attac1.txt', { 'account_type': 'L', 'label_id': '10303', 'contract_id': None, 'period_id': '217', 'filename': 'attac1.txt', 'extension': 'txt', }, ), ('12345', {}), ('randomstring.', {}), ( 'L10303|123_217_attac1.txt', { 'account_type': 'L', 'label_id': '10303', 'contract_id': '123', 'period_id': '217', 'filename': 'attac1.txt', 'extension': 'txt', }, ), ('L10303|notADigitContract_217_attac1.txt', {}), ], ) def test_parse_file_key(key, expected_result): """Test parse_file_key function.""" res = parse_file_key(key) assert res == expected_result @pytest.mark.parametrize( 'size, expected_result', [ (1024, True), (1024 * 1024, True), (10 * 1024 * 1024, True), (20 * 1024 * 1024, True), (21 * 1024 * 1024, False), ], ) def test_validate_size(size, expected_result): """Test validate_size function.""" assert validate_size(size) == expected_result @pytest.mark.parametrize( 'extension, expected_result', [ ('pdf', True), ('csv', True), ('xls', True), ('xlsx', True), ('png', True), ('jpg', True), ('doc', True), ('docx', True), ('PDF', True), ('txt', False), ('exe', False), ], ) def test_validate_extension(extension, expected_result): """Test validate_extension function.""" assert validate_extension(extension) == expected_result @pytest.mark.parametrize( 'key, expected_result', [ ('HappyFace.jpg', False), ('another-dir/HappyFace.jpg', False), ('dev-statement-attachments/HappyFace.jpg', True), ], ) @mock.patch('src.utils.functions.S3_BUCKET_FOLDER', 'dev-statement-attachments') def test_validate_path(key, expected_result): """Test validate_path function.""" assert validate_path(key) == expected_result @pytest.mark.parametrize( 'validation_to_fail, expected_error', [ ('validate_path', Error.INVALID_PATH_MSG), ('validate_size', Error.INVALID_SIZE_MSG), ('parse_file_key', Error.INVALID_NAME_MSG), ('validate_extension', Error.INVALID_EXTENSION_MSG), ('no_failure', None), ], ) @mock.patch('src.utils.functions.validate_extension') @mock.patch('src.utils.functions.parse_file_key') @mock.patch('src.utils.functions.validate_size') @mock.patch('src.utils.functions.validate_path') def test_validate_file( mock_validate_path, mock_validate_size, mock_parse_file_key, mock_validate_extension, validation_to_fail, expected_error, s3_event_fixture, ): """Test validate_file function.""" validation_mock = locals().get(f'mock_{validation_to_fail}') if validation_mock: if validation_to_fail == 'parse_file_key': validation_mock.return_value = None else: validation_mock.return_value = False result = validate_file(s3_event_fixture) assert result == expected_error @pytest.mark.parametrize( 'key, expected_result', [ ('test/test.key', 'test.key'), ('test123.key', 'test123.key'), ('another-level/test/test-file.key', 'test-file.key'), ], ) def test_get_file_name_from_key(key, expected_result): """Test get_file_name_from_key utility function.""" assert get_file_name_from_key(key) == expected_result @pytest.mark.parametrize( 'period_id, expected_periods_list', [ (1, [1, 2, 3]), (2, [1, 2, 3]), (3, [1, 2, 3]), (88, [88, 89, 90]), (89, [88, 89, 90]), (90, [88, 89, 90]), (187, [187, 188, 189]), (188, [187, 188, 189]), (189, [187, 188, 189]), (226, [226, 227, 228]), (227, [226, 227, 228]), (228, [226, 227, 228]), ], ) def test_get_quarter_periods_by_period(period_id, expected_periods_list): """Test get_quarter_periods_by_period with different 4 quarters periods.""" result_list = get_quarter_periods_by_period(period_id) assert result_list == expected_periods_list @pytest.mark.parametrize( 'account_type, account_id, period_ids, expected_str', [ ('L', 10303, [217, 218, 219], 'L10303_217_218_219'), ('L', 10303, [217], 'L10303_217'), ('S', 10303, [217], 'S10303_217'), ], ) def test_get_attachment_primary_key_value(account_type, account_id, period_ids, expected_str): """Test get_attachment_primary_key_value.""" result_str = get_attachment_primary_key_value(account_type, account_id, period_ids) assert result_str == expected_str @pytest.fixture def s3_event_fixture(): """S3 event fixture.""" return { 'Records': [ { 'eventVersion': '2.0', 'eventTime': '1970-01-01T00:00:00.000Z', 'requestParameters': {'sourceIPAddress': '127.0.0.1'}, 's3': { 'configurationId': 'testConfigRule', 'object': { 'eTag': '0123456789abcdef0123456789abcdef', 'sequencer': '0A1B2C3D4E5F678901', 'key': '/testfolder/L10303_217_attac1.txt', 'size': 1024, }, 'bucket': { 'arn': 'bucketarn', 'name': 'sourcebucket', 'ownerIdentity': {'principalId': 'EXAMPLE'}, }, 's3SchemaVersion': '1.0', }, 'responseElements': { 'x-amz-id-2': '/mnopqrstuvwxyzABCDEFGH', 'x-amz-request-id': 'EXAMPLE123456789', }, 'awsRegion': 'us-east-1', 'eventName': 'ObjectCreated:Put', 'userIdentity': {'principalId': 'EXAMPLE'}, 'eventSource': 'aws:s3', } ] } def test_s3_event_get_attachment_details_success(s3_event_fixture): """Test s3_event_get_attachment_details.""" file_name = 'attac1.txt' file_type = 'txt' account_type = 'L' label_id = '10303' period_id = '217' attachment_attrs = { 'filename': file_name, 'extension': file_type, 'account_type': account_type, 'label_id': label_id, 'contract_id': '123', 'period_id': period_id, } expected_result = { 'file_key': '/testfolder/L10303_217_attac1.txt', 'file_name': file_name, 'original_file_name': file_name, 'file_type': file_type, 'bucket_name': 'sourcebucket', 'file_size': 1024, 'etag': '0123456789abcdef0123456789abcdef', 'account_type': account_type, 'label_id': 10303, 'contract_id': 123, 'period_ids': 217, 'status': Status.STATUS_COMPLETED, 'upload_date': '1970-01-01T00:00:00.000Z', } result = s3_event_get_attachment_details(s3_event_fixture, attachment_attrs) assert result == expected_result def test_s3_event_get_attachment_details_exception(s3_event_fixture): """Test s3_event_get_attachment_details in case of exception.""" del s3_event_fixture['Records'][0]['s3'] with pytest.raises(Exception): s3_event_get_attachment_details(s3_event_fixture, {}) @pytest.mark.parametrize( 'file_name, period_id, expected_result', [ ('test.csv', 217, 'test.csv(217)'), ('test.csv', 218, 'test.csv(218)'), ('test.csv', 219, 'test.csv(219)'), ], ) def test_format_quarter_file_name(file_name, period_id, expected_result): """Test format_quarter_file_name.""" result = format_quarter_file_name(file_name, period_id) assert expected_result == result