import asyncio import pytest from app.adapters.delivery_providers.base import ProviderRequestError from app.schemas.order import OrderCreateRequest, OrderCreateResponse from app.services.aggregator import ( AggregatorService, InvalidOrderCreateRequestError, OrderCreationUnavailableError, ) class StubOrderAdapter: def __init__( self, *, response: OrderCreateResponse | None = None, error: Exception | None = None, ) -> None: self._response = response self._error = error self.calls: list[OrderCreateRequest] = [] async def register_order(self, request: OrderCreateRequest) -> OrderCreateResponse: self.calls.append(request) if self._error is not None: raise self._error if self._response is None: raise RuntimeError("Stub order adapter has no response configured.") return self._response def _make_order_request(**overrides: object) -> OrderCreateRequest: payload: dict[str, object] = { "type": 2, "tariff_code": 535, "comment": "Test order", "sender": { "name": "Petr Petrov", "email": "sender@example.com", "phones": [{"number": "+79009876543"}], }, "recipient": { "name": "Ivan Ivanov", "email": "ivan@example.com", "phones": [{"number": "+79001234567"}], }, "from_location": { "address": "Lenina 1", "city": "Moscow", "country_code": "RU", }, "to_location": { "address": "Pushkina 10", "city": "Novosibirsk", "country_code": "RU", }, "services": [{"code": "INSURANCE", "parameter": "1000"}], "packages": [ { "number": "1", "weight": 1000, "length": 20, "width": 15, "height": 10, "comment": "Package 1", } ], } payload.update(overrides) return OrderCreateRequest(**payload) def test_create_order_delegates_to_adapter_and_returns_created_order() -> None: request = _make_order_request() adapter = StubOrderAdapter( response=OrderCreateResponse(provider="cdek", order_uuid="order-uuid-1") ) service = AggregatorService(providers=[], order_adapter=adapter) result = asyncio.run(service.create_order(request)) assert result == OrderCreateResponse(provider="cdek", order_uuid="order-uuid-1") assert adapter.calls == [request] def test_create_order_maps_provider_request_errors_to_invalid_order_error() -> None: request = _make_order_request() adapter = StubOrderAdapter(error=ProviderRequestError("bad payload")) service = AggregatorService(providers=[], order_adapter=adapter) with pytest.raises(InvalidOrderCreateRequestError): asyncio.run(service.create_order(request)) assert adapter.calls == [request] def test_create_order_maps_transport_failures_to_unavailable_error() -> None: request = _make_order_request() adapter = StubOrderAdapter(error=RuntimeError("transport down")) service = AggregatorService(providers=[], order_adapter=adapter) with pytest.raises(OrderCreationUnavailableError): asyncio.run(service.create_order(request)) assert adapter.calls == [request] def test_create_order_without_configured_adapter_raises_unavailable_error() -> None: service = AggregatorService(providers=[]) with pytest.raises(OrderCreationUnavailableError): asyncio.run(service.create_order(_make_order_request()))