"""Unit testcases for AdjustmentsJsonValidationProcessor processor.""" import os from decimal import Decimal from unittest.mock import ANY, MagicMock, call, patch import numpy as np import pandas as pd import pytest from adjustments_json_validation.constants.adjustments_json_validation import ( ERROR_NO_ADJUSTMENT_FILE_FOUND, ERROR_NO_CURRENT_STATEMENT_PERIOD, ERROR_STATEMENT_PERIOD_IS_NOT_IN_CURRENT_STATE, INVALID_FILE_PATH, ) from adjustments_json_validation.error_handling import NotFoundError, ValidationError from adjustments_json_validation.processor import ( AdjustmentsJsonValidationProcessor, ) @patch('adjustments_json_validation.processor.get_statement_period_adjustment_file') def test__get_statement_period_adjustment_file( mock_get_statement_period_adjustment_file, mock_event, mock_statement_period_adjustment_file, ): """Test _get_statement_period_adjustment_file method.""" mock_sf_executor = MagicMock() mock_get_statement_period_adjustment_file.return_value = ( mock_statement_period_adjustment_file ) processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._validate_statement_period = MagicMock(return_value=True) with patch( 'adjustments_json_validation.processor.S3_BUCKET_NAME', 'test', ): file_name, s3_path = processor._get_statement_period_adjustment_file() assert file_name == 'flowthrough_adjustments_file' assert s3_path == '5011/flowthrough_adjustments_file.json.gz' @patch('adjustments_json_validation.processor.get_statement_period_adjustment_file') def test__get_statement_period_adjustment_file_error( mock_get_statement_period_adjustment_file, mock_event, ): """Test raises an error if there is no record for adjustment file.""" mock_sf_executor = MagicMock() mock_get_statement_period_adjustment_file.return_value = None processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with pytest.raises(NotFoundError) as excinfo: processor._get_statement_period_adjustment_file() assert str(excinfo.value) == ERROR_NO_ADJUSTMENT_FILE_FOUND.format( statement_period_adjustment_file_id=1 ) @patch('adjustments_json_validation.processor.get_statement_period_adjustment_file') def test__get_statement_period_adjustment_file_no_file_path( mock_get_statement_period_adjustment_file, mock_event, ): """Test raises an error if there is no valid adjustment file path.""" mock_sf_executor = MagicMock() mock_get_statement_period_adjustment_file.return_value = { 'valid_file_location': None, 'statement_period_id': 1, } processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._validate_statement_period = MagicMock(return_value=True) with pytest.raises(ValidationError) as excinfo: processor._get_statement_period_adjustment_file() assert str(excinfo.value) == INVALID_FILE_PATH @patch('adjustments_json_validation.processor.get_statement_period_adjustment_file') def test__get_statement_period_adjustment_file_no_current_period( mock_get_statement_period_adjustment_file, mock_event, mock_statement_period_adjustment_file, ): """Test raises an error if there is no current statement period.""" mock_sf_executor = MagicMock() mock_get_statement_period_adjustment_file.return_value = ( mock_statement_period_adjustment_file ) processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._validate_statement_period = MagicMock( side_effect=NotFoundError(ERROR_NO_CURRENT_STATEMENT_PERIOD) ) with pytest.raises(NotFoundError) as excinfo: processor._get_statement_period_adjustment_file() assert str(excinfo.value) == ERROR_NO_CURRENT_STATEMENT_PERIOD @patch('adjustments_json_validation.processor.get_current_statement_period') def test__validate_statement_period_success( mock_get_current_statement_period, mock_event, mock_statement_period, ): """Test statement period is in current state.""" mock_sf_executor = MagicMock() mock_get_current_statement_period.return_value = mock_statement_period statement_period_id = 325 processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) result = processor._validate_statement_period(statement_period_id) assert result is True @patch('adjustments_json_validation.processor.get_current_statement_period') def test__validate_statement_period_no_current_period( mock_get_current_statement_period, mock_event, ): """Test raises an error if there is no current statement period.""" mock_sf_executor = MagicMock() mock_get_current_statement_period.return_value = {} statement_period_id = 325 processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with pytest.raises(NotFoundError) as excinfo: processor._validate_statement_period(statement_period_id) assert str(excinfo.value) == ERROR_NO_CURRENT_STATEMENT_PERIOD @patch('adjustments_json_validation.processor.get_current_statement_period') def test__validate_statement_period_not_in_current_state( mock_get_current_statement_period, mock_event, mock_statement_period ): """Test raises an error if adjustment statement period is not in current state.""" mock_sf_executor = MagicMock() mock_get_current_statement_period.return_value = mock_statement_period statement_period_id = 324 processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with pytest.raises(ValidationError) as excinfo: processor._validate_statement_period(statement_period_id) assert str(excinfo.value) == ERROR_STATEMENT_PERIOD_IS_NOT_IN_CURRENT_STATE.format( statement_period_id=statement_period_id ) @patch('adjustments_json_validation.processor.get_formatted_query') def test__create_temp_table_success(mock_get_query, mock_event): """Test to create temp table successfully.""" mock_sf_executor = MagicMock() mock_cursor = MagicMock() mock_cursor.execute.return_value = True mock_get_query.return_value = 'CREATE TABLE TEST...' mock_sf_executor.get_cursor.return_value.__enter__.return_value = mock_cursor processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._create_temp_table() mock_get_query.assert_called_once_with('create_temp_adjustments_upload.sql') mock_cursor.execute.assert_called_once_with('CREATE TABLE TEST...') @patch('adjustments_json_validation.processor.get_formatted_query') def test__create_temp_table_exception(mock_get_query, mock_event): """Test to raise exception when the temp table creation fails.""" mock_sf_executor = MagicMock() mock_cursor = MagicMock() mock_cursor.execute.side_effect = Exception('Snowflake Down') mock_get_query.return_value = 'CREATE TABLE TEST...' mock_sf_executor.get_cursor.return_value.__enter__.return_value = mock_cursor processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with pytest.raises(Exception) as excinfo: processor._create_temp_table() mock_get_query.assert_called_once_with('create_temp_adjustments_upload.sql') mock_cursor.execute.assert_called_once_with('CREATE TABLE TEST...') assert 'Snowflake Down' in str(excinfo.value) @patch('adjustments_json_validation.processor.get_formatted_query') def test__create_temp_raw_json_data_variant_table_success(mock_get_query, mock_event): """Test to create temp table raw_json_data successfully.""" mock_sf_executor = MagicMock() mock_cursor = MagicMock() mock_cursor.execute.return_value = True mock_get_query.return_value = 'CREATE TABLE TEST...' mock_sf_executor.get_cursor.return_value.__enter__.return_value = mock_cursor processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._create_temp_raw_json_data_variant_table() mock_get_query.assert_called_once_with('create_temp_raw_json_data_variant.sql') mock_cursor.execute.assert_called_once_with('CREATE TABLE TEST...') @patch('adjustments_json_validation.processor.get_formatted_query') def test__create_temp_raw_json_data_variant_table_exception(mock_get_query, mock_event): """Test to raise exception when the temp table raw_json_data creation fails.""" mock_sf_executor = MagicMock() mock_cursor = MagicMock() mock_cursor.execute.side_effect = Exception('Snowflake Down') mock_get_query.return_value = 'CREATE TABLE TEST...' mock_sf_executor.get_cursor.return_value.__enter__.return_value = mock_cursor processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with pytest.raises(Exception) as excinfo: processor._create_temp_raw_json_data_variant_table() mock_get_query.assert_called_once_with('create_temp_raw_json_data_variant.sql') mock_cursor.execute.assert_called_once_with('CREATE TABLE TEST...') assert 'Snowflake Down' in str(excinfo.value) @patch('adjustments_json_validation.processor.get_formatted_query') def test__copy_into_temp_raw_json_data_table(mock_get_query, mock_event): """Test to copy records into the temp table raw_json_data.""" mock_sf_executor = MagicMock() mock_cursor = MagicMock() mock_cursor.execute.return_value = True mock_get_query.side_effect = [ 'DESCRIBE TABLE TEMP TABLE...', 'INSERT INTO TEMP_TABLE...', ] mock_sf_executor.get_cursor.return_value.__enter__.return_value = mock_cursor test_s3_path = 'path/to/file.json.gz' processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with patch( 'adjustments_json_validation.processor.ABACUS_ADJUSTMENTS_STAGE', 'dummy_stage', ): processor._copy_into_temp_raw_json_data_table(test_s3_path) assert mock_get_query.call_count == 2 mock_get_query.assert_has_calls( [ call('check_if_temp_raw_json_data_table_exists.sql'), call( 'copy_into_raw_json_data_variant.sql', {'stage': 'dummy_stage', 's3_path': test_s3_path}, ), ] ) assert mock_cursor.execute.call_count == 2 mock_cursor.execute.assert_has_calls( [call('DESCRIBE TABLE TEMP TABLE...'), call('INSERT INTO TEMP_TABLE...')] ) @patch('adjustments_json_validation.processor.get_formatted_query') def test_copy_into_temp_raw_json_data_table_failure(mock_get_query, mock_event): """Test that an exception in the first query stops the process.""" mock_sf_executor = MagicMock() mock_cursor = MagicMock() mock_sf_executor.get_cursor.return_value.__enter__.return_value = mock_cursor mock_cursor.execute.side_effect = Exception('Snowflake Connection Failed') processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with pytest.raises(Exception) as excinfo: processor._copy_into_temp_raw_json_data_table('any_path') assert 'Snowflake Connection Failed' in str(excinfo.value) assert mock_get_query.call_count == 1 @patch('adjustments_json_validation.processor.get_formatted_query') def test__insert_into_temp_table(mock_get_query, mock_event): """Test to insert records into the temp table.""" mock_sf_executor = MagicMock() mock_cursor = MagicMock() mock_cursor.execute.return_value = True mock_get_query.side_effect = [ 'DESCRIBE TABLE TEMP TABLE...', 'INSERT INTO TEMP_TABLE...', ] mock_sf_executor.get_cursor.return_value.__enter__.return_value = mock_cursor processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with patch( 'adjustments_json_validation.processor.ABACUS_ADJUSTMENTS_STAGE', 'dummy_stage', ): processor._insert_into_temp_table() assert mock_get_query.call_count == 2 mock_get_query.assert_has_calls( [ call('check_if_temp_table_exists.sql'), call( 'insert_into_temp_adjustments_uploads.sql', ), ] ) assert mock_cursor.execute.call_count == 2 mock_cursor.execute.assert_has_calls( [call('DESCRIBE TABLE TEMP TABLE...'), call('INSERT INTO TEMP_TABLE...')] ) @patch('adjustments_json_validation.processor.get_formatted_query') def test_insert_into_temp_table_failure(mock_get_query, mock_event): """Test that an exception in the first query stops the process.""" mock_sf_executor = MagicMock() mock_cursor = MagicMock() mock_sf_executor.get_cursor.return_value.__enter__.return_value = mock_cursor mock_cursor.execute.side_effect = Exception('Snowflake Connection Failed') processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) with pytest.raises(Exception) as excinfo: processor._insert_into_temp_table() assert 'Snowflake Connection Failed' in str(excinfo.value) assert mock_get_query.call_count == 1 @patch('adjustments_json_validation.processor.get_formatted_query') def test_validate_adjustments_success(mock_get_query, mock_event): """Test successful validation query and record return.""" mock_sf_executor = MagicMock() mock_rows = [ { 'ID': 1, 'Amount': '100.00', 'Validation Errors': '', 'Total Invalid Rows Count': 0, 'Total Valid Rows Count': 1, } ] mock_sf_executor.fetchall.return_value = mock_rows mock_get_query.return_value = 'SELECT * FROM TEMP_TABLE' processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._statement_period_id = 123 result = processor._validate_adjustments() mock_get_query.assert_called_once_with( 'validate_adjustments.sql', {'statement_period_id': 123} ) mock_sf_executor.fetchall.assert_called_once_with( 'SELECT * FROM TEMP_TABLE', dict_cursor=True ) assert result == mock_rows assert len(result) == 1 assert result[0]['ID'] == 1 @patch('adjustments_json_validation.processor.get_formatted_query') def test_validate_adjustments_empty(mock_get_query, mock_event): """Test behavior when Snowflake returns no records.""" mock_sf_executor = MagicMock() mock_sf_executor.fetchall.return_value = [] mock_get_query.return_value = 'SELECT * FROM TEMP_TABLE' processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._statement_period_id = 123 result = processor._validate_adjustments() mock_get_query.assert_called_once_with( 'validate_adjustments.sql', {'statement_period_id': 123} ) mock_sf_executor.fetchall.assert_called_once_with( 'SELECT * FROM TEMP_TABLE', dict_cursor=True ) assert result == [] assert len(result) == 0 @patch('adjustments_json_validation.processor.tempfile.gettempdir') @patch('adjustments_json_validation.processor.pd.DataFrame.to_json') def test_export_errors_to_json_and_compress_success( mock_to_json, mock_gettempdir, mock_event ): """Test the file path generation and pandas to_json parameters.""" mock_gettempdir.return_value = '/tmp' mock_sf_executor = MagicMock() processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) test_file_name = 'Adjustment Test File' test_df = pd.DataFrame([{'ID': 1, 'Validation Errors': 'Invalid Amount'}]) gzip_path, json_gz_file_name = processor._export_errors_to_json_and_compress( test_file_name, test_df ) expected_filename = 'Adjustment-Test-File-errors.json.gz' expected_path = os.path.join('/tmp', expected_filename) assert json_gz_file_name == expected_filename assert gzip_path == expected_path mock_to_json.assert_called_once_with( expected_path, orient='records', lines=True, compression='gzip', force_ascii=False, ) @patch('adjustments_json_validation.processor.pd.DataFrame.to_json') def test_export_errors_to_json_and_compress_io_error(mock_to_json, mock_event): """Test behavior when disk/pandas writing fails.""" mock_sf_executor = MagicMock() processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) mock_to_json.side_effect = IOError('Disk full') test_df = pd.DataFrame([{'data': 1, 'Validation Errors': None}]) with pytest.raises(IOError) as excinfo: processor._export_errors_to_json_and_compress('file', test_df) assert 'Disk full' in str(excinfo.value) @patch('adjustments_json_validation.processor.get_s3_connector') @patch('adjustments_json_validation.processor.S3_BUCKET_NAME', 'test-bucket') @patch('adjustments_json_validation.processor.S3_ACCOUNT_ID', '123456789') def test_upload_zip_file_to_s3_success(mock_get_s3, mock_event): """Test S3 path generation and upload call parameters.""" mock_s3_connector = MagicMock() mock_get_s3.return_value = mock_s3_connector mock_sf_executor = MagicMock() test_gzip_path = '/tmp/file-errors.json.gz' test_filename = 'file-errors.json.gz' expected_s3_key = '123/file-errors.json.gz' processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._statement_period_adjustment_file_id = 123 result = processor._upload_zip_file_to_s3(test_gzip_path, test_filename) assert result == expected_s3_key mock_s3_connector.upload_object.assert_called_once_with( 'test-bucket', test_gzip_path, expected_s3_key, '123456789' ) @patch('adjustments_json_validation.processor.get_s3_connector') def test_upload_zip_file_to_s3_failure(mock_get_s3, mock_event): """Test behavior when S3 upload fails.""" mock_s3_connector = MagicMock() mock_get_s3.return_value = mock_s3_connector mock_s3_connector.upload_object.side_effect = Exception('S3 Connection Timeout') mock_sf_executor = MagicMock() test_gzip_path = '/tmp/file-errors.json.gz' test_filename = 'file-errors.json.gz' processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._statement_period_adjustment_file_id = 123 with pytest.raises(Exception) as excinfo: processor._upload_zip_file_to_s3(test_gzip_path, test_filename) assert 'S3 Connection Timeout' in str(excinfo.value) def test_is_valid_amount_cases(mock_event): """Test various inputs for amount validation logic.""" mock_sf_executor = MagicMock() processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) assert processor._is_valid_amount('100') is True assert processor._is_valid_amount(100.50) is True assert processor._is_valid_amount('-50.25') is True assert processor._is_valid_amount('nan') is False assert processor._is_valid_amount(str(np.nan)) is False assert processor._is_valid_amount(np.nan) is False assert processor._is_valid_amount(None) is False assert processor._is_valid_amount('abc') is False assert processor._is_valid_amount('100.00.00') is False assert processor._is_valid_amount('') is False def test_calculate_total_adjustments_amount_success(mock_event): """Test summation and rounding logic with mixed valid/invalid rows.""" mock_sf_executor = MagicMock() processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) records = pd.DataFrame( [{'Amount': '100.505'}, {'Amount': 'abc'}, {'Amount': '-20.00'}] ) with patch.object(processor, '_is_valid_amount') as mock_valid_check: mock_valid_check.side_effect = [True, False, True] total, rounded = processor._calculate_total_adjustments_amount(records) expected_total = Decimal('80.505') expected_rounded = Decimal('80.51') assert total == expected_total assert rounded == expected_rounded assert mock_valid_check.call_count == 3 def test_calculate_total_adjustments_empty_df(mock_event): """Test behavior with an empty DataFrame.""" processor = AdjustmentsJsonValidationProcessor(mock_event, MagicMock()) empty_df = pd.DataFrame(columns=['Amount']) total, rounded = processor._calculate_total_adjustments_amount(empty_df) assert total == Decimal('0.0') assert rounded == Decimal('0.00') @patch('adjustments_json_validation.processor.update_statement_period_adjustment_file') @patch('adjustments_json_validation.processor.S3_BUCKET_NAME', 'test-bucket') def test_update_adjustment_file_record_success(mock_update_api, mock_event): """Test that the final dictionary sent to the API is correctly formatted.""" mock_sf_executor = MagicMock() processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._statement_period_id = 10 processor._statement_period_adjustment_file_id = 20 processor._total_valid_rows_count = 5 processor._total_invalid_rows_count = 2 records = pd.DataFrame([{'Amount': '100.00'}]) mock_total = Decimal('100.00') mock_rounded = Decimal('100.00') with patch.object(processor, '_calculate_total_adjustments_amount') as mock_calc: mock_calc.return_value = (mock_total, mock_rounded) error_type = 'CONTENT_ERROR' error_path = 'path/to/error.json.gz' processor._update_statement_period_adjustment_file( records, error_type, error_path ) expected_put_body = { 'valid_row_count': 5, 'invalid_row_count': 2, 'total_file_amount_multicurrency': '100.00', 'total_rounded_amount_multicurrency': '100.00', 'invalid_file_location': 's3://test-bucket/path/to/error.json.gz', 'error_type': 'CONTENT_ERROR', } mock_update_api.assert_called_once_with(expected_put_body, 10, 20) @patch('adjustments_json_validation.processor.update_statement_period_adjustment_file') def test_update_adjustment_file_empty_records(mock_update_api, mock_event): """Test behavior when records are empty (counts should be 0).""" error_type = 'CONTENT_ERROR' processor = AdjustmentsJsonValidationProcessor(mock_event, MagicMock()) processor._statement_period_id = 10 processor._statement_period_adjustment_file_id = 20 processor._update_statement_period_adjustment_file(pd.DataFrame(), error_type, None) expected_put_body = { 'valid_row_count': 0, 'invalid_row_count': 0, 'total_file_amount_multicurrency': '0', 'total_rounded_amount_multicurrency': '0', 'error_type': 'CONTENT_ERROR', } mock_update_api.assert_called_once_with(expected_put_body, 10, 20) class MockErrorTypes: """Mock adjustment file error types.""" CONTENT_ERROR = 'CONTENT_ERROR' @patch( 'adjustments_json_validation.processor.STATEMENT_PERIOD_ADJUSTMENT_FILE_ERROR_TYPES', MockErrorTypes, ) def test_process_with_validation_errors(mock_event): """Test process flow when the file contains invalid records.""" mock_sf_executor = MagicMock() processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._get_statement_period_adjustment_file = MagicMock( return_value=('adjustment_file', 's3://test_bucket/123') ) processor._create_temp_table = MagicMock() processor._create_temp_raw_json_data_variant_table = MagicMock() processor._copy_into_temp_raw_json_data_table = MagicMock() processor._insert_into_temp_table = MagicMock() invalid_records = [ {'ID': 1, 'Total Invalid Rows Count': 2, 'Total Valid Rows Count': 10} ] processor._validate_adjustments = MagicMock(return_value=invalid_records) processor._export_errors_to_json_and_compress = MagicMock( return_value=('/tmp/path', 'adjustment_file.json.gz') ) processor._upload_zip_file_to_s3 = MagicMock( return_value='123/adjustment_file.json.gz' ) processor._update_statement_period_adjustment_file = MagicMock() result = processor.process() assert result is False processor._create_temp_table.assert_called_once() processor._create_temp_raw_json_data_variant_table.assert_called_once() processor._copy_into_temp_raw_json_data_table.assert_called_once_with( 's3://test_bucket/123' ) processor._insert_into_temp_table.assert_called_once() processor._validate_adjustments.assert_called_once() processor._export_errors_to_json_and_compress.assert_called_once() processor._upload_zip_file_to_s3.assert_called_once_with( '/tmp/path', 'adjustment_file.json.gz' ) processor._update_statement_period_adjustment_file.assert_called_once() args = processor._update_statement_period_adjustment_file.call_args[0] assert args[1] == 'CONTENT_ERROR' assert args[2] == '123/adjustment_file.json.gz' def test_process_success_valid_file(mock_event): """Test process method when the file is valid.""" mock_sf_executor = MagicMock() processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._get_statement_period_adjustment_file = MagicMock( return_value=('adjustment_file', 's3://test_bucket/123') ) processor._create_temp_table = MagicMock() processor._create_temp_raw_json_data_variant_table = MagicMock() processor._copy_into_temp_raw_json_data_table = MagicMock() processor._insert_into_temp_table = MagicMock() valid_records = [ {'ID': 1, 'Total Invalid Rows Count': 0, 'Total Valid Rows Count': 5} ] processor._validate_adjustments = MagicMock(return_value=valid_records) processor._export_errors_to_json_and_compress = MagicMock() processor._upload_zip_file_to_s3 = MagicMock() processor._update_statement_period_adjustment_file = MagicMock() result = processor.process() assert result is True assert processor._total_valid_rows_count == 5 assert processor._total_invalid_rows_count == 0 processor._export_errors_to_json_and_compress.assert_not_called() processor._upload_zip_file_to_s3.assert_not_called() processor._update_statement_period_adjustment_file.assert_called_once_with( ANY, None, None ) def test_process_validation_error_exception(mock_event): """Test the exception block when a ValidationError is raised.""" mock_sf_executor = MagicMock() processor = AdjustmentsJsonValidationProcessor(mock_event, mock_sf_executor) processor._statement_period_adjustment_file_id = 123 processor._get_statement_period_adjustment_file = MagicMock( side_effect=ValidationError('No file path') ) processor._create_temp_table = MagicMock() processor._create_temp_raw_json_data_variant_table = MagicMock() processor._copy_into_temp_raw_json_data_table = MagicMock() processor._insert_into_temp_table = MagicMock() processor._validate_adjustments = MagicMock() processor._export_errors_to_json_and_compress = MagicMock() processor._upload_zip_file_to_s3 = MagicMock() processor._update_statement_period_adjustment_file = MagicMock() with pytest.raises(ValidationError): processor.process() assert processor._total_valid_rows_count == 0 assert processor._total_invalid_rows_count == 0 processor._create_temp_table.assert_not_called() processor._create_temp_raw_json_data_variant_table.assert_not_called() processor._copy_into_temp_raw_json_data_table.assert_not_called() processor._insert_into_temp_table.assert_not_called() processor._validate_adjustments.assert_not_called() processor._export_errors_to_json_and_compress.assert_not_called() processor._upload_zip_file_to_s3.assert_not_called() processor._update_statement_period_adjustment_file.assert_not_called()