"""Test find_or_create_account handler.""" from unittest.mock import patch from ddex_ingester_common.lambda_exceptions import ( LambdaException, ProductExistUnderDifferentVendorException, RetryableException, VendorDoNotIngestException, ) from ddex_ingester_common.schemas.s3_schema import ( S3Schema ) import index import pytest @pytest.fixture def patched_modules(): """Patch the modules used in the handler.""" with ( patch('index.logger') as mock_logger, patch('index.load_ddex_json') as mock_load_ddex_json, patch('index.check_remapping_parent_rep_owner') as mock_check_remapping_parent_rep_owner, patch('index.save_s3_context') as mock_save_s3_context, patch('index.insert_vendor_and_subaccount_mapping') as mock_insert_vendor_and_subaccount_mapping, patch('index.get_vendor_via_graphql') as mock_get_vendor_via_graphql, patch('index.get_subaccount_via_graphql') as mock_get_subaccount_via_graphql, patch('index.get_vendor_and_subaccount_in_mapping_table') as mock_get_vendor_and_subaccount_in_mapping_table, patch('index.get_vendor_and_subaccount_for_existing_product') as mock_get_vendor_and_subaccount_for_existing_product, patch('index.S3Schema.load') as mock_s3_schema_load, patch('index.create_vendor') as mock_create_vendor, patch('index.create_subaccount') as mock_create_subaccount, ): yield { 'logger': mock_logger, 'load_ddex_json': mock_load_ddex_json, 'check_remapping_parent_rep_owner': mock_check_remapping_parent_rep_owner, 'save_s3_context': mock_save_s3_context, 'insert_vendor_and_subaccount_mapping': mock_insert_vendor_and_subaccount_mapping, 'get_vendor_via_graphql': mock_get_vendor_via_graphql, 'get_subaccount_via_graphql': mock_get_subaccount_via_graphql, 'get_vendor_and_subaccount_in_mapping_table': mock_get_vendor_and_subaccount_in_mapping_table, 'get_vendor_and_subaccount_for_existing_product': mock_get_vendor_and_subaccount_for_existing_product, 'S3Schema_load': mock_s3_schema_load, 'create_vendor': mock_create_vendor, 'create_subaccount': mock_create_subaccount, } def test_handler_get_vendor_and_subaccount_for_existing_product( patched_modules, mock_event, s3_ddex): """Test handler with mapping in mapping table.""" patched_modules['get_vendor_and_subaccount_for_existing_product'].return_value = (123, 345) # Call the handler result = index.handler(mock_event, None) # Assertions patched_modules['check_remapping_parent_rep_owner'].assert_called_once_with( S3Schema().load(s3_ddex)) patched_modules[ 'get_vendor_and_subaccount_in_mapping_table'].assert_not_called() patched_modules['get_vendor_via_graphql'].assert_not_called() patched_modules['insert_vendor_and_subaccount_mapping'].assert_not_called() patched_modules['create_vendor'].assert_not_called() assert result['product']['vendor_id'] == 123 assert result['product']['subaccount_id'] == 345 assert result['product']['not_for_distribution'] == 'SMEAnalyticsDummy' def test_handler_get_vendor_and_subaccount_for_existing_product_raises_error( patched_modules, mock_event, s3_ddex): """Test handler with mapping in mapping table.""" patched_modules['get_vendor_and_subaccount_for_existing_product'].side_effect = ( ProductExistUnderDifferentVendorException( 'Product exists under different vendor')) # Call the handler with pytest.raises(ProductExistUnderDifferentVendorException): index.handler(mock_event, None) # Assertions patched_modules['check_remapping_parent_rep_owner'].assert_not_called() patched_modules['get_vendor_and_subaccount_in_mapping_table'].assert_not_called() patched_modules['get_vendor_via_graphql'].assert_not_called() patched_modules['insert_vendor_and_subaccount_mapping'].assert_not_called() patched_modules['create_vendor'].assert_not_called() def test_handler_with_mapping_in_the_mapping_table( patched_modules, mock_event, s3_ddex): """Test handler with mapping in mapping table.""" patched_modules['get_vendor_and_subaccount_for_existing_product'].return_value = (None, None) patched_modules['get_vendor_and_subaccount_in_mapping_table'].return_value = (123, 345) # Call the handler result = index.handler(mock_event, None) # Assertions patched_modules['check_remapping_parent_rep_owner'].assert_called_once_with( S3Schema().load(s3_ddex)) patched_modules['get_vendor_and_subaccount_for_existing_product'].assert_called_once_with( S3Schema().load(s3_ddex)) patched_modules['get_vendor_and_subaccount_in_mapping_table'].assert_called_once_with( S3Schema().load(s3_ddex)) patched_modules['get_vendor_via_graphql'].assert_not_called() patched_modules['insert_vendor_and_subaccount_mapping'].assert_not_called() patched_modules['create_vendor'].assert_not_called() assert result['product']['vendor_id'] == 123 assert result['product']['subaccount_id'] == 345 assert result['product']['not_for_distribution'] == 'SMEAnalyticsDummy' def test_handler_without_mapping_the_mapping_table( patched_modules, mock_event, s3_ddex): """Test handler without mapping in table, but there is mapping via graphql.""" patched_modules['get_vendor_and_subaccount_for_existing_product'].return_value = (None, None) patched_modules['get_vendor_and_subaccount_in_mapping_table'].return_value = (None, None) patched_modules['get_vendor_via_graphql'].return_value = 123 patched_modules['get_subaccount_via_graphql'].return_value = 345 # Call the handler result = index.handler(mock_event, None) # Assertions patched_modules['check_remapping_parent_rep_owner'].assert_called_once_with( S3Schema().load(s3_ddex)) patched_modules['get_vendor_and_subaccount_for_existing_product'].assert_called_once_with( S3Schema().load(s3_ddex)) patched_modules['get_vendor_and_subaccount_in_mapping_table'].assert_called_once_with( S3Schema().load(s3_ddex)) patched_modules['get_vendor_via_graphql'].assert_called_once_with( S3Schema().load(s3_ddex)) patched_modules['get_subaccount_via_graphql'].assert_called_once_with( S3Schema().load(s3_ddex), 123) patched_modules['insert_vendor_and_subaccount_mapping'].assert_called_once_with( patched_modules['logger'], 123, 345, S3Schema().load(s3_ddex)) patched_modules['create_vendor'].assert_not_called() assert result['product']['vendor_id'] == 123 assert result['product']['subaccount_id'] == 345 assert result['product']['not_for_distribution'] == 'SMEAnalyticsDummy' def test_handler_without_vendor_via_graphql(patched_modules, mock_event, s3_ddex): """Test handler without mapping in table and via graphql.""" patched_modules['get_vendor_and_subaccount_for_existing_product'].return_value = (None, None) patched_modules['get_vendor_and_subaccount_in_mapping_table'].return_value = (None, None) patched_modules['get_vendor_via_graphql'].return_value = None patched_modules['create_vendor'].return_value = 123 patched_modules['create_subaccount'].return_value = 345 # Call the handler result = index.handler(mock_event, None) # Assertions patched_modules['check_remapping_parent_rep_owner'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['get_vendor_and_subaccount_for_existing_product'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['get_vendor_and_subaccount_in_mapping_table'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['get_vendor_via_graphql'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['get_subaccount_via_graphql'].assert_not_called() patched_modules[ 'insert_vendor_and_subaccount_mapping'].assert_called_once_with( patched_modules['logger'], 123, 345, S3Schema().load(s3_ddex)) patched_modules['create_vendor'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['create_subaccount'].assert_called_once_with(S3Schema().load(s3_ddex), 123) assert result['product']['vendor_id'] == 123 assert result['product']['subaccount_id'] == 345 assert result['product']['not_for_distribution'] == 'SMEAnalyticsDummy' def test_handler_without_subaccount_via_graphql(patched_modules, mock_event, s3_ddex): """Test handler without mapping in table, there is vendor, but no subaccount.""" patched_modules['get_vendor_and_subaccount_for_existing_product'].return_value = (None, None) patched_modules['get_vendor_and_subaccount_in_mapping_table'].return_value = (None, None) patched_modules['get_vendor_via_graphql'].return_value = 123 patched_modules['get_subaccount_via_graphql'].return_value = None patched_modules['create_subaccount'].return_value = 345 # Call the handler result = index.handler(mock_event, None) # Assertions patched_modules['check_remapping_parent_rep_owner'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['get_vendor_and_subaccount_for_existing_product'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['get_vendor_and_subaccount_in_mapping_table'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['get_vendor_via_graphql'].assert_called_once_with(S3Schema().load(s3_ddex)) patched_modules['get_subaccount_via_graphql'].assert_called_once_with(S3Schema().load(s3_ddex), 123) patched_modules[ 'insert_vendor_and_subaccount_mapping'].assert_called_once_with( patched_modules['logger'], 123, 345, S3Schema().load(s3_ddex)) patched_modules['create_vendor'].assert_not_called() patched_modules['create_subaccount'].assert_called_once_with(S3Schema().load(s3_ddex), 123) assert result['product']['vendor_id'] == 123 assert result['product']['subaccount_id'] == 345 assert result['product']['not_for_distribution'] == 'SMEAnalyticsDummy' @pytest.mark.parametrize('exception', [ (TimeoutError('The read operation timed out')), (ConnectionError('The connection timed out')) ]) def test_handler_raises_retry_error(patched_modules, mock_event, s3_ddex, exception): """Test handler raises RetryableException for specific errors.""" patched_modules['get_vendor_and_subaccount_for_existing_product'].side_effect = exception # Call the handler with pytest.raises(RetryableException): index.handler(mock_event, None) @patch('index.logger') @patch('index.get_vendor_and_subaccount_for_rep_owner_code_rows') def test_get_vendor_and_subaccount_in_mapping_table( mock_get_vendor_and_subaccount, mock_logger, s3_ddex): """Test get_vendor_and_subaccount with existing mapping.""" mock_get_vendor_and_subaccount.return_value = [ {'vendor_id': 123, 'subaccount_id': 345, 'do_not_ingest': False}] context = S3Schema().load(s3_ddex) context.product.imprint = 'foo' # Call the function result = index.get_vendor_and_subaccount_in_mapping_table(context) # Assertions assert result == (123, 345) mock_get_vendor_and_subaccount.assert_called_once_with(mock_logger, context) @patch('index.logger') @patch('index.get_vendor_and_subaccount_for_rep_owner_code_rows') def test_get_vendor_and_subaccount_in_mapping_table_do_not_ingest( mock_get_vendor_and_subaccount, mock_logger, s3_ddex): """Test get_vendor_and_subaccount with existing mapping.""" mock_get_vendor_and_subaccount.return_value = [ {'vendor_id': 123, 'subaccount_id': 345, 'do_not_ingest': True}] context = S3Schema().load(s3_ddex) context.product.imprint = 'foo' # Call the function with pytest.raises(VendorDoNotIngestException): index.get_vendor_and_subaccount_in_mapping_table(context) # Assertions mock_get_vendor_and_subaccount.assert_called_once_with(mock_logger, context) @patch('index.logger') @patch('index.get_vendor_and_subaccount_for_rep_owner_code_rows') def test_get_vendor_and_subaccount_in_mapping_table_no_mapping( mock_get_vendor_and_subaccount, mock_logger, s3_ddex): """Test get_vendor_and_subaccount if there is no mapping.""" mock_get_vendor_and_subaccount.return_value = [] # Call the function response = index.get_vendor_and_subaccount_in_mapping_table(s3_ddex) assert response == (None, None) # Assertions mock_get_vendor_and_subaccount.assert_called_once_with(mock_logger, s3_ddex) @patch('index.logger') @patch('index.get_vendor_and_subaccount_for_rep_owner_code_rows') def test_get_vendor_and_subaccount_in_mapping_table_two_mappings( mock_get_vendor_and_subaccount, mock_logger, s3_ddex): """Test get_vendor_and_subaccount if there are more than one mapping.""" mock_get_vendor_and_subaccount.return_value = [ {'vendor_id': 123, 'subaccount_id': 345, 'do_not_ingest': False}, {'vendor_id': 456, 'subaccount_id': 789, 'do_not_ingest': False}] # Call the function with pytest.raises(LambdaException): index.get_vendor_and_subaccount_in_mapping_table(s3_ddex) # Assertions mock_get_vendor_and_subaccount.assert_called_once_with(mock_logger, s3_ddex) @patch('index.logger') @patch('index.get_vendor_and_subaccount_for_rep_owner_code_rows') @pytest.mark.parametrize( 'imprint', [ 'Palm Tree Records/RCA Records', 'Palm Tree Records', ] ) def test_get_vendor_and_subaccount_in_mapping_table_palm_tree_records( mock_get_vendor_and_subaccount, mock_logger, s3_ddex, imprint): """Test get_vendor_and_subaccount if there palm_tree_records labels.""" mock_get_vendor_and_subaccount.return_value = [ {'vendor_id': 99, 'subaccount_id': 88, 'do_not_ingest': True}] s3_schema = S3Schema().load(s3_ddex) s3_schema.product.imprint = imprint # Call the function result = index.get_vendor_and_subaccount_in_mapping_table(s3_schema) # Assertions assert result == (99, 88) mock_get_vendor_and_subaccount.assert_called_once_with(mock_logger, s3_schema) @patch('index.logger') @patch('index.get_vendor_for_rep_owner_code') def test_get_vendor_via_graphql( mock_get_vendor_for_rep_owner_code, mock_logger, s3_ddex): """Test get_vendor_via_graphql with existing vendor.""" mock_get_vendor_for_rep_owner_code.return_value = [ {'vendorId': 123}] # Call the function result = index.get_vendor_via_graphql(s3_ddex) # Assertions assert result == 123 mock_get_vendor_for_rep_owner_code.assert_called_once_with(mock_logger, s3_ddex) @patch('index.logger') @patch('index.get_vendor_for_rep_owner_code') def test_get_vendor_via_graphql_no_mapping( mock_get_vendor_for_rep_owner_code, mock_logger, s3_ddex): """Test get_vendor_via_graphql if there is no mapping.""" mock_get_vendor_for_rep_owner_code.return_value = [] # Call the function response = index.get_vendor_via_graphql(s3_ddex) assert response is None # Assertions mock_get_vendor_for_rep_owner_code.assert_called_once_with(mock_logger, s3_ddex) @patch('index.logger') @patch('index.get_vendor_for_rep_owner_code') def test_get_vendor_via_graphql_two_mappings( mock_get_vendor_for_rep_owner_code, mock_logger, s3_ddex): """Test get_vendor_via_graphql if there are more than one mapping.""" mock_get_vendor_for_rep_owner_code.return_value = [ {'vendorId': 123}, {'vendorId': 456}] # Call the function with pytest.raises(LambdaException): index.get_vendor_via_graphql(s3_ddex) # Assertions mock_get_vendor_for_rep_owner_code.assert_called_once_with(mock_logger, s3_ddex) @patch('index.logger') @patch('index.get_subaccount_for_vendor') def test_get_subaccount_via_graphql( mock_get_subaccount_for_vendor, mock_logger, s3_ddex): """Test get_subaccount_via_graphql with existing subaccount.""" mock_get_subaccount_for_vendor.return_value = [{ 'name': 'Subaccount Name', 'subaccountId': 1212}] # Call the function result = index.get_subaccount_via_graphql(s3_ddex, 123) # Assertions assert result == 1212 mock_get_subaccount_for_vendor.assert_called_once_with(mock_logger, s3_ddex, 123) @patch('index.logger') @patch('index.get_subaccount_for_vendor') def test_get_subaccount_via_graphql_no_mapping( mock_get_subaccount_for_vendor, mock_logger, s3_ddex): """Test get_subaccount_via_graphql if there is no subaccount.""" mock_get_subaccount_for_vendor.return_value = [] # Call the function response = index.get_subaccount_via_graphql(s3_ddex, 123) assert response is None # Assertions mock_get_subaccount_for_vendor.assert_called_once_with(mock_logger, s3_ddex, 123) @patch('index.logger') @patch('index.get_subaccount_for_vendor') def test_get_subaccount_via_graphql_two_mappings( mock_get_subaccount_for_vendor, mock_logger, s3_ddex): """Test get_subaccount_via_graphql if there are more than one mapping.""" mock_get_subaccount_for_vendor.return_value = [{ 'name': 'Subaccount Name', 'subaccountId': 1212}, {'name': 'Subaccount Name2', 'subaccountId': 1213}] # Call the function with pytest.raises(LambdaException): index.get_subaccount_via_graphql(s3_ddex, 123) # Assertions mock_get_subaccount_for_vendor.assert_called_once_with(mock_logger, s3_ddex, 123) @patch('index.logger') @patch('index.get_product_by_upc') def test_get_vendor_and_subaccount_for_existing_product( mock_get_product_by_upc, mock_logger, s3_ddex): """Test get_product_by_upc with existing product.""" mock_get_product_by_upc.return_value = { 'vendorId': 123, 'subaccountId': 345, 'notForDistribution': 'SMEAnalyticsDummy' } # Call the function result = index.get_vendor_and_subaccount_for_existing_product(s3_ddex) # Assertions assert result == (123, 345) mock_get_product_by_upc.assert_called_once_with(mock_logger, s3_ddex) @patch('index.logger') @patch('index.get_product_by_upc') def test_get_vendor_and_subaccount_for_existing_product_return_nothing( mock_get_product_by_upc, mock_logger, s3_ddex): """Test get_product_by_upc with existing product.""" mock_get_product_by_upc.return_value = None # Call the function result = index.get_vendor_and_subaccount_for_existing_product(s3_ddex) # Assertions assert result == (None, None) mock_get_product_by_upc.assert_called_once_with(mock_logger, s3_ddex) @patch('index.logger') @patch('index.get_product_by_upc') def test_get_vendor_and_subaccount_for_existing_product_error( mock_get_product_by_upc, mock_logger, s3_ddex): """Test get_product_by_upc with existing product.""" context = S3Schema().load(s3_ddex) mock_get_product_by_upc.return_value = { 'vendorId': 123, 'subaccountId': 345, 'notForDistribution': 'N' } # Call the function with pytest.raises(ProductExistUnderDifferentVendorException): index.get_vendor_and_subaccount_for_existing_product(context) # Assertions mock_get_product_by_upc.assert_called_once_with(mock_logger, context) @patch('index.logger') @patch('index.get_parent_repertoire_owner_mapping') def test_check_remapping_parent_rep_owner_no_mapping(mock_get_mapping, mock_logger, s3_ddex): """Test check_remapping_parent_rep_owner with no mappings.""" mock_get_mapping.return_value = [] context = S3Schema().load(s3_ddex) parent_repertoire_owner_code = context.product.parent_repertoire_owner_code parent_repertoire_owner_name = context.product.parent_repertoire_owner_name # Call the function index.check_remapping_parent_rep_owner(context) # Assertions mock_get_mapping.assert_called_once_with(mock_logger, context) assert context.product.parent_repertoire_owner_code == parent_repertoire_owner_code assert context.product.parent_repertoire_owner_name == parent_repertoire_owner_name @patch('index.logger') @patch('index.get_parent_repertoire_owner_mapping') def test_check_remapping_parent_rep_owner_single_mapping(mock_get_mapping, mock_logger, s3_ddex): """Test check_remapping_parent_rep_owner with a single mapping.""" mock_get_mapping.return_value = [{ 'REP_OWNER_PARENT_CD': 'NEW_CODE', 'REP_OWNER_PARENT_NM': 'New Name' }] context = S3Schema().load(s3_ddex) context.product.parent_repertoire_owner_code = 'OLD_CODE' # Call the function index.check_remapping_parent_rep_owner(context) # Assertions mock_get_mapping.assert_called_once_with(mock_logger, context) assert context.product.parent_repertoire_owner_code == 'NEW_CODE' assert context.product.parent_repertoire_owner_name == 'New Name' @patch('index.logger') @patch('index.get_parent_repertoire_owner_mapping') def test_check_remapping_parent_rep_owner_multiple_mappings(mock_get_mapping, mock_logger, s3_ddex): """Test check_remapping_parent_rep_owner with multiple mappings.""" mock_get_mapping.return_value = [ {'REP_OWNER_PARENT_CD': 'CODE1', 'REP_OWNER_PARENT_NM': 'Name1'}, {'REP_OWNER_PARENT_CD': 'CODE2', 'REP_OWNER_PARENT_NM': 'Name2'} ] context = S3Schema().load(s3_ddex) # Call the function and assert exception with pytest.raises(LambdaException): index.check_remapping_parent_rep_owner(context) # Assertions mock_get_mapping.assert_called_once_with(mock_logger, context) @patch('index.logger') @patch('index.create_new_vendor') @patch('index.update_external_identifier_1') @patch('index.get_vendor_country_id') @patch('index.update_vendor_country_id') def test_create_vendor_success(mock_update_vendor_country_id, mock_get_vendor_country_id, mock_update_external_identifier_1, mock_create_new_vendor, mock_logger, s3_ddex): """Test create_vendor with successful vendor creation.""" # Mock the return value of create_new_vendor mock_create_new_vendor.return_value = {'vendorId': 123, 'uuid': 'uuid-123'} mock_get_vendor_country_id.return_value = 5 # Call the function result = index.create_vendor(s3_ddex) # Assertions assert result == 123 mock_create_new_vendor.assert_called_once_with(mock_logger, s3_ddex) mock_update_external_identifier_1.assert_called_once_with(mock_logger, s3_ddex, 'uuid-123') mock_update_vendor_country_id.assert_called_once_with(mock_logger, 5, 'uuid-123') @patch('index.logger') @patch('index.create_new_vendor') @patch('index.update_external_identifier_1') @patch('index.get_vendor_country_id') def test_create_vendor_failure(mock_get_vendor_country_id, mock_update_external_identifier_1, mock_create_new_vendor, mock_logger, s3_ddex): """Test create_vendor when vendor creation fails.""" # Mock the return value of create_new_vendor to None mock_create_new_vendor.return_value = None # Call the function and assert exception with pytest.raises(LambdaException, match='Vendor creation failed.'): index.create_vendor(s3_ddex) # Assertions mock_create_new_vendor.assert_called_once_with(mock_logger, s3_ddex) mock_get_vendor_country_id.assert_called_once_with(s3_ddex) mock_update_external_identifier_1.assert_not_called() @patch('index.logger') @patch('index.create_new_subaccount') def test_create_subaccount_success(mock_create_new_subaccount, mock_logger, s3_ddex): """Test create_subaccount with successful subaccount creation.""" # Mock the return value of create_new_subaccount mock_create_new_subaccount.return_value = {'subaccountId': 345} # Call the function result = index.create_subaccount(s3_ddex, 123) # Assertions assert result == 345 mock_create_new_subaccount.assert_called_once_with(mock_logger, s3_ddex, 123) @patch('index.logger') @patch('index.create_new_subaccount') def test_create_subaccount_failure(mock_create_new_subaccount, mock_logger, s3_ddex): """Test create_subaccount when subaccount creation fails.""" # Mock the return value of create_new_subaccount to None mock_create_new_subaccount.return_value = None # Call the function and assert exception with pytest.raises(LambdaException, match='Subaccount creation failed.'): index.create_subaccount(s3_ddex, 123) # Assertions mock_create_new_subaccount.assert_called_once_with(mock_logger, s3_ddex, 123)