"""Tests for processor.""" import pytest from datetime import datetime from datetime import timedelta from unittest.mock import ANY from unittest.mock import patch from json_contract_file_import.constants.json_contract_file_import import \ DEFAULT_ENCODING from json_contract_file_import.entity_import_result import EntityImportResult from json_contract_file_import.processor import _format_directory_suffix from json_contract_file_import.processor import _import_entities from json_contract_file_import.processor import _log_statistics from json_contract_file_import.processor import _process_s3_file from json_contract_file_import.processor import _process_s3_files from json_contract_file_import.processor import process success_account_import_result = EntityImportResult( EntityImportResult.ACCOUNT, '1', True, additional_info='Some additional info.' ) failed_contract_import_result = EntityImportResult( EntityImportResult.CONTRACT, '-1', False, error_message='Some error message.' ) jira_ticket = 'ACC-7777' import_user = 'jdoe' @patch('json_contract_file_import.processor.file_loader') def test_process_no_user_provided(mock_file_loader): """Test process run when no user provided.""" with pytest.raises(Exception) as e_info: mock_file_loader.list_file_keys.return_value = [] process({ 'jira_ticket': jira_ticket }) error_message = e_info.value.args[0] assert error_message == 'import_user and jira_ticket are required parameters.' @patch('json_contract_file_import.processor.file_loader') def test_process_no_ticket_provided(mock_file_loader): """Test process run when no ticket provided.""" with pytest.raises(Exception) as e_info: mock_file_loader.list_file_keys.return_value = [] process({ 'import_user': import_user, }) error_message = e_info.value.args[0] assert error_message == 'import_user and jira_ticket are required parameters.' @patch('json_contract_file_import.processor.file_loader') def test_process_import_user_and_ticket_are_empty_strigns(mock_file_loader): """Test process run when import user and jira ticket are empty strings.""" with pytest.raises(Exception) as e_info: mock_file_loader.list_file_keys.return_value = [] process({ 'import_user': '', 'jira_ticket': '', }) error_message = e_info.value.args[0] assert error_message == 'import_user and jira_ticket are required parameters.' @patch('json_contract_file_import.processor.file_loader') def test_process_no_new_files(mock_file_loader): """Test process run when no new files.""" mock_file_loader.list_file_keys.return_value = [] process({ 'import_user': import_user, 'jira_ticket': jira_ticket }) mock_file_loader.list_file_keys.assert_called_once() @patch('json_contract_file_import.processor.file_loader') def test_process_with_directory(mock_file_loader): """Test process run when directory is passed.""" mock_file_loader.list_file_keys.return_value = [] process({ 'import_user': import_user, 'jira_ticket': jira_ticket, 'directory': 'test1' }) mock_file_loader.list_file_keys.assert_called_once_with('test1/') def test__format_directory_suffix_empty_param(): """Test format directory suffix when empty input param.""" assert _format_directory_suffix('') == '' def test__format_directory_suffix_directory_without_prefix(): """Test format directory suffix when directory without ending slash.""" assert _format_directory_suffix('test1') == 'test1/' def test__format_directory_suffix_directory_with_prefix(): """Test format directory suffix when input with ending slash.""" assert _format_directory_suffix('test1/') == 'test1/' def test__format_directory_suffix_complex_path(): """Test format directory suffix when input is a complex path.""" assert _format_directory_suffix('test1/test2/test3') == 'test1/test2/test3/' @patch('json_contract_file_import.processor._import_entities') @patch('json_contract_file_import.processor.file_loader') @patch('json_contract_file_import.processor.file_parser') @patch('json_contract_file_import.processor._log_statistics') @patch('json_contract_file_import.processor.save_import_status') def test__process_s3_file( mock_save_import_status, mock_log_statistics, mock_file_parser, mock_file_loader, mock_import_entities, mock_json_contract_file_parsed, ): """Test process S3 file.""" entity_import_result_list = [] mock_import_entities.return_value = entity_import_result_list file_key = 's3_file_key.json' report_file_key = 'report_file.json' processed_file_key = 'processed/s3_file_key.json' file_content_bytes = bytes('{}', DEFAULT_ENCODING) mock_file_loader.get_file_content_bytes.return_value = file_content_bytes mock_file_loader.create_report_file.return_value = report_file_key mock_file_loader.move_file_to_processed.return_value = processed_file_key mock_file_parser.parse_bytes.return_value = mock_json_contract_file_parsed _process_s3_file(file_key, False, False, False, import_user, jira_ticket) mock_file_parser.parse_bytes.assert_called_once_with(file_content_bytes) mock_file_loader.get_file_content_bytes.assert_called_once_with(file_key) mock_import_entities.assert_called_once_with( mock_json_contract_file_parsed, False, False, False ) mock_file_loader.create_report_file.assert_called_once_with( file_key, entity_import_result_list ) mock_file_loader.move_file_to_processed.assert_called_once_with( file_key ) mock_log_statistics.assert_called_once_with(file_key, [], ANY) mock_save_import_status.assert_called_once_with( ANY, processed_file_key, report_file_key, False, ANY, entity_import_result_list, mock_json_contract_file_parsed, import_user, jira_ticket ) @patch('json_contract_file_import.processor.file_loader') @patch('json_contract_file_import.processor.account_import') @patch('json_contract_file_import.processor.contract_import') def test__import_entities(mock_contract_import, mock_account_import, mock_json_contract_file_parsed): """Test import entities from S3 file.""" account_import_result = EntityImportResult( EntityImportResult.ACCOUNT, '123', True) contract_import_result = EntityImportResult( EntityImportResult.CONTRACT, '222', True) contract_term_import_result = EntityImportResult( EntityImportResult.CONTRACT_TERM, '333', True) mock_account_import.import_account.return_value = [account_import_result] mock_contract_import.import_contract.return_value = [ contract_import_result, contract_term_import_result ] import_entity_results = _import_entities( mock_json_contract_file_parsed, False, False, False ) assert import_entity_results == [ account_import_result, contract_import_result, contract_term_import_result ] mock_account_import.import_account.assert_called_once_with( mock_json_contract_file_parsed, False) mock_contract_import.import_contract.assert_called_once_with( mock_json_contract_file_parsed, False) @patch('json_contract_file_import.processor.file_loader') @patch('json_contract_file_import.processor.account_import') @patch('json_contract_file_import.processor.contract_import') def test__import_entities_skip_contract_import( mock_contract_import, mock_account_import, mock_json_contract_file_parsed): """Test import entities from S3 file but skip importing contracts.""" account_import_result = EntityImportResult( EntityImportResult.ACCOUNT, '123', True) mock_account_import.import_account.return_value = [account_import_result] import_entity_results = _import_entities( mock_json_contract_file_parsed, False, True, False ) assert import_entity_results == [ account_import_result ] mock_account_import.import_account.assert_called_once_with( mock_json_contract_file_parsed, False) assert not mock_contract_import.import_contract.called @patch('json_contract_file_import.processor._process_s3_file') @patch('json_contract_file_import.processor.datetime') def test__process_s3_files_timeout( mock_datetime, mock_process_s3_file, ): """Test process S3 files with timeout.""" mock_process_s3_file.side_effect = lambda *args: None mock_datetime.now.side_effect = [ datetime(2025, 1, 1, 12, 0, 0), # start time datetime(2025, 1, 1, 12, 0, 1), # first iteration - processed datetime(2025, 1, 1, 12, 15, 0), # second iteration - exceeds timeout ] _process_s3_files( import_user='test_user', jira_ticket='TEST-123', new_s3_file_keys=['file1.json', 'file2.json'], overwrite=False, skip_account_import=False, skip_contract_import=False, timeout_seconds=800 ) # Should only process first file before timeout assert mock_process_s3_file.call_count == 1 mock_process_s3_file.assert_called_once_with( 'file1.json', False, False, False, 'test_user', 'TEST-123' ) @patch('json_contract_file_import.processor.file_loader') @patch('json_contract_file_import.processor.account_import') @patch('json_contract_file_import.processor.contract_import') def test__import_entities_skip_account_import( mock_contract_import, mock_account_import, mock_json_contract_file_parsed): """Test import entities from S3 file but skip importing accounts.""" contract_import_result = EntityImportResult( EntityImportResult.CONTRACT, '222', True) contract_term_import_result = EntityImportResult( EntityImportResult.CONTRACT_TERM, '333', True) mock_contract_import.import_contract.return_value = [ contract_import_result, contract_term_import_result ] import_entity_results = _import_entities( mock_json_contract_file_parsed, False, False, True ) assert import_entity_results == [ contract_import_result, contract_term_import_result ] assert not mock_account_import.import_account.called mock_contract_import.import_contract.assert_called_once_with( mock_json_contract_file_parsed, False) @patch('json_contract_file_import.processor.logger') def test__log_statistics_no_failed_entities(mock_logger): """Test log statistics with no failed entities.""" execution_time = timedelta( seconds=3 ) _log_statistics( 'file_name.json', [success_account_import_result], execution_time ) mock_logger.info.assert_called_once_with( 'Processed file: file_name.json. All entities imported successfully.' ' Processing time: 0:00:03') @patch('json_contract_file_import.processor.logger') def test__log_statistics_with_failed_entity(mock_logger): """Test log statistics with some failed entities.""" execution_time = timedelta( seconds=3 ) _log_statistics( 'file_name.json', [success_account_import_result, failed_contract_import_result], execution_time ) mock_logger.info.assert_called_once_with( "Processed file: file_name.json. Failed entities are: ['contract']." ' Processing time: 0:00:03' ) @patch('json_contract_file_import.processor.file_loader') @patch('json_contract_file_import.processor.file_parser') @patch('json_contract_file_import.processor.account_import') @patch('json_contract_file_import.processor.contract_import') @patch('json_contract_file_import.processor.save_import_status') def test_process_one_file( mock_save_import_status, mock_contract_import, mock_account_import, mock_file_parser, mock_file_loader, mock_json_contract_file_parsed ): """Test process single file.""" s3_file_name = 'file_name.json' report_file_name = 'report.json' processed_file_name = 'processed/file_name.json' file_content_bytes = bytes('{}', DEFAULT_ENCODING) account_import_result = EntityImportResult(EntityImportResult.ACCOUNT, '123', True) contract_import_result = EntityImportResult(EntityImportResult.CONTRACT, '222', True) mock_file_loader.list_file_keys.return_value = [s3_file_name] mock_file_loader.get_file_content_bytes.return_value = file_content_bytes mock_file_loader.create_report_file.return_value = report_file_name mock_file_loader.move_file_to_processed.return_value = processed_file_name mock_file_parser.parse_bytes.return_value = mock_json_contract_file_parsed mock_account_import.import_account.return_value = [account_import_result] mock_contract_import.import_contract.return_value = [ contract_import_result ] process({ 'import_user': import_user, 'jira_ticket': jira_ticket, }) mock_file_loader.list_file_keys.assert_called_once() mock_file_loader.get_file_content_bytes.assert_called_once_with( s3_file_name) mock_file_parser.parse_bytes.assert_called_once_with(file_content_bytes) mock_account_import.import_account.assert_called_once_with( mock_json_contract_file_parsed, False) mock_contract_import.import_contract.assert_called_once_with( mock_json_contract_file_parsed, False) mock_file_loader.move_file_to_processed.assert_called_once_with( s3_file_name) mock_file_loader.create_report_file.assert_called_once_with(s3_file_name, [ account_import_result, contract_import_result]) mock_save_import_status.assert_called_once_with( ANY, processed_file_name, report_file_name, False, ANY, [account_import_result, contract_import_result], mock_json_contract_file_parsed, import_user, jira_ticket )