"""Test rules.""" from unittest.mock import MagicMock, patch from ddex_ingester_common.constants import \ validation_rule_error_codes as rule_error_codes from ddex_ingester_common.constants.catalog_ingestion import ( REJECT, SUCCESS, WARNING, ) import ddex_ingester_common.validation.rules as rules def test_require_product_name(validation_s3_context): """Test requires product name rule.""" output = rules.require_product_name(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_NAME, SUCCESS, None) def test_require_product_name_invalid(validation_s3_context): """Test requires product name rule.""" validation_s3_context['product']['product_name'] = '' output = rules.require_product_name(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_NAME, REJECT, 'Product Name is missing' ) def test_require_product_release_reference(validation_s3_context): """Test requires product release reference rule.""" output = rules.require_product_release_reference(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_RELEASE_REFERENCE, SUCCESS, None ) def test_require_product_release_reference_invalid(validation_s3_context): """Test requires product release reference rule.""" validation_s3_context['product']['release_reference'] = '' output = rules.require_product_release_reference(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_RELEASE_REFERENCE, REJECT, 'Product Release Reference is missing' ) def test_require_product_display_artist_name(validation_s3_context): """Test requires product display artist name rule.""" output = rules.require_product_display_artist_name(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_DISPLAY_ARTIST_NAME, SUCCESS, None ) def test_require_product_display_artist_name_invalid(validation_s3_context): """Test requires product display artist name rule.""" validation_s3_context['product']['display_artist_name'] = '' output = rules.require_product_display_artist_name(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_DISPLAY_ARTIST_NAME, REJECT, 'Product Display Artist Name is missing' ) def test_require_product_release_type(validation_s3_context): """Test requires product release type rule.""" output = rules.require_product_release_type(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_RELEASE_TYPE, SUCCESS, None ) def test_require_product_release_type_invalid(validation_s3_context): """Test requires product release type rule.""" validation_s3_context['product']['release_type'] = '' output = rules.require_product_release_type(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_RELEASE_TYPE, REJECT, 'Product Release Type is missing' ) def test_require_product_is_main_release_true(validation_s3_context): """Test requires product is main release rule.""" validation_s3_context['product']['is_main_release'] = True output = rules.require_product_is_main_release(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_IS_MAIN_RELEASE, SUCCESS, None ) def test_require_product_is_main_release_false(validation_s3_context): """Test requires product is main release rule.""" validation_s3_context['product']['is_main_release'] = False output = rules.require_product_is_main_release(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_IS_MAIN_RELEASE, SUCCESS, None ) def test_require_product_is_main_release_invalid(validation_s3_context): """Test requires product is main release rule.""" validation_s3_context['product']['is_main_release'] = None output = rules.require_product_is_main_release(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_IS_MAIN_RELEASE, REJECT, 'Product Main Release is missing' ) def test_require_product_upc(validation_s3_context): """Test requires product UPC rule.""" output = rules.require_product_upc(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_UPC, SUCCESS, None ) def test_require_product_upc_invalid(validation_s3_context): """Test requires product UPC rule.""" validation_s3_context['product']['upc'] = '' output = rules.require_product_upc(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT_UPC, REJECT, 'Product UPC is missing' ) def test_require_party_id_sme_party_id(validation_s3_context): """Test requires party id rule with SME party id.""" output = rules.require_party_id(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_PARTY_ID, SUCCESS, None) def test_require_party_id_awal_party_id(validation_s3_context): """Test requires party id rule with AWAL party id.""" validation_s3_context['party_id'] = 'PADPIDA20100409010' output = rules.require_party_id(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_PARTY_ID, SUCCESS, None) def test_require_party_id_empty_party_id(validation_s3_context): """Test requires party id rule with empty party id.""" party_id = '' validation_s3_context['party_id'] = party_id output = rules.require_party_id(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_PARTY_ID, REJECT, 'Party Id is missing' ) def test_require_party_id_unknown_party_id(validation_s3_context): """Test requires party id rule with an unknown party id.""" party_id = 'PADPIDA20100409019' validation_s3_context['party_id'] = 'PADPIDA20100409019' output = rules.require_party_id(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_PARTY_ID, REJECT, f'Invalid Party Id: {party_id}' ) def test_require_message_id(validation_s3_context): """Test requires message_id rule.""" output = rules.require_message_id(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_MESSAGE_ID, SUCCESS, None ) def test_require_message_id_invalid(validation_s3_context): """Test requires message id rule.""" validation_s3_context['message_id'] = '' output = rules.require_message_id(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_MESSAGE_ID, REJECT, 'Message Id is missing' ) def test_require_product(validation_s3_context): """Test requires product rule.""" output = rules.require_product(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT, SUCCESS, None ) def test_require_product_invalid(validation_s3_context): """Test requires product UPC rule.""" validation_s3_context['product'] = '' output = rules.require_product(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PRODUCT, REJECT, 'Product is missing' ) def test_require_valid_awal_genre_missing_genre( validation_s3_context, validation_genres): """Test require_valid_awal_genre rule.""" graphql_gateway = MagicMock() graphql_gateway.execute.return_value = validation_genres validation_s3_context['product']['genres'] = None result = rules.get_require_valid_awal_genre(graphql_gateway)( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_GENRE, REJECT, 'Genre is missing' ) def test_require_valid_awal_genre_pass( validation_s3_context, validation_genres): """Test require_valid_awal_genre rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute.return_value = validation_genres validation_s3_context['product']['genres'] = [ { 'genre': 'Blues', 'subgenre': 'Acoustic Blues' }, ] result = rules.get_require_valid_awal_genre(mock_graphql_gateway)( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_GENRE, SUCCESS, None) def test_require_valid_awal_genre_missing_subgenre( validation_s3_context, validation_genres): """Test require_valid_awal_genre rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute.return_value = validation_genres validation_s3_context['product']['genres'] = [ { 'genre': 'Blues', }, ] result = rules.get_require_valid_awal_genre(mock_graphql_gateway)( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_SUBGENRE, REJECT, 'Subgenre is missing' ) def test_require_valid_awal_genre_wrong_subgenre( validation_s3_context, validation_genres): """Test require_valid_awal_genre rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute.return_value = validation_genres validation_s3_context['product']['genres'] = [ { 'genre': 'Blues', 'subgenre': 'Death Metal' }, ] result = rules.get_require_valid_awal_genre(mock_graphql_gateway)( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_SUBGENRE, REJECT, 'Invalid subgenre: Death Metal for genre: Blues' ) def test_require_valid_awal_genre_wrong_genre( validation_s3_context, validation_genres): """Test require_valid_awal_genre rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute.return_value = validation_genres validation_s3_context['product']['genres'] = [ { 'genre': 'genre', 'subgenre': 'subgenre' }, ] result = rules.get_require_valid_awal_genre(mock_graphql_gateway)( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_GENRE, REJECT, 'Invalid genre: genre' ) @patch('ddex_ingester_common.validation.' 'rules.is_ccm_som_livre_grps_ddex_ingestion_enabled') def test_require_valid_sme_genre_missing_genre( mock_is_ccm_som_livre_grps_ddex_ingestion_enabled, validation_s3_context): """Test require_valid_sme_genre rule.""" mock_splitio_client = MagicMock() mock_is_ccm_som_livre_grps_ddex_ingestion_enabled.return_value = True result = rules.get_require_valid_sme_genre(mock_splitio_client, 'test')( validation_s3_context) validation_s3_context['product']['genres'] = None assert result == rules.RuleResult( rule_error_codes.MISSING_GENRE, REJECT, 'Genre is missing' ) @patch('ddex_ingester_common.validation.rules.' 'is_ccm_som_livre_grps_ddex_ingestion_enabled') def test_require_valid_sme_genre_pass( mock_is_ccm_som_livre_grps_ddex_ingestion_enabled, validation_s3_context): """Test require_valid_sme_genre rule.""" mock_splitio_client = MagicMock() mock_is_ccm_som_livre_grps_ddex_ingestion_enabled.return_value = True validation_s3_context['product']['genres'] = [ { 'genre': 'KWAITO-00' }, ] result = rules.get_require_valid_sme_genre(mock_splitio_client, 'test')( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_GENRE, SUCCESS, None) def test_require_valid_cline(validation_s3_context): """Test require_valid_cline.""" result = rules.require_valid_cline(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_CLINE, SUCCESS, None) def test_require_valid_cline_missing(validation_s3_context): """Test require_valid_cline missing.""" validation_s3_context['product']['c_line'] = None result = rules.require_valid_cline(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_CLINE, SUCCESS, None) def test_require_valid_cline_reject(validation_s3_context): """Test require_valid_cline reject.""" validation_s3_context['product']['c_line'] = 'product c-line' result = rules.require_valid_cline(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_CLINE, REJECT, 'Invalid product C-Line' ) def test_require_valid_pline(validation_s3_context): """Test require_valid_pline.""" result = rules.require_valid_pline(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_PLINE, SUCCESS, None) def test_require_valid_pline_missing(validation_s3_context): """Test require_valid_pline missing.""" validation_s3_context['tracks'][0]['p_line'] = None result = rules.require_valid_pline(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_PLINE, SUCCESS, None) def test_require_valid_pline_reject(validation_s3_context): """Test require_valid_pline.""" validation_s3_context['tracks'][0]['p_line'] = 'track p-line' result = rules.require_valid_pline(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_PLINE, REJECT, 'Invalid P-Line on track 1-1' ) def test_validate_product_localization_language_codes(validation_s3_context): """Test validate_product_localization_language_codes.""" result = rules.validate_product_localization_language_codes( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.DUPLICATE_LOCALIZED_PRODUCT_LANGUAGE_CODE) def test_validate_product_localization_language_codes_fail_chinese( validation_s3_context): """Test validate_product_localization_language_codes fail chinese.""" validation_s3_context['product']['localized_titles'] = [ { 'language_code': 'cmn-Hans', 'title': '标题', 'sub_title': '副标题', }, { 'language_code': 'en', 'title': 'title', 'subtitle': 'subtitle', }, ] result = rules.validate_product_localization_language_codes( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_CHINESE_SIMPLIFIED_OR_TRADITIONAL, WARNING, 'Both Simplified and Traditional Chinese must be present for localized' ' product title' ) def test_validate_product_localization_language_codes_latn_suffix( validation_s3_context): """Test validate_product_localization_language_codes fail chinese.""" validation_s3_context['product']['localized_titles'] = [ { 'language_code': 'he-Latn', 'title': 'hebrew language', 'sub_title': 'with latin script', }, { 'language_code': 'en', 'title': 'title', 'subtitle': 'subtitle', }, ] result = rules.validate_product_localization_language_codes( validation_s3_context) assert result == rules.RuleResult( 36, SUCCESS, None ) def test_validate_product_display_artist_language_codes(validation_s3_context): """Test validate_product_display_artist_language_codes.""" result = rules.validate_product_display_artist_language_codes( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.DUPLICATE_LOCALIZED_PRODUCT_ARTIST_LANGUAGE_CODE) def test_validate_product_display_artist_language_codes_fail( validation_s3_context): """Test validate_product_display_artist_language_codes.""" validation_s3_context['product']['display_artists'][1][ 'localized_names'].append( { 'name': 'english name 2', 'language_code': 'en' } ) result = rules.validate_product_display_artist_language_codes( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.DUPLICATE_LOCALIZED_PRODUCT_ARTIST_LANGUAGE_CODE, REJECT, 'Duplicate language code en not allowed for localization' ) def test_require_track_name(validation_s3_context): """Test requires track name rule.""" output = rules.require_track_name(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_NAME, SUCCESS, None ) def test_require_track_name_invalid(validation_s3_context): """Test requires track name rule.""" validation_s3_context['tracks'][0]['track_name'] = '' output = rules.require_track_name(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_NAME, REJECT, 'Track Name is missing' ) def test_require_track_isrc(validation_s3_context): """Test requires track ISRC rule.""" output = rules.require_track_isrc(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_ISRC, SUCCESS, None ) def test_require_track_isrc_invalid(validation_s3_context): """Test requires track ISRC rule.""" validation_s3_context['tracks'][0]['isrc'] = '' output = rules.require_track_isrc(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_ISRC, REJECT, 'Track ISRC is missing' ) def test_require_track_unique_isrc(validation_s3_context): """Test requires track unique ISRC rule.""" output = rules.require_track_unique_isrc(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.DUPLICATE_TRACK_ISRC, SUCCESS, None ) def test_require_track_unique_isrc_invalid(validation_s3_context): """Test requires track unique ISRC rule.""" validation_s3_context['tracks'][1]['isrc'] = \ validation_s3_context['tracks'][0]['isrc'] output = rules.require_track_unique_isrc(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.DUPLICATE_TRACK_ISRC, REJECT, 'Duplicate track ISRC QZCDB2000001' ) def test_require_track_sequence_number(validation_s3_context): """Test requires track sequence number rule.""" output = rules.require_track_sequence_number(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_SEQUENCE_NUMBER, SUCCESS, None ) def test_require_track_sequence_number_invalid(validation_s3_context): """Test requires track sequence number rule.""" validation_s3_context['tracks'][0]['sequence_number'] = '' output = rules.require_track_sequence_number(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_SEQUENCE_NUMBER, REJECT, 'Track Sequence Number is missing' ) def test_require_track_volume(validation_s3_context): """Test requires track volume rule.""" output = rules.require_track_volume(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_VOLUME, SUCCESS, None ) def test_require_track_volume_invalid(validation_s3_context): """Test requires track volume rule.""" validation_s3_context['tracks'][0]['volume'] = '' output = rules.require_track_volume(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_VOLUME, REJECT, 'Track Volume is missing' ) def test_require_track_release_type(validation_s3_context): """Test requires track release type rule.""" output = rules.require_track_release_type(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_RELEASE_TYPE, SUCCESS, None ) def test_require_track_release_type_invalid(validation_s3_context): """Test requires track release type rule.""" validation_s3_context['tracks'][0]['release_type'] = '' output = rules.require_track_release_type(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_RELEASE_TYPE, REJECT, 'Track Release Type is missing' ) def test_require_track_release_reference(validation_s3_context): """Test requires track release reference rule.""" output = rules.require_track_release_reference(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_RELEASE_REFERENCE, SUCCESS, None ) def test_require_track_release_reference_invalid(validation_s3_context): """Test requires track release reference rule.""" validation_s3_context['tracks'][0]['release_reference'] = '' output = rules.require_track_release_reference(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_RELEASE_REFERENCE, REJECT, 'Track Release Reference is missing' ) def test_require_track_resource_reference(validation_s3_context): """Test requires track resource reference rule.""" output = rules.require_track_resource_reference(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_RESOURCE_REFERENCE, SUCCESS, None ) def test_require_track_resource_reference_invalid(validation_s3_context): """Test requires track resource reference rule.""" validation_s3_context['tracks'][0]['resource_reference'] = '' output = rules.require_track_resource_reference(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_RESOURCE_REFERENCE, REJECT, 'Track Resource Reference is missing' ) def test_validate_track_localization_language_codes(validation_s3_context): """Test validate_track_localization_language_codes.""" result = rules.validate_track_localization_language_codes( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.DUPLICATE_LOCALIZED_TRACK_LANGUAGE_CODE) def test_validate_track_localization_language_codes_fail_chinese( validation_s3_context): """Test validate_track_localization_language_codes fail chinese.""" validation_s3_context['tracks'][1]['localized_titles'] = [ { 'language_code': 'cmn-Hans', 'title': '标题', 'sub_title': '副标题', }, { 'language_code': 'en', 'title': 'title', 'subtitle': 'subtitle', }, ] result = rules.validate_track_localization_language_codes( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_CHINESE_SIMPLIFIED_OR_TRADITIONAL, WARNING, 'Both Simplified and Traditional Chinese must be present for ' 'This track 2' ) def test_validate_track_display_artist_language_codes(validation_s3_context): """Test validate_track_display_artist_language_codes.""" result = rules.validate_track_display_artist_language_codes( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.DUPLICATE_LOCALIZED_TRACK_ARTIST_LANGUAGE_CODE) def test_validate_track_display_artist_language_codes_fail( validation_s3_context): """Test validate_track_display_artist_language_codes fails.""" validation_s3_context['tracks'][1]['display_artists'][1][ 'localized_names'].append( { 'name': 'english name 2', 'language_code': 'en' } ) result = rules.validate_track_display_artist_language_codes( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.DUPLICATE_LOCALIZED_TRACK_ARTIST_LANGUAGE_CODE, REJECT, 'Duplicate language code en not allowed for localization' ) def test_require_orchard_label(validation_s3_context): """Test require_orchard_label success.""" result = rules.require_orchard_label(validation_s3_context) assert result == rules.RuleResult(rule_error_codes.MISSING_ORCHARD_LABEL) def test_require_orchard_label_missing(validation_s3_context): """Test require_orchard_label failure.""" del validation_s3_context['product']['vendor_id'] result = rules.require_orchard_label(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_ORCHARD_LABEL, REJECT, 'Orchard Label ID is missing' ) def test_require_project_data(validation_s3_context): """Test require_project_from_ext_meta.""" result = rules.require_project_from_ext_meta(validation_s3_context) assert result == rules.RuleResult(rule_error_codes.MISSING_PROJECT_DATA) def test_require_project_data_missing(validation_s3_context): """Test require_project_from_ext_meta missing project section.""" validation_s3_context['project'] = None result = rules.require_project_from_ext_meta(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_PROJECT_DATA, REJECT, 'Project section is missing' ) def test_require_project_code_missing(validation_s3_context): """Test require_project_from_ext_meta missing project code.""" validation_s3_context['project']['project_code'] = None result = rules.require_project_from_ext_meta(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_PROJECT_CODE, REJECT, 'Project code is missing' ) def test_require_project_artist_missing(validation_s3_context): """Test require_project_from_ext_meta missing project code.""" validation_s3_context['project']['artist'] = None result = rules.require_project_from_ext_meta(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISSING_PROJECT_ARTIST, REJECT, 'Project artist is missing' ) def test_require_video_name(validation_s3_context): """Test requires video name rule.""" output = rules.require_video_name(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_NAME, SUCCESS, None ) def test_require_video_name_invalid(validation_s3_context): """Test requires video name rule.""" validation_s3_context['video']['video_name'] = '' output = rules.require_video_name(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_NAME, REJECT, 'Video Name is missing' ) def test_require_video_isrc(validation_s3_context): """Test requires video ISRC rule.""" output = rules.require_video_isrc(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_ISRC, SUCCESS, None ) def test_require_video_isrc_invalid(validation_s3_context): """Test requires video ISRC rule.""" validation_s3_context['video']['isrc'] = '' output = rules.require_video_isrc(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_ISRC, REJECT, 'Video ISRC is missing' ) def test_require_video_release_type(validation_s3_context): """Test requires video release type rule.""" output = rules.require_video_release_type(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_RELEASE_TYPE, SUCCESS, None ) def test_require_video_release_type_invalid(validation_s3_context): """Test requires video release type rule.""" validation_s3_context['video']['release_type'] = '' output = rules.require_video_release_type(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_RELEASE_TYPE, REJECT, 'Video Release Type is missing' ) def test_require_video_release_reference(validation_s3_context): """Test requires video release reference rule.""" output = rules.require_video_release_reference(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_RELEASE_REFERENCE, SUCCESS, None ) def test_require_video_release_reference_invalid(validation_s3_context): """Test requires video release reference rule.""" validation_s3_context['video']['release_reference'] = '' output = rules.require_video_release_reference(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_RELEASE_REFERENCE, REJECT, 'Video Release Reference is missing' ) def test_require_video_composer(validation_s3_context): """Test requires video composer rule - composer in display_artists.""" validation_s3_context['video']['display_artists'].append( {'name': 'Jane Doe', 'sequence_number': 3, 'roles': ['Composer']} ) output = rules.require_video_composer(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_COMPOSER, SUCCESS, None ) def test_require_video_composer_in_resource_contributors( validation_s3_context): """Test video composer rule - composer in resource_contributors.""" validation_s3_context['video']['resource_contributors'] = [ {'name': 'Jane Doe', 'sequence_number': 1, 'roles': ['Composer']} ] output = rules.require_video_composer(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_COMPOSER, SUCCESS, None ) def test_require_video_composer_missing(validation_s3_context): """Test requires video composer rule - composer absent.""" output = rules.require_video_composer(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_COMPOSER, REJECT, 'Video Composer is required' ) def test_require_video_composer_no_video(validation_s3_context): """Test requires video composer rule - no video in data.""" validation_s3_context['video'] = None output = rules.require_video_composer(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_COMPOSER, SUCCESS, None ) def test_validate_video_p_line(validation_s3_context): """Test validate video pline rule.""" output = rules.validate_video_p_line(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_PLINE_DATA, SUCCESS, None ) def test_validate_video_p_line_invalid(validation_s3_context): """Test validate video pline rule.""" validation_s3_context['video']['p_line'] = {'invalid': 'data'} output = rules.validate_video_p_line(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_PLINE_DATA, REJECT, 'Video PLine Text is missing' ) def test_validate_video_c_line(validation_s3_context): """Test validate video cline rule.""" output = rules.validate_video_c_line(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_CLINE_DATA, SUCCESS, None ) def test_validate_video_c_line_invalid(validation_s3_context): """Test validate video cline rule.""" validation_s3_context['video']['c_line'] = {'invalid': 'data'} output = rules.validate_video_c_line(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_VIDEO_CLINE_DATA, REJECT, 'Video CLine Text is missing' ) def test_validate_product_participants(validation_s3_context): """Test validate product participants rule.""" output = rules.validate_product_participants(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PARTICIPANT_DATA, SUCCESS, None ) def test_validate_product_participants_invalid(validation_s3_context): """Test validate product participants rule.""" validation_s3_context['product']['display_artists'].append( {'invalid': 'data'}) output = rules.validate_product_participants(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PARTICIPANT_DATA, REJECT, 'Product Participant Name is missing' ) def test_validate_track_participants(validation_s3_context): """Test validate track participants rule.""" output = rules.validate_track_participants(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PARTICIPANT_DATA, SUCCESS, None ) def test_validate_track_display_artists_empy(validation_s3_context): """Test validate track display_artists rule.""" validation_s3_context['tracks'][0]['display_artists'] = [] output = rules.validate_track_participants(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PARTICIPANT_DATA, REJECT, 'Display Artists is missing' ) def test_validate_track_display_artists_none(validation_s3_context): """Test validate track display_artists rule.""" validation_s3_context['tracks'][0]['display_artists'] = None output = rules.validate_track_participants(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PARTICIPANT_DATA, REJECT, 'Display Artists is missing' ) def test_validate_track_participants_invalid(validation_s3_context): """Test validate track participants rule.""" validation_s3_context['tracks'][0]['display_artists'].append( {'invalid': 'data'}) output = rules.validate_track_participants(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PARTICIPANT_DATA, REJECT, 'Track Participant Name is missing' ) def test_validate_video_participants(validation_s3_context): """Test validate video participants rule.""" output = rules.validate_video_participants(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PARTICIPANT_DATA, SUCCESS, None ) def test_validate_video_participants_invalid(validation_s3_context): """Test validate video participants rule.""" validation_s3_context['video']['display_artists'].append( {'invalid': 'data'}) output = rules.validate_video_participants(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_PARTICIPANT_DATA, REJECT, 'Video Participant Name is missing' ) def test_validate_product_localized_titles(validation_s3_context): """Test validate product localized titles rule.""" output = rules.validate_product_localized_titles(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_LOCALIZED_TITLE_DATA, SUCCESS, None ) def test_validate_product_localized_titles_invalid(validation_s3_context): """Test validate product localized titles rule.""" validation_s3_context['product']['localized_titles'].append( {'invalid': 'data'}) output = rules.validate_product_localized_titles(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_LOCALIZED_TITLE_DATA, REJECT, 'Product Localization Title is missing' ) def test_validate_track_localized_titles(validation_s3_context): """Test validate track localized titles rule.""" output = rules.validate_track_localized_titles(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_LOCALIZED_TITLE_DATA, SUCCESS, None ) def test_validate_track_localized_titles_invalid(validation_s3_context): """Test validate track localized titles rule.""" validation_s3_context['tracks'][0]['localized_titles'].append( {'invalid': 'data'}) output = rules.validate_track_localized_titles(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_LOCALIZED_TITLE_DATA, REJECT, 'Track Localization Title is missing' ) def test_validate_product_localized_artists(validation_s3_context): """Test validate product localized artists rule.""" output = rules.validate_product_localized_artists(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_LOCALIZED_ARTIST_DATA, SUCCESS, None ) def test_validate_product_localized_artists_invalid(validation_s3_context): """Test validate product localized artists rule.""" validation_s3_context['product']['display_artists'][0][ 'localized_names'].append( {'invalid': 'data'}) output = rules.validate_product_localized_artists(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_LOCALIZED_ARTIST_DATA, REJECT, 'Product Artist Localization Name is missing' ) def test_validate_track_localized_artists(validation_s3_context): """Test validate track localized artists rule.""" output = rules.validate_track_localized_artists(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_LOCALIZED_ARTIST_DATA, SUCCESS, None ) def test_validate_track_localized_artists_invalid(validation_s3_context): """Test validate track localized artists rule.""" validation_s3_context['tracks'][0]['display_artists'][0][ 'localized_names'].append( {'invalid': 'data'}) output = rules.validate_track_localized_artists(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_LOCALIZED_ARTIST_DATA, REJECT, 'Track Artist Localization Name is missing' ) def test_validate_deal_release_references(validation_s3_context): """Test validate deal release references rule.""" output = rules.validate_deal_release_references(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_RELEASE_REFERENCES, SUCCESS, None ) def test_validate_deal_release_references_invalid(validation_s3_context): """Test validate deal release references rule.""" validation_s3_context['deals'][0]['release_references'] = [] output = rules.validate_deal_release_references(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_RELEASE_REFERENCES, REJECT, 'Deal Release References are missing' ) def test_validate_deal_terms(validation_s3_context): """Test validate deal terms rule.""" output = rules.validate_deal_terms(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_TERMS, SUCCESS, None ) def test_validate_deal_terms_invalid(validation_s3_context): """Test validate deal terms rule.""" validation_s3_context['deals'][0]['deal_terms'] = [] output = rules.validate_deal_terms(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_TERMS, REJECT, "Deal Terms are missing for references: ['R1']" ) def test_validate_deal_term_commercial_model_types(validation_s3_context): """Test validate deal term commercial model types rule.""" output = rules.validate_deal_term_commercial_model_types( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_TERM_COMMERCIAL_MODEL_TYPES, SUCCESS, None ) def test_validate_deal_term_commercial_model_types_invalid( validation_s3_context): """Test validate deal term commercial model types rule.""" validation_s3_context['deals'][0]['deal_terms'][0][ 'commercial_model_types'] = [] output = rules.validate_deal_term_commercial_model_types( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_TERM_COMMERCIAL_MODEL_TYPES, REJECT, 'Deal Term Commercial Model Types are missing' ) def test_validate_deal_term_usage_type(validation_s3_context): """Test validate deal term usage type rule.""" output = rules.validate_deal_term_usage_type(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_TERM_USAGE_TYPE, SUCCESS, None ) def test_validate_deal_term_usage_type_invalid(validation_s3_context): """Test validate deal term usage type rule.""" validation_s3_context['deals'][0]['deal_terms'][0]['usage_type'] = [] output = rules.validate_deal_term_usage_type(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_TERM_USAGE_TYPE, REJECT, 'Deal Term Usage Type is missing' ) def test_validate_deal_term_territories(validation_s3_context): """Test validate deal term territories rule.""" output = rules.validate_deal_term_territories(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_TERM_TERRITORIES, SUCCESS, None ) def test_validate_deal_term_territories_invalid(validation_s3_context): """Test validate deal term territories rule.""" validation_s3_context['deals'][0]['deal_terms'][0]['territories'] = [] output = rules.validate_deal_term_territories(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_DEAL_TERM_TERRITORIES, REJECT, 'Deal Term Territories are missing' ) def test_validate_instant_gratification_references(validation_s3_context): """Test validate instant gratification references rule.""" output = rules.validate_instant_gratification_references( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_INSTANT_GRATIFICATION_REFERENCES, SUCCESS, None ) def test_validate_instant_gratification_references_invalid( validation_s3_context): """Test validate instant gratification references rule.""" validation_s3_context['deals'][0]['deal_terms'][0][ 'instant_gratifications'] = \ {'invalid': 'data'} output = rules.validate_instant_gratification_references( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_INSTANT_GRATIFICATION_REFERENCES, REJECT, 'Instant Gratification References are missing' ) def test_validate_update_indicator(validation_s3_context): """Test validate update indicator rule.""" output = rules.validate_update_indicator(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_UPDATE_INDICATOR, SUCCESS, None ) def test_validate_update_indicator_invalid(validation_s3_context): """Test validate update indicator rule.""" validation_s3_context['update_indicator'] = 'Not valid' output = rules.validate_update_indicator(validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_UPDATE_INDICATOR, REJECT, 'Invalid value for update indicator' ) def test_validate_product_price_type( validation_s3_context, validation_pricing_family_response): """Test validate product album price type rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute \ .return_value = validation_pricing_family_response validation_s3_context['deals'][0]['deal_terms'][0]['price_type'] = '25' output = rules.get_validate_product_price_type(mock_graphql_gateway)( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_PRODUCT_PRICE_TYPE, SUCCESS, None ) def test_validate_product_price_type_invalid_1( validation_s3_context, validation_pricing_family_response): """Test validate product album price type rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute \ .return_value = validation_pricing_family_response validation_s3_context['deals'][0]['deal_terms'][0][ 'price_type'] = 'Not valid' output = rules.get_validate_product_price_type(mock_graphql_gateway)( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_PRODUCT_PRICE_TYPE, REJECT, 'Product price type "Not valid" is not an integer' ) def test_validate_product_price_type_invalid_2( validation_s3_context, validation_pricing_family_response): """Test validate product album price type rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute \ .return_value = validation_pricing_family_response validation_s3_context['deals'][0]['deal_terms'][0]['price_type'] = '1' output = rules.get_validate_product_price_type(mock_graphql_gateway)( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_PRODUCT_PRICE_TYPE, REJECT, 'Product price type "1" is not valid' ) def test_validate_product_price_type_null( validation_s3_context, validation_pricing_family_response): """Test validate product album price type rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute \ .return_value = validation_pricing_family_response validation_s3_context['deals'][0]['deal_terms'][0]['price_type'] = None output = rules.get_validate_product_price_type(mock_graphql_gateway)( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_PRODUCT_PRICE_TYPE, SUCCESS, None ) def test_validate_track_price_type( validation_s3_context, validation_pricing_family_response): """Test validate product track price type rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute \ .return_value = validation_pricing_family_response validation_s3_context['deals'][0]['deal_terms'][0]['price_type'] = '25' output = rules.get_validate_track_price_type(mock_graphql_gateway)( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_TRACK_PRICE_TYPE, SUCCESS, None ) def test_validate_track_price_type_invalid_1( validation_s3_context, validation_pricing_family_response): """Test validate product track price type rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute \ .return_value = validation_pricing_family_response validation_s3_context['deals'][0]['deal_terms'][0][ 'price_type'] = 'Not Valid' output = rules.get_validate_track_price_type(mock_graphql_gateway)( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_TRACK_PRICE_TYPE, REJECT, 'On track QZCDB2000001 price type "Not Valid" is not an integer' ) def test_validate_track_price_type_invalid_2( validation_s3_context, validation_pricing_family_response): """Test validate product track price type rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute \ .return_value = validation_pricing_family_response validation_s3_context['deals'][0]['deal_terms'][0]['price_type'] = '1' output = rules.get_validate_track_price_type(mock_graphql_gateway)( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_TRACK_PRICE_TYPE, REJECT, 'On track QZCDB2000001 price type "1" is not valid' ) def test_validate_track_price_type_null( validation_s3_context, validation_pricing_family_response): """Test validate product track price type rule.""" mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute \ .return_value = validation_pricing_family_response validation_s3_context['deals'][0]['deal_terms'][0]['price_type'] = None output = rules.get_validate_track_price_type(mock_graphql_gateway)( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.INVALID_TRACK_PRICE_TYPE, SUCCESS, None ) def test_mismatched_vendor_id( validation_s3_context): """Test require_target_vendor_subaccount_matches_existing_product.""" mock_graphql_gateway = MagicMock() validation_s3_context['product']['vendor_id'] = 100 validation_s3_context['product']['subaccount_id'] = None mock_graphql_gateway.execute.return_value = { 'data': { 'productByUpc': { 'vendorId': 123, 'subaccountId': None } } } result = \ rules.get_require_target_vendor_subaccount_matches_existing_product( mock_graphql_gateway)( validation_s3_context) expected_msg = ( 'Product 231232563123 exists in the Orchard but under a different' ' vendor or subaccount than what the Switchboard deal is targeting.' ' Switchboard Vendor ID: 100, Orchard Vendor ID: 123, Switchboard' ' Subaccount ID: None, Orchard Subaccount ID: None') assert result == rules.RuleResult( rule_error_codes.MISMATCHING_VENDOR_OR_SUBACCOUNT, REJECT, expected_msg) def test_mismatched_subaccount_id( validation_s3_context): """Test require_target_vendor_subaccount_matches_existing_product.""" mock_graphql_gateway = MagicMock() validation_s3_context['product']['vendor_id'] = 123 validation_s3_context['product']['subaccount_id'] = 999 mock_graphql_gateway.execute.return_value = { 'data': { 'productByUpc': { 'vendorId': 123, 'subaccountId': None } } } result = \ rules.get_require_target_vendor_subaccount_matches_existing_product( mock_graphql_gateway)( validation_s3_context) expected_msg = ( 'Product 231232563123 exists in the Orchard but under a different' ' vendor or subaccount than what the Switchboard deal is targeting.' ' Switchboard Vendor ID: 123, Orchard Vendor ID: 123, Switchboard' ' Subaccount ID: 999, Orchard Subaccount ID: None') assert result == rules.RuleResult( rule_error_codes.MISMATCHING_VENDOR_OR_SUBACCOUNT, REJECT, expected_msg) def test_matching_account_ids( validation_s3_context): """Test require_target_vendor_subaccount_matches_existing_product.""" mock_graphql_gateway = MagicMock() validation_s3_context['product']['vendor_id'] = 123 validation_s3_context['product']['subaccount_id'] = 1000 mock_graphql_gateway.execute.return_value = { 'data': { 'productByUpc': { 'vendorId': 123, 'subaccountId': 1000 } } } result = \ rules.get_require_target_vendor_subaccount_matches_existing_product( mock_graphql_gateway)( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISMATCHING_VENDOR_OR_SUBACCOUNT, SUCCESS) def test_warn_on_format_mismatch_failure(validation_s3_context): """Test warn_on_format_mismatch.""" validation_s3_context['product']['release_type'] = 'Album' mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute.return_value = { 'data': { 'productByUpc': { 'format': 'EP', } } } expected_msg = ( 'Formats mismatch between incoming DDEX and existing Orchard Product. ' 'Orchard format: EP / DDEX format: Full Length') result = rules.get_warn_on_format_mismatch(mock_graphql_gateway)( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISMATCHING_FORMAT, WARNING, expected_msg ) def test_warn_on_format_mismatch_success(validation_s3_context): """Test warn_on_format_mismatch.""" validation_s3_context['product']['release_type'] = 'Album' mock_graphql_gateway = MagicMock() mock_graphql_gateway.execute.return_value = { 'data': { 'productByUpc': { 'format': 'Full Length', } } } result = rules.get_warn_on_format_mismatch(mock_graphql_gateway)( validation_s3_context) assert result == rules.RuleResult( rule_error_codes.MISMATCHING_FORMAT, SUCCESS) def test_validate_roles_failure(validation_s3_context): """Test validate_roles.""" result = rules.validate_roles(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_ROLE, WARNING, 'Invalid role Invalid on video artist Kelly Clarkson' ) def test_validate_roles_success(validation_s3_context): """Test validate_roles.""" validation_s3_context['video'] = None result = rules.validate_roles(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_ROLE, SUCCESS) def test_validate_awal_not_for_distribution_failure(validation_s3_context): """Test validate_awal_not_for_distribution.""" validation_s3_context['product']['not_for_distribution'] = 'Invalid' result = rules.validate_awal_not_for_distribution(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_NOT_FOR_DISTRIBUTION, REJECT, "Invalid Not For Distribution 'Invalid' for AWAL" ) def test_validate_awal_not_for_distribution_success(validation_s3_context): """Test validate_awal_not_for_distribution.""" validation_s3_context['product']['not_for_distribution'] = 'N' result = rules.validate_awal_not_for_distribution(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_NOT_FOR_DISTRIBUTION, SUCCESS) def test_validate_awal_not_for_distribution_null(validation_s3_context): """Test validate_awal_not_for_distribution.""" validation_s3_context['product']['not_for_distribution'] = None result = rules.validate_awal_not_for_distribution(validation_s3_context) assert result == rules.RuleResult( rule_error_codes.INVALID_NOT_FOR_DISTRIBUTION, SUCCESS) def test_validate_sme_analytics_not_confidential_true(validation_s3_context): """Test sme analytics data not confidential rule.""" validation_s3_context['product']['is_confidential'] = True output = rules.validate_sme_analytics_not_confidential( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.DATA_IS_CONFIDENTIAL, REJECT, 'SME Analytics Data is confidential' ) def test_validate_sme_analytics_not_confidential_false(validation_s3_context): """Test sme analytics data not confidential rule.""" validation_s3_context['product']['is_confidential'] = False output = rules.validate_sme_analytics_not_confidential( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.DATA_IS_CONFIDENTIAL, SUCCESS, ) def test_validate_sme_analytics_tracks_original_release_date_null( validation_s3_context): """Test sme analytics tracks original release date null rule.""" output = \ rules.validate_sme_analytics_tracks_original_release_date_not_null( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_ORIGINAL_RELEASE_DATE, REJECT, 'SME Analytics track is missing original_release_date', ) def test_validate_sme_analytics_tracks_original_release_date_not_null( validation_s3_context): """Test sme analytics tracks original release date not null rule.""" for track in validation_s3_context['tracks']: track['original_release_date'] = '2025-01-01' output = \ rules.validate_sme_analytics_tracks_original_release_date_not_null( validation_s3_context) assert output == rules.RuleResult( rule_error_codes.MISSING_TRACK_ORIGINAL_RELEASE_DATE, SUCCESS )