from typing import Any, Callable from unittest.mock import MagicMock, call, patch import freezegun import pytest from fastapi import Response from pytest_mock import MockerFixture from delivery_metadata.constants import ( DEFAULT_FORMAT, DeliveryType, MetadataFormatVersion, StoreIds, TrackTypes, ) from delivery_metadata.logic import delivery_metadata as delivery_metadata_logic from delivery_metadata.logic.delivery_metadata import ( get_formatter_class, store_delivery_format_version_to_metadata_formatter, ) from delivery_metadata.logic.metadata_formatters.ddex.ddex_ern_4_3.formatter_audio import ( DdexErn43FormatterAudio, ) from delivery_metadata.logic.metadata_formatters.ddex.ddex_ern_4_3.spotify.spotify_formatter_audio import ( SpotifyDdexErn43FormatterAudio, ) from delivery_metadata.models.delivery_rights import ( DeliveryRights, ) from delivery_metadata.models.schemas import DeliveryMetadata, ProductBundle from tests.unit.conftest import ( get_delivery_metadata_mock_by_store, get_store_mock, update_mock_object, ) @pytest.mark.parametrize( ( "delivery_format_version", "expected_get_delivery_metadata_calls", "expected_formatter_class", "store_id", ), [ ( MetadataFormatVersion.DDEX_ERN_4_3, [ call( upc=75679660923, store_id=StoreIds.SPOTIFY, delivery_type=DeliveryType.COMPLETE_ALBUM, ), ], SpotifyDdexErn43FormatterAudio, StoreIds.SPOTIFY, ), ( MetadataFormatVersion.DDEX_ERN_4_3, [ call( upc=75679660923, store_id=StoreIds.NO_STORE, delivery_type=DeliveryType.COMPLETE_ALBUM, ), ], DdexErn43FormatterAudio, 0, ), ], ) @freezegun.freeze_time("2021-08-01 23:59:01") @pytest.mark.asyncio async def test_generate( delivery_format_version: MetadataFormatVersion, audio_delivery_rights_mock_no_pricing: DeliveryRights, expected_get_delivery_metadata_calls: list[Any], expected_formatter_class: Callable[..., DdexErn43FormatterAudio], store_id: int, mocker: MockerFixture, ) -> None: store = get_store_mock(store_id, [TrackTypes.MUSIC]) delivery_metadata_mock = get_delivery_metadata_mock_by_store( store, [TrackTypes.MUSIC] ) get_delivery_metadata_mock = mocker.patch( "delivery_metadata.models.delivery_metadata.get_delivery_metadata", return_value=delivery_metadata_mock, ) get_delivery_rights_mock = mocker.patch( "delivery_metadata.logic.delivery_metadata.get_delivery_rights", return_value=audio_delivery_rights_mock_no_pricing, ) result: Response = await delivery_metadata_logic.generate( upc=75679660923, store_id=store_id, delivery_type=DeliveryType.COMPLETE_ALBUM, delivery_format_version=delivery_format_version, ) assert get_delivery_metadata_mock.mock_calls == expected_get_delivery_metadata_calls assert get_delivery_rights_mock.mock_calls == [call(delivery_metadata_mock)] expected_formatter = expected_formatter_class( delivery_metadata_mock, audio_delivery_rights_mock_no_pricing ) expected_response = Response( content=expected_formatter.format(), media_type=expected_formatter.media_type, ) assert result.body == expected_response.body assert result.media_type == expected_response.media_type @pytest.mark.parametrize( "metadata_format_version", store_delivery_format_version_to_metadata_formatter.keys(), ) def test_all_formatters_succeed_with_same_input( delivery_metadata_mock: DeliveryMetadata, metadata_format_version: MetadataFormatVersion, audio_delivery_rights_mock_no_pricing: DeliveryRights, ) -> None: formatter = get_formatter_class( metadata_format_version, type(delivery_metadata_mock.product), DEFAULT_FORMAT ) assert formatter( delivery_metadata_mock, audio_delivery_rights_mock_no_pricing ).format() @pytest.mark.parametrize( "metadata_format_version", store_delivery_format_version_to_metadata_formatter.keys(), ) def test_all_formatters_succeed_with_same_input_metadata_update( delivery_metadata_mock: DeliveryMetadata, metadata_format_version: MetadataFormatVersion, audio_delivery_rights_mock_no_pricing: DeliveryRights, ) -> None: formatter = get_formatter_class( metadata_format_version, type(delivery_metadata_mock.product), DEFAULT_FORMAT ) meta_update_mock = update_mock_object( delivery_metadata_mock, DeliveryMetadata, { "delivery.delivery_type": DeliveryType.METADATA_UPDATE, }, ) assert formatter(meta_update_mock, audio_delivery_rights_mock_no_pricing).format() @pytest.mark.parametrize( "metadata_format_version", store_delivery_format_version_to_metadata_formatter.keys(), ) def test_all_formatters_succeed_with_same_input_takedown( delivery_metadata_mock: DeliveryMetadata, metadata_format_version: MetadataFormatVersion, audio_delivery_rights_mock_no_pricing: DeliveryRights, ) -> None: formatter = get_formatter_class( metadata_format_version, type(delivery_metadata_mock.product), DEFAULT_FORMAT ) takedown_mock = update_mock_object( delivery_metadata_mock, DeliveryMetadata, { "delivery.delivery_type": DeliveryType.METADATA_UPDATE, "delivery.allowed_territories": [], }, ) assert formatter(takedown_mock, audio_delivery_rights_mock_no_pricing).format() @pytest.mark.parametrize( "metadata_format_version", store_delivery_format_version_to_metadata_formatter.keys(), ) def test_all_formatters_succeed_with_same_input_no_distribution_rights( delivery_metadata_mock: DeliveryMetadata, metadata_format_version: MetadataFormatVersion, audio_delivery_rights_mock_no_pricing: DeliveryRights, ) -> None: formatter = get_formatter_class( metadata_format_version, type(delivery_metadata_mock.product), DEFAULT_FORMAT ) takedown_mock = update_mock_object( delivery_metadata_mock, DeliveryMetadata, { "delivery.delivery_type": DeliveryType.METADATA_UPDATE, "product.distribution_rights": set(), }, ) assert formatter(takedown_mock, audio_delivery_rights_mock_no_pricing).format() def test_get_formatter_class_not_implemented() -> None: with pytest.raises(NotImplementedError) as exc: get_formatter_class( MetadataFormatVersion.DDEX_ERN_4_3, ProductBundle, DEFAULT_FORMAT ) assert ( str(exc.value) == "Format ddex_ern for version 4.3 for ProductBundle not implemented" ) @patch("delivery_metadata.logic.delivery_metadata.MetadataFormatVersion") def test_get_formatter_format_version_not_implemented( metadata_format_version_mock: MagicMock = MagicMock(), ) -> None: metadata_format_version_mock.format.value = "new format" metadata_format_version_mock.version = "new version" with pytest.raises(NotImplementedError) as exc: get_formatter_class(metadata_format_version_mock, ProductBundle, DEFAULT_FORMAT) assert str(exc.value) == "Format new format for version new version not implemented" @pytest.mark.asyncio @patch("delivery_metadata.logic.delivery_metadata.MetadataFormatVersion") async def test_generate_format_not_implemented( metadata_format_version_mock: MagicMock = MagicMock(name="value"), ) -> None: metadata_format_version_mock.value = "NEW_FORMAT_VERSION" with pytest.raises(NotImplementedError) as exc: await delivery_metadata_logic.generate( upc=75679660923, store_id=StoreIds.NO_STORE, delivery_type=DeliveryType.COMPLETE_ALBUM, delivery_format_version=metadata_format_version_mock, ) assert str(exc.value) == "Format NEW_FORMAT_VERSION not implemented"