"""Test Processor.""" from unittest.mock import call, MagicMock, patch, PropertyMock import pytest from commit_royalties.constants import constants from commit_royalties.constants import snowflake from commit_royalties.ledger_entry_queue import LedgerEntryQueue from commit_royalties.ledger_processor import LedgerProcessor from commit_royalties.processor import CommitRoyaltyProcessor @patch('commit_royalties.processor.app_logger') @patch('commit_royalties.processor.config') def test_batch_account_ids(mock_config, mock_logger, mock_event): """Test processor batches list of account_ids into smaller chunks.""" mock_sf_executor = MagicMock() mock_config.ACCOUNT_BATCH_SIZE = 2 account_ids = list(range(10)) processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) res = processor._batch_account_ids(account_ids) assert len(res) == 5 assert mock_logger.info.call_count == 2 mock_logger.info.assert_called_with(constants.LEDGER_MSG.format(10)) def test_commit_royalties(mock_event, mock_sales_query): """Test committing royalty sales to abacus ledgers.""" mock_sf_executor = MagicMock() account_id = mock_sales_query[0].get('ACCOUNT_ID') sales_by_account_id = {account_id: [mock_sales_query]} LedgerEntryQueue.flush_entries = MagicMock() LedgerEntryQueue.length = PropertyMock(return_value=3) LedgerProcessor.process = MagicMock() processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) processor._commit_royalties(sales_by_account_id) LedgerProcessor.process.assert_called_once_with( [mock_sales_query] ) LedgerEntryQueue.flush_entries.assert_called_once() @patch('commit_royalties.processor.get_formatted_query') def test_get_accounts_from_snowflake( mock_sf_query, mock_accounting_run, mock_account_query, mock_event ): """Test querying snowflake to get distinct list of account_ids.""" mock_sf_executor = MagicMock() accounting_run_id = mock_accounting_run.get('accounting_run_id') mock_sf_executor.fetchall.return_value = mock_account_query processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) res = processor._get_accounts_from_snowflake() assert res == [account.get('ACCOUNT_ID') for account in mock_account_query] mock_sf_query.assert_called_once_with( snowflake.GET_ACCOUNTS_WITH_TRANSACTIONS, { 'accounting_run_id': accounting_run_id, 'contract_transaction_table': snowflake.CONTRACT_TRANSACTION_DISTRO } ) mock_sf_executor.fetchall.assert_called_once() @patch('commit_royalties.processor.get_formatted_query') def test_get_total_sales_from_snowflake( mock_sf_query, mock_accounting_run, mock_event, mock_sales_query ): """Test querying snowflake for accounts' sales in accounting period.""" mock_sf_executor = MagicMock() account_ids = [str(sale.get('ACCOUNT_ID')) for sale in mock_sales_query] accounting_run_id = mock_accounting_run.get('accounting_run_id') mock_sf_executor.fetchall.return_value = mock_sales_query processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) res = processor._get_total_sales_from_snowflake(account_ids) assert res == mock_sales_query mock_sf_query.assert_called_once_with( snowflake.GET_TOTALS_BY_CONTRACT_ACCOUNT_DISTRO, { 'account_ids': ','.join(account_ids), 'accounting_run_id': accounting_run_id } ) mock_sf_executor.fetchall.assert_called_once() def test_group_sales_by_account_id(mock_event, mock_sales_query): """Test grouping sales results by account_id.""" mock_sf_executor = MagicMock() account_id = mock_sales_query[0].get('ACCOUNT_ID') processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) res = processor._group_sales_by_account_id(mock_sales_query) assert len(res) == 1 assert res.get(account_id) assert len(res.get(account_id)) == len(mock_sales_query) @patch('commit_royalties.processor.get_accounting_period_detail') @patch('commit_royalties.processor.get_accounting_run_detail') def test_set_contract_type_distro( mock_get_accounting_run, mock_get_accounting_period, mock_accounting_run, mock_event ): """Test updating the processor's _contract_type to 'distribution'.""" mock_sf_executor = MagicMock() accounting_run_id = mock_accounting_run.get('accounting_run_id') accounting_period_id = mock_accounting_run.get('accounting_period_id') mock_get_accounting_run.return_value = mock_accounting_run mock_get_accounting_period.return_value = { 'accounting_period_status': 'open', 'closed_date': None, 'contract_type': constants.CONTRACT_TYPES.DISTRIBUTION, 'accounting_period_name': 'test', 'statement_period_id': 282, 'accounting_period_id': accounting_period_id } processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) processor._set_contract_type() assert processor._contract_type == constants.CONTRACT_TYPES.DISTRIBUTION mock_get_accounting_run.assert_called_once_with(accounting_run_id) mock_get_accounting_period.assert_called_once_with(accounting_period_id) @patch('commit_royalties.processor.get_accounting_period_detail') @patch('commit_royalties.processor.get_accounting_run_detail') def test_set_contract_type_nr( mock_get_accounting_run, mock_get_accounting_period, mock_accounting_run, mock_event ): """Test updating the processor's _contract_type to 'neighbouring_rights'. When event/target is 'accounting_run'. """ mock_sf_executor = MagicMock() accounting_run_id = mock_accounting_run.get('accounting_run_id') accounting_period_id = mock_accounting_run.get('accounting_period_id') mock_get_accounting_run.return_value = mock_accounting_run mock_get_accounting_period.return_value = { 'accounting_period_status': 'open', 'closed_date': None, 'contract_type': constants.CONTRACT_TYPES.NEIGHBOURING_RIGHTS, 'accounting_period_name': 'test', 'statement_period_id': 282, 'accounting_period_id': accounting_period_id } processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) processor._set_contract_type() assert processor._contract_type == constants.CONTRACT_TYPES.NEIGHBOURING_RIGHTS mock_get_accounting_run.assert_called_once_with(accounting_run_id) mock_get_accounting_period.assert_called_once_with(accounting_period_id) @patch('commit_royalties.processor.get_abacus_states') def test_get_accounting_run_state( mock_get_abacus_states, mock_event, mock_abacus_states ): """Test getting accounting_run states by accounting_run_id(target_id).""" mock_sf_executor = MagicMock() accounting_run_id = int(mock_event.get('target_id')) mock_get_abacus_states.return_value = mock_abacus_states processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) res = processor._get_accounting_run_state(accounting_run_id) mock_get_abacus_states.assert_called_once_with('accounting_run', accounting_run_id) assert res.get('abacus_state_id') == 1 assert res.get('parent_table_name') == 'accounting_run' assert res.get('action_name') == 'commit_royalties' @patch('commit_royalties.processor.get_abacus_states') def test_get_accounting_run_state_no_commit_royalties_states( mock_get_abacus_states, mock_event, mock_abacus_states ): """Test raising exception in case no state with commit_royalties action_name.""" # noqa: E501 mock_sf_executor = MagicMock() accounting_run_id = int(mock_event.get('target_id')) mock_get_abacus_states.return_value = [mock_abacus_states[1]] processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) with pytest.raises(ValueError): processor._get_accounting_run_state(accounting_run_id) mock_get_abacus_states.assert_called_once_with('accounting_run', accounting_run_id) @patch('commit_royalties.processor.update_abacus_state_by_id') def test_update_state_status( mock_update_abacus_state_by_id, mock_event, mock_abacus_state ): """Test updating accounting_run state with new status by state_id.""" mock_sf_executor = MagicMock() mock_update_abacus_state_by_id.return_value = mock_abacus_state abacus_state_id = mock_abacus_state.get('abacus_state_id') status = 'some_status' processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) processor._update_state_status(mock_abacus_state, status) mock_update_abacus_state_by_id.assert_called_once_with( abacus_state_id, {'action_status': status} ) @patch('commit_royalties.processor.app_logger') def test_process_successful( mock_logger, mock_abacus_state, mock_accounting_run, mock_account_query, mock_event, mock_sales_query ): """Test CommitRoyaltiesProcessor's main process method when FF is on.""" mock_sf_executor = MagicMock() account_ids = [account.get('ACCOUNT_ID') for account in mock_account_query] accounting_run_id = mock_accounting_run.get('accounting_run_id') sales_by_account_id = dict() for account_id in account_ids: sales_by_account_id[account_id] = [ sale for sale in mock_sales_query if sale.get('ACCOUNT_ID') == account_id ] CommitRoyaltyProcessor._get_accounting_run_state = MagicMock( return_value=mock_abacus_state ) CommitRoyaltyProcessor._update_state_status = MagicMock() CommitRoyaltyProcessor._batch_account_ids = MagicMock(return_value=[account_ids]) CommitRoyaltyProcessor._commit_royalties = MagicMock() CommitRoyaltyProcessor._get_accounts_from_snowflake = MagicMock( return_value=account_ids ) CommitRoyaltyProcessor._get_total_sales_from_snowflake = MagicMock( return_value=mock_sales_query ) CommitRoyaltyProcessor._group_sales_by_account_id = MagicMock( return_value=sales_by_account_id ) CommitRoyaltyProcessor._set_contract_type = MagicMock() processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) processor.process() assert processor._accounting_run_id == accounting_run_id assert processor._event == mock_event assert mock_logger.info.call_count == 3 assert CommitRoyaltyProcessor._update_state_status.call_count == 2 CommitRoyaltyProcessor._set_contract_type.assert_called_once() CommitRoyaltyProcessor._get_accounting_run_state.assert_called_once_with( int(mock_event.get('target_id')) ) CommitRoyaltyProcessor._get_accounts_from_snowflake.assert_called_once() CommitRoyaltyProcessor._batch_account_ids.assert_called_once_with(account_ids) CommitRoyaltyProcessor._get_total_sales_from_snowflake.assert_called_once_with( account_ids ) CommitRoyaltyProcessor._group_sales_by_account_id.assert_called_once_with( mock_sales_query ) CommitRoyaltyProcessor._commit_royalties.assert_called_once_with( sales_by_account_id ) CommitRoyaltyProcessor._update_state_status.assert_has_calls( [call(mock_abacus_state, 'running'), call(mock_abacus_state, 'complete')] ) def test_process_failed( mock_abacus_state, mock_accounting_run, mock_account_query, mock_event, mock_sales_query ): """Test CommitRoyaltiesProcessor's main process method with raising exception.""" mock_sf_executor = MagicMock() CommitRoyaltyProcessor._get_accounting_run_state = MagicMock( return_value=mock_abacus_state ) CommitRoyaltyProcessor._update_state_status = MagicMock() CommitRoyaltyProcessor._set_contract_type = MagicMock( side_effect=Exception() ) with pytest.raises(Exception): processor = CommitRoyaltyProcessor(mock_event, mock_sf_executor) processor.process() assert CommitRoyaltyProcessor._update_state_status.call_count == 2 CommitRoyaltyProcessor._get_accounting_run_state.assert_called_once_with( int(mock_event.get('target_id')) ) CommitRoyaltyProcessor._update_state_status.assert_has_calls( [call(mock_abacus_state, 'running'), call(mock_abacus_state, 'error')] )