"""Banking details processors tests.""" from unittest.mock import call, Mock, patch from faker import Faker import pytest from src.processors.banking_details.purge_banking_details import ( PurgeBankingDetailsProcessor, ) from src.processors.exceptions import ProcessingError from tests.unit.factories import AbacusStateFactory from tests.utils import create_sample_csv_buffer class TestPurgeBankingDetailsProcessor: """PurgeBankingDetailsProcessor test suite.""" @patch.object(PurgeBankingDetailsProcessor, '_load_csv_accounts') @patch.object(PurgeBankingDetailsProcessor, '_load_payees_by_accounts') @patch.object(PurgeBankingDetailsProcessor, '_validate_payees') @patch.object(PurgeBankingDetailsProcessor, '_purge_banking_details') def test_process( self, mock_purge_banking_details: Mock, mock_validate_payees: Mock, mock_load_payees_by_accounts: Mock, mock_load_csv_accounts: Mock, faker: Faker, ) -> None: """Test process method.""" processor = PurgeBankingDetailsProcessor(faker.pystr(), faker.pystr()) processor.process() mock_purge_banking_details.assert_called_once() mock_validate_payees.assert_called_once() mock_load_payees_by_accounts.assert_called_once() mock_load_csv_accounts.assert_called_once() @patch('src.processors.banking_details.purge_banking_details.capture_message') @patch('src.processors.banking_details.purge_banking_details.logger') def test_capture_error( self, mock_logger: Mock, mock_capture_message: Mock, faker: Faker ) -> None: """Test capture_error.""" message = faker.pystr() processor = PurgeBankingDetailsProcessor(faker.pystr(), faker.pystr()) processor.capture_error(message) mock_logger.error.assert_called_once_with(message) mock_capture_message.assert_called_once_with(message, level='error') @pytest.mark.parametrize('file_content', (['vendor_id', 52, 180], ['vendor_id', 3])) def test_load_data_success(self, file_content: list[str | int]) -> None: """Test loading data from CSV file success.""" processor = PurgeBankingDetailsProcessor('', '') processor._input_file_buffer = create_sample_csv_buffer( ((i,) for i in file_content) ) processor._load_csv_accounts() assert processor._account_ids == file_content[1:] def test_load_data_failure_no_file(self) -> None: """Test loading data from CSV file failure.""" processor = PurgeBankingDetailsProcessor('', '') with pytest.raises(ProcessingError, match='Unable to read the file'): processor._load_csv_accounts() def test_load_data_failure_invalid_content(self) -> None: """Test loading data from CSV file failure.""" processor = PurgeBankingDetailsProcessor('', '') processor._input_file_buffer = create_sample_csv_buffer( (('header',), ('row1',), ('row2',)) ) with pytest.raises(ProcessingError, match='Invalid file content'): processor._load_csv_accounts() def test_load_data_failure_no_items(self) -> None: """Test loading data from CSV file failure.""" processor = PurgeBankingDetailsProcessor('', '') processor._input_file_buffer = create_sample_csv_buffer((('vendor_id',),)) with pytest.raises(ProcessingError, match='No items in file to post'): processor._load_csv_accounts() @patch.object(PurgeBankingDetailsProcessor, 'capture_error') @patch( 'src.processors.banking_details.purge_banking_details.get_payees_by_accounts' ) def test_load_payees_by_accounts( self, mock_get_payees_by_accounts: Mock, mock_capture_error: Mock, faker: Faker ) -> None: """Test _load_payees_by_accounts method.""" account_ids = [105, 81, 15] account_id_to_payee_id = {105: 1050, 15: 152} mock_get_payees_by_accounts.return_value = account_id_to_payee_id processor = PurgeBankingDetailsProcessor(faker.pystr(), faker.pystr()) processor._account_ids = account_ids processor._load_payees_by_accounts() mock_get_payees_by_accounts.assert_called_once_with(account_ids) assert processor._account_id_to_payee_id == account_id_to_payee_id mock_capture_error.assert_called_once_with('Accounts not found: {81}') @patch.object(PurgeBankingDetailsProcessor, 'capture_error') @patch('src.processors.banking_details.purge_banking_details.get_abacus_state') def test_validate_payees( self, mock_get_abacus_state: Mock, mock_capture_error: Mock, faker: Faker ) -> None: """Test _validate_payees method.""" account_id_to_payee_id = {15: 1005, 11: 190, 5: 50, 24: 1002} mock_get_abacus_state.side_effect = [ None, AbacusStateFactory.build(action_status='stat1'), AbacusStateFactory.build(action_status='stat2'), None, ] processor = PurgeBankingDetailsProcessor(faker.pystr(), faker.pystr()) processor._account_id_to_payee_id = account_id_to_payee_id processor._validate_payees() assert mock_get_abacus_state.call_args_list == [ call(payee_id, 'banking_details_review') for payee_id in account_id_to_payee_id.values() ] assert processor._account_payee_ids == [1005, 1002] mock_capture_error.assert_called_once_with( "Account payees have banking_details_review state {190: 'stat1', 50: 'stat2'}" ) @patch( 'src.processors.banking_details.purge_banking_details.delete_banking_details' ) def test_purge_banking_details( self, mock_delete_banking_details: Mock, faker: Faker ) -> None: """Test _purge_banking_details method.""" account_payee_ids = [107, 11, 82] processor = PurgeBankingDetailsProcessor(faker.pystr(), faker.pystr()) processor._account_payee_ids = account_payee_ids processor._purge_banking_details() assert mock_delete_banking_details.call_args_list == [ call(payee_id) for payee_id in account_payee_ids ]