018 add parcel type
This commit is contained in:
@@ -7,9 +7,10 @@ import pytest
|
||||
from app.controllers.v1 import delivery as delivery_controller
|
||||
from app.controllers.v1.delivery import get_aggregator_service
|
||||
from app.main import create_app
|
||||
from app.schemas.request import DeliveryEntity, DeliveryRequest
|
||||
from app.schemas.request import DeliveryEntity, DeliveryRequest, ParcelType
|
||||
from app.schemas.response import DeliveryPrice
|
||||
from app.services.aggregator import (
|
||||
AggregatorService,
|
||||
AggregatorServiceError,
|
||||
InvalidDeliveryRequestError,
|
||||
)
|
||||
@@ -28,6 +29,18 @@ class StubAggregatorService:
|
||||
return self._response
|
||||
|
||||
|
||||
class StubPriceProvider:
|
||||
def __init__(self, response: list[DeliveryPrice]) -> None:
|
||||
self.name = "stub-provider"
|
||||
self.cache_ttl_seconds = 900
|
||||
self._response = response
|
||||
self.calls: list[DeliveryRequest] = []
|
||||
|
||||
async def get_prices(self, request: DeliveryRequest) -> list[DeliveryPrice]:
|
||||
self.calls.append(request)
|
||||
return self._response
|
||||
|
||||
|
||||
def _install_service_override(app, service: StubAggregatorService) -> None:
|
||||
async def override_service() -> StubAggregatorService:
|
||||
return service
|
||||
@@ -47,6 +60,22 @@ def _valid_payload() -> dict[str, object]:
|
||||
}
|
||||
|
||||
|
||||
def _make_price(
|
||||
*,
|
||||
service_name: str,
|
||||
price: str,
|
||||
provider: str = "cdek",
|
||||
) -> DeliveryPrice:
|
||||
return DeliveryPrice(
|
||||
provider=provider,
|
||||
service_name=service_name,
|
||||
price=Decimal(price),
|
||||
currency="RUB",
|
||||
delivery_days_min=1,
|
||||
delivery_days_max=3,
|
||||
)
|
||||
|
||||
|
||||
def test_post_delivery_price_uses_registered_provider_in_default_dependency(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
@@ -210,6 +239,7 @@ def test_post_delivery_price_returns_prices_and_delegates_to_service() -> None:
|
||||
length_cm=30.0,
|
||||
width_cm=20.0,
|
||||
height_cm=10.0,
|
||||
parcel_type=None,
|
||||
)
|
||||
|
||||
|
||||
@@ -235,6 +265,72 @@ def test_post_delivery_price_accepts_optional_country_code() -> None:
|
||||
assert service.calls[0].country_code == "kz"
|
||||
|
||||
|
||||
def test_post_delivery_price_accepts_optional_parcel_type() -> None:
|
||||
service = StubAggregatorService(response=[])
|
||||
app = create_app()
|
||||
_install_service_override(app, service)
|
||||
payload = _valid_payload()
|
||||
payload["parcel_type"] = "doc"
|
||||
|
||||
async def run_request() -> httpx.Response:
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport,
|
||||
base_url="http://testserver",
|
||||
) as client:
|
||||
return await client.post("/api/v1/delivery/price", json=payload)
|
||||
|
||||
response = asyncio.run(run_request())
|
||||
|
||||
assert response.status_code == 200
|
||||
assert len(service.calls) == 1
|
||||
assert service.calls[0].parcel_type == ParcelType.DOC
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("parcel_type", "expected_service_names"),
|
||||
[
|
||||
("doc", ["Срочный документ", "DOCUMENT EXPRESS"]),
|
||||
("parcel", ["Parcel locker"]),
|
||||
(None, ["Parcel locker", "Срочный документ", "DOCUMENT EXPRESS"]),
|
||||
],
|
||||
)
|
||||
def test_post_delivery_price_filters_response_by_optional_parcel_type(
|
||||
parcel_type: str | None,
|
||||
expected_service_names: list[str],
|
||||
) -> None:
|
||||
provider = StubPriceProvider(
|
||||
response=[
|
||||
_make_price(service_name="Parcel locker", price="90.00"),
|
||||
_make_price(service_name="Срочный документ", price="150.00"),
|
||||
_make_price(service_name="DOCUMENT EXPRESS", price="200.00"),
|
||||
]
|
||||
)
|
||||
service = AggregatorService(providers=[provider])
|
||||
app = create_app()
|
||||
|
||||
async def override_service() -> AggregatorService:
|
||||
return service
|
||||
|
||||
app.dependency_overrides[get_aggregator_service] = override_service
|
||||
payload = _valid_payload()
|
||||
if parcel_type is not None:
|
||||
payload["parcel_type"] = parcel_type
|
||||
|
||||
async def run_request() -> httpx.Response:
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport,
|
||||
base_url="http://testserver",
|
||||
) as client:
|
||||
return await client.post("/api/v1/delivery/price", json=payload)
|
||||
|
||||
response = asyncio.run(run_request())
|
||||
|
||||
assert response.status_code == 200
|
||||
assert [item["service_name"] for item in response.json()] == expected_service_names
|
||||
|
||||
|
||||
def test_post_delivery_price_rejects_invalid_payload() -> None:
|
||||
service = StubAggregatorService(response=[])
|
||||
app = create_app()
|
||||
@@ -256,6 +352,28 @@ def test_post_delivery_price_rejects_invalid_payload() -> None:
|
||||
assert service.calls == []
|
||||
|
||||
|
||||
def test_post_delivery_price_rejects_invalid_parcel_type() -> None:
|
||||
service = StubAggregatorService(response=[])
|
||||
app = create_app()
|
||||
_install_service_override(app, service)
|
||||
invalid_payload = _valid_payload()
|
||||
invalid_payload["parcel_type"] = "letters"
|
||||
|
||||
async def run_request() -> httpx.Response:
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport,
|
||||
base_url="http://testserver",
|
||||
) as client:
|
||||
return await client.post("/api/v1/delivery/price", json=invalid_payload)
|
||||
|
||||
response = asyncio.run(run_request())
|
||||
|
||||
assert response.status_code == 422
|
||||
assert response.json()["detail"][0]["loc"] == ["body", "parcel_type"]
|
||||
assert service.calls == []
|
||||
|
||||
|
||||
def test_post_delivery_price_maps_service_exception_to_503() -> None:
|
||||
service = StubAggregatorService(
|
||||
response=[],
|
||||
|
||||
Reference in New Issue
Block a user