Добавлена обработка уведомлений через ручку
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import asyncio
|
||||
|
||||
import httpx
|
||||
|
||||
from app.controllers.v1.delivery import get_aggregator_service
|
||||
from app.main import create_app
|
||||
from app.schemas.payment import TBankPaymentNotification
|
||||
from app.services.aggregator import (
|
||||
InvalidTBankPaymentNotificationError,
|
||||
TBankPaymentNotificationProcessingError,
|
||||
)
|
||||
|
||||
|
||||
class StubAggregatorService:
|
||||
def __init__(self, *, response: str = "OK", error: Exception | None = None) -> None:
|
||||
self._response = response
|
||||
self._error = error
|
||||
self.calls: list[TBankPaymentNotification] = []
|
||||
|
||||
async def handle_tbank_payment_notification(
|
||||
self,
|
||||
notification: TBankPaymentNotification,
|
||||
) -> str:
|
||||
self.calls.append(notification)
|
||||
if self._error is not None:
|
||||
raise self._error
|
||||
return self._response
|
||||
|
||||
|
||||
def _install_service_override(app, service: StubAggregatorService) -> None:
|
||||
async def override_service() -> StubAggregatorService:
|
||||
return service
|
||||
|
||||
app.dependency_overrides[get_aggregator_service] = override_service
|
||||
|
||||
|
||||
def _valid_payload() -> dict[str, object]:
|
||||
return {
|
||||
"TerminalKey": "TestTerminal",
|
||||
"OrderId": "order-uuid-1",
|
||||
"Success": True,
|
||||
"Status": "CONFIRMED",
|
||||
"PaymentId": 8347568144,
|
||||
"ErrorCode": "0",
|
||||
"Amount": 125000,
|
||||
"Token": "signed-token",
|
||||
"Data": {"nested": "accepted by schema"},
|
||||
}
|
||||
|
||||
|
||||
def _post_notification(app, payload: dict[str, object]) -> httpx.Response:
|
||||
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/tbank/notifications",
|
||||
json=payload,
|
||||
)
|
||||
|
||||
return asyncio.run(run_request())
|
||||
|
||||
|
||||
def test_post_tbank_notification_returns_plain_text_ok_and_delegates_once() -> None:
|
||||
service = StubAggregatorService(response="OK")
|
||||
app = create_app()
|
||||
_install_service_override(app, service)
|
||||
|
||||
response = _post_notification(app, _valid_payload())
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.text == "OK"
|
||||
assert response.headers["content-type"].startswith("text/plain")
|
||||
assert service.calls == [TBankPaymentNotification(**_valid_payload())]
|
||||
|
||||
|
||||
def test_post_tbank_notification_maps_invalid_token_to_400() -> None:
|
||||
service = StubAggregatorService(
|
||||
error=InvalidTBankPaymentNotificationError("invalid token")
|
||||
)
|
||||
app = create_app()
|
||||
_install_service_override(app, service)
|
||||
|
||||
response = _post_notification(app, _valid_payload())
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json()["detail"]["code"] == "invalid_tbank_payment_notification"
|
||||
assert service.calls == [TBankPaymentNotification(**_valid_payload())]
|
||||
|
||||
|
||||
def test_post_tbank_notification_maps_processing_failure_to_503() -> None:
|
||||
service = StubAggregatorService(
|
||||
error=TBankPaymentNotificationProcessingError("temporary failure")
|
||||
)
|
||||
app = create_app()
|
||||
_install_service_override(app, service)
|
||||
|
||||
response = _post_notification(app, _valid_payload())
|
||||
|
||||
assert response.status_code == 503
|
||||
assert (
|
||||
response.json()["detail"]["code"]
|
||||
== "tbank_payment_notification_processing_unavailable"
|
||||
)
|
||||
assert service.calls == [TBankPaymentNotification(**_valid_payload())]
|
||||
|
||||
|
||||
def test_post_tbank_notification_rejects_invalid_payload_without_service_call() -> None:
|
||||
service = StubAggregatorService()
|
||||
app = create_app()
|
||||
_install_service_override(app, service)
|
||||
payload = _valid_payload()
|
||||
del payload["Token"]
|
||||
|
||||
response = _post_notification(app, payload)
|
||||
|
||||
assert response.status_code == 422
|
||||
assert service.calls == []
|
||||
Reference in New Issue
Block a user