"""Test handler.""" from unittest.mock import MagicMock, patch from constants import queries from ddex_ingester_common.constants import ddex_providers from ddex_ingester_common.lambda_exceptions import ( ArtistIdNotFoundException, DuplicateProjectCodeException, ProjectCodeMismatchException, ) from ddex_ingester_common.schemas.s3_schema import S3Schema from ddex_ingester_common.schemas.state_machine_schema import ( StateMachineSchema ) import index from lambdacommon.graphql import graphql import pytest @patch('index.graphql_gateway.execute') @patch('index.retrieve_artist_id') def test_update_project_payload( mock_retrieve_artist_id, mock_graphql_execute, get_project_response, context, s3_ddex ): """Test that update project calls graphql with correct payload.""" mock_retrieve_artist_id.return_value = 2348776 payload = [ 'name', 'artistId', 'projectId', 'description' ] context = StateMachineSchema().load(context) s3_ddex = S3Schema().load(s3_ddex) index.update_project(context, s3_ddex) call_dict = mock_graphql_execute.mock_calls[0][1][1]['data'] call_keys = list(call_dict) mock_graphql_execute.assert_called_once() assert payload == call_keys mock_retrieve_artist_id.assert_called_with(s3_ddex) @patch('index.graphql_gateway.execute') @patch('index.retrieve_artist_id') def test_update_project_payload_no_description( mock_retrieve_artist_id, mock_graphql_execute, get_project_response, context, s3_ddex ): """Test that update calls graphql without description in payload.""" mock_retrieve_artist_id.return_value = 2348776 payload = [ 'name', 'artistId', 'projectId' ] context = StateMachineSchema().load(context) s3_ddex = S3Schema().load(s3_ddex) s3_ddex.project.description = None index.update_project(context, s3_ddex) call_dict = mock_graphql_execute.mock_calls[0][1][1]['data'] call_keys = list(call_dict) mock_graphql_execute.assert_called_once() assert payload == call_keys mock_retrieve_artist_id.assert_called_with(s3_ddex) @patch('index.check_for_project') @patch('index.graphql_gateway.execute') @patch('index.load_ddex_json') @patch('index.retrieve_artist_id') @patch('index.check_project_code_mismatch') def test_create_project_if_none_exists( mock_check_project_code_mismatch, mock_retrieve_artist_id, mock_load_ddex_json, mock_graphql_execute, mock_check_project, context, s3_ddex, get_project_no_result, get_project_response ): """Test that a new project will be created if none found.""" mock_load_ddex_json.return_value = s3_ddex mock_return = get_project_no_result['data']['projectByProjectCode'] mock_check_project.return_value = mock_return mock_retrieve_artist_id.return_value = 2348776 payload = { 'data': { 'projectCode': 'FAKE project_code', 'name': 'FAKE name', 'artistId': 2348776, 'description': 'FAKE description', 'accountId': 123, 'subaccountId': 0 } } response = index.handler(context, None) mock_graphql_execute.assert_called_with( queries.CREATE_PROJECT, payload) assert response.get('project_id') @patch('index.check_for_project') @patch('index.graphql_gateway.execute') @patch('index.load_ddex_json') @patch('index.retrieve_artist_id') @patch('index.check_project_code_mismatch') def test_create_project_duplicate_code_exception( mock_check_project_code_mismatch, mock_retrieve_artist_id, mock_load_ddex_json, mock_graphql_execute, mock_check_project, context, s3_ddex, get_project_no_result, get_project_response ): """Test that we wrap a know error caused by a race condition.""" s3_ddex['project']['project_code'] = '1461605' mock_load_ddex_json.return_value = s3_ddex mock_return = get_project_no_result['data']['projectByProjectCode'] mock_check_project.return_value = mock_return mock_retrieve_artist_id.return_value = 2348776 duplicate_project_code_gql_response = [ { 'message': '400: BAD REQUEST', 'path': [ 'createProject', 0 ], 'extensions': { 'code': 'INTERNAL_SERVER_ERROR', 'serviceName': 'graphql-product', 'query': 'mutation{createProject(input:{}}){}}', # noqa 'variables': {}, 'response': { 'url': 'https://prod-ows-project-manager.theorchard.io/project', # noqa 'status': 400, 'statusText': 'BAD REQUEST', 'body': { 'code': 'validation_error', 'message': { 'project_code': { 'validator': 'used', 'validator_value': True, 'message': "Project code '1461605' already exists", # noqa 'deletions': 'N', 'existing_project_id': 4766607 } } } }, 'exception': { 'stacktrace': [ 'GraphQLError: 400: BAD REQUEST', ' at downstreamServiceError (/var/app/node_modules/@apollo/gateway/dist/executeQueryPlan.js:273:12)', # noqa ' at /var/app/node_modules/@apollo/gateway/dist/executeQueryPlan.js:181:65', # noqa ' at Array.map ()', ' at /var/app/node_modules/@apollo/gateway/dist/executeQueryPlan.js:181:52', # noqa ' at Generator.next ()', ' at fulfilled (/var/app/node_modules/@apollo/gateway/dist/executeQueryPlan.js:5:58)', # noqa ' at runMicrotasks ()', ' at processTicksAndRejections (internal/process/task_queues.js:97:5)' # noqa ] } } } ] graphql_error = graphql.GraphQLError(duplicate_project_code_gql_response) mock_graphql_execute.side_effect = graphql_error with pytest.raises(DuplicateProjectCodeException): index.handler(context, None) @patch('index.graphql_gateway.execute') @patch('index.load_ddex_json') @patch('index.check_project_code_mismatch') def test_update_project_if_found( mock_check_project_code_mismatch, mock_load_ddex_json, mock_graphql_execute, context, s3_ddex, get_project_response, update_project_success ): """Test that an existing project will be updated if found.""" index.update_project = MagicMock() index.update_project.return_value = update_project_success mock_check_project_code_mismatch.return_value = False mock_load_ddex_json.return_value = s3_ddex mock_graphql_execute.return_value = get_project_response index.handler(context, None) index.update_project.assert_called_once() @patch('index.graphql_gateway.execute') @patch('index.load_ddex_json') @patch('index.check_project_code_mismatch') def test_update_project_if_found_and_project_code_mismatch( mock_check_project_code_mismatch, mock_load_ddex_json, mock_graphql_execute, context, s3_ddex, get_project_response, update_project_success ): """Test that an existing project won't be updated if project mismatch.""" index.update_project = MagicMock() index.update_project.return_value = update_project_success mock_check_project_code_mismatch.return_value = True mock_load_ddex_json.return_value = s3_ddex mock_graphql_execute.return_value = get_project_response index.handler(context, None) index.update_project.assert_not_called() def test_participant_artist_id_found( s3_ddex, s3_extended_artist ): """Test that an existing artist_id will be returned if found.""" s3_ddex = S3Schema().load(s3_ddex) s3_ddex.project.artist = s3_extended_artist response = index.retrieve_artist_id(s3_ddex) assert response == 1 def test_participant_artist_id_not_found( s3_ddex, s3_extended_artist ): """Test that an error will be thrown if no artist_id found.""" s3_ddex = S3Schema().load(s3_ddex) s3_ddex.project.artist = s3_extended_artist s3_ddex.project.artist.name = 'no_match_expected' with pytest.raises(ArtistIdNotFoundException) as exception: index.retrieve_artist_id(s3_ddex) assert str( exception.value) == ( f'Artist id not found for name: {s3_ddex.project.artist.name}') @patch('index.graphql_gateway.execute') def test_check_project_code_mismatch_fail( mock_graphql_execute, context, s3_ddex): """Test check_project_code_mismatch fails on mismatch.""" context = StateMachineSchema().load(context) s3_ddex = S3Schema().load(s3_ddex) context.ddex_provider = ddex_providers.AWAL project_code = '1234567' s3_ddex.project.project_code = project_code upc = '886445895605' mock_graphql_execute.return_value = { 'data': { 'productByUpc': { 'project': { 'projectCode': '1259833' } } } } with pytest.raises(ProjectCodeMismatchException): index.check_project_code_mismatch(s3_ddex, context, upc) @patch('index.graphql_gateway.execute') def test_check_project_code_mismatch_success( mock_graphql_execute, context, s3_ddex): """Test check_project_code_mismatch does not fail on without a project.""" context = StateMachineSchema().load(context) s3_ddex = S3Schema().load(s3_ddex) project_code = '1234567' s3_ddex.project.project_code = project_code upc = '886445895605' mock_graphql_execute.return_value = { 'data': { 'productByUpc': None } } result = index.check_project_code_mismatch(s3_ddex, context, upc) assert not result @patch('index.graphql_gateway.execute') def test_check_project_code_remove_prefix( mock_graphql_execute, context, s3_ddex): """Test check_project_code_mismatch discards prefix.""" context = StateMachineSchema().load(context) s3_ddex = S3Schema().load(s3_ddex) project_code = '1234567' s3_ddex.project.project_code = project_code upc = '886445895605' mock_graphql_execute.return_value = { 'data': { 'productByUpc': { 'project': { 'projectCode': 'SONY:id:' + project_code } } } } index.check_project_code_mismatch(s3_ddex, context, upc) @patch('index.graphql_gateway.execute') def test_check_vendor_id_mismatch_fail( mock_graphql_execute, context, s3_ddex): """Test check_project_code_mismatch fails on vendor_id mismatch.""" context = StateMachineSchema().load(context) s3_ddex = S3Schema().load(s3_ddex) project_code = '1234567' s3_ddex.project.project_code = project_code upc = '886445895605' mock_graphql_execute.return_value = { 'data': { 'productByUpc': { 'vendorId': 456, 'project': { 'projectCode': project_code } } } } with pytest.raises(ProjectCodeMismatchException): index.check_project_code_mismatch(s3_ddex, context, upc) @pytest.mark.parametrize( 'ddex_provider', [ ddex_providers.SME, ddex_providers.SME_ANALYTICS_PROVIDER, ] ) @patch('index.graphql_gateway.execute') def test_check_project_code_mismatch_for_sme_provider( mock_graphql_execute, context, s3_ddex, ddex_provider): """Test check_project_code_mismatch doesn't fail for some providers.""" context = StateMachineSchema().load(context) s3_ddex = S3Schema().load(s3_ddex) context.ddex_provider = ddex_provider project_code = '1234567' s3_ddex.project.project_code = project_code upc = '886445895605' mock_graphql_execute.return_value = { 'data': { 'productByUpc': { 'project': { 'projectCode': '1259833' } } } } # This should not raise an exception for SME provider, but return False result = index.check_project_code_mismatch(s3_ddex, context, upc) assert result is True