from http import HTTPStatus from typing import Any, ContextManager import pytest from fastapi.testclient import TestClient from httpx import HTTPStatusError from pytest_mock import MockerFixture from syrupy.assertion import SnapshotAssertion from delivery_metadata.clients.ows_pricing.pricing import ( get_product_pricing, get_track_pricing, ) from delivery_metadata.exceptions import PricingDataNotFound _error_cases = [ pytest.param( HTTPStatus.NOT_FOUND, None, pytest.raises(PricingDataNotFound), id="404_raises_pricing_not_found", ), pytest.param( HTTPStatus.INTERNAL_SERVER_ERROR, None, pytest.raises(HTTPStatusError), id="500_raises_http_status_error", ), pytest.param( None, {}, pytest.raises(PricingDataNotFound), id="empty_data_raises_pricing_not_found", ), pytest.param( None, {"items": []}, pytest.raises(PricingDataNotFound), id="empty_items_raises_pricing_not_found", ), ] @pytest.mark.asyncio @pytest.mark.parametrize("status_code, json_data, expected_exception", _error_cases) async def test_get_product_pricing_error_cases( status_code: int | None, json_data: dict[str, Any] | None, expected_exception: ContextManager[Exception], mocker: MockerFixture, test_client: TestClient, ) -> None: response_mock = mocker.Mock() if status_code is not None: http_response_mock = mocker.Mock() http_response_mock.status_code = status_code response_mock.raise_for_status.side_effect = HTTPStatusError( str(status_code), request=mocker.Mock(), response=http_response_mock ) else: response_mock.json.return_value = json_data mocker.patch.object( test_client.app.state.ows_connector, # type: ignore[attr-defined] "get", return_value=response_mock, autospec=True, ) with expected_exception: await get_product_pricing(344235, 286) @pytest.mark.asyncio @pytest.mark.parametrize("status_code, json_data, expected_exception", _error_cases) async def test_get_track_pricing_error_cases( status_code: int | None, json_data: dict[str, Any] | None, expected_exception: ContextManager[Exception], mocker: MockerFixture, test_client: TestClient, ) -> None: response_mock = mocker.Mock() if status_code is not None: http_response_mock = mocker.Mock() http_response_mock.status_code = status_code response_mock.raise_for_status.side_effect = HTTPStatusError( str(status_code), request=mocker.Mock(), response=http_response_mock ) else: response_mock.json.return_value = json_data mocker.patch.object( test_client.app.state.ows_connector, # type: ignore[attr-defined] "get", return_value=response_mock, autospec=True, ) with expected_exception: await get_track_pricing(344235, 286) @pytest.mark.asyncio async def test_get_product_pricing( mocker: MockerFixture, test_client: TestClient, snapshot: SnapshotAssertion, ) -> None: response_mock = mocker.Mock() response_mock.json = mocker.Mock( return_value={ "items": [ { "territories": ["RU"], "price_code": "104", }, { "territories": ["CA"], "price_code": "8", "custom_currency_code": "CAD", "custom_price": "2.89", }, { "territories": ["GB", "US"], "price_code": "3", }, { "territories": ["FR"], "price_code": "8", "start_date": "2025-10-01", "end_date": "2025-12-31", }, { "territories": ["MX"], "price_code": "8", "custom_currency_code": "MXN", "custom_price": "39.45", }, ], } ) get_mock = mocker.patch.object( test_client.app.state.ows_connector, # type: ignore[attr-defined] "get", return_value=response_mock, autospec=True, ) result = await get_product_pricing(344235, 286) get_mock.assert_called_once_with( service_name="ows-pricing", path="/pricing_family/2/product/344235/store/286/pricing", ) response_mock.raise_for_status.assert_called_once() assert result == snapshot @pytest.mark.asyncio async def test_get_music_track_product_pricing( mocker: MockerFixture, test_client: TestClient, snapshot: SnapshotAssertion, ) -> None: response_mock = mocker.Mock() response_mock.json = mocker.Mock( return_value={ "items": [ { "territories": ["CA", "CZ", "PL"], "price_code": "8", "track_ids": [1234, 2345, 3456, 4567, 5678], "start_date": "2025-09-01", "end_date": "2025-11-31", }, { "territories": ["GB", "US"], "price_code": "3", "track_ids": [1234, 2345, 3456, 5678], }, { "territories": ["FR"], "price_code": "8", "track_ids": [1234, 2345, 3456, 4567, 5678], "custom_currency_code": "EUR", "custom_price": "1.99", "start_date": "2025-10-01", "end_date": "2025-12-31", }, { "territories": ["MX"], "price_code": "8", "track_ids": [1234, 2345, 3456, 4567, 5678], "start_date": "2025-10-01", "end_date": "2025-12-31", }, ], } ) get_mock = mocker.patch.object( test_client.app.state.ows_connector, # type: ignore[attr-defined] "get", return_value=response_mock, autospec=True, ) result = await get_track_pricing(344235, 286) get_mock.assert_called_once_with( service_name="ows-pricing", path="/pricing_family/3/product/344235/store/286/pricing", ) response_mock.raise_for_status.assert_called_once() assert result == snapshot @pytest.mark.asyncio async def test_get_video_track_product_pricing( mocker: MockerFixture, test_client: TestClient, snapshot: SnapshotAssertion, ) -> None: response_mock = mocker.Mock() response_mock.json = mocker.Mock( return_value={ "items": [ { "territories": ["CA", "CZ", "PL"], "price_code": "8", "track_ids": [2345, 3456, 4567, 5678], "start_date": "2025-09-01", "end_date": "2025-11-31", }, { "territories": ["GB", "US"], "price_code": "3", "track_ids": [1234, 2345, 3456, 5678], }, ], } ) get_mock = mocker.patch.object( test_client.app.state.ows_connector, # type: ignore[attr-defined] "get", return_value=response_mock, autospec=True, ) result = await get_track_pricing(344235, 286, True) get_mock.assert_called_once_with( service_name="ows-pricing", path="/pricing_family/5/product/344235/store/286/pricing", ) response_mock.raise_for_status.assert_called_once() assert result == snapshot