Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import uuid
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.api import router
|
||||
|
||||
|
||||
def make_client() -> TestClient:
|
||||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
def test_get_payment_requires_api_key() -> None:
|
||||
with make_client() as client:
|
||||
response = client.get(f"/api/v1/payments/{uuid.uuid4()}")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert response.json() == {"detail": "Invalid or missing API key"}
|
||||
|
||||
|
||||
def test_create_payment_requires_idempotency_key() -> None:
|
||||
with make_client() as client:
|
||||
response = client.post(
|
||||
"/api/v1/payments",
|
||||
headers={"X-API-Key": "change-me"},
|
||||
json={
|
||||
"amount": "100.00",
|
||||
"currency": "RUB",
|
||||
"description": "Test payment",
|
||||
"metadata": {},
|
||||
"webhook_url": "https://example.com/webhook",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
assert response.json()["detail"][0]["loc"] == ["header", "Idempotency-Key"]
|
||||
|
||||
|
||||
def test_create_payment_rejects_unsupported_currency() -> None:
|
||||
with make_client() as client:
|
||||
response = client.post(
|
||||
"/api/v1/payments",
|
||||
headers={
|
||||
"X-API-Key": "change-me",
|
||||
"Idempotency-Key": "test-key",
|
||||
},
|
||||
json={
|
||||
"amount": "100.00",
|
||||
"currency": "GBP",
|
||||
"description": "Test payment",
|
||||
"metadata": {},
|
||||
"webhook_url": "https://example.com/webhook",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
@@ -0,0 +1,53 @@
|
||||
import pytest
|
||||
|
||||
from app.processing import retry_async
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_retry_uses_exponential_delay_and_returns_success() -> None:
|
||||
calls = 0
|
||||
delays: list[float] = []
|
||||
|
||||
async def operation() -> str:
|
||||
nonlocal calls
|
||||
calls += 1
|
||||
if calls < 3:
|
||||
raise RuntimeError("temporary failure")
|
||||
return "processed"
|
||||
|
||||
async def record_sleep(delay: float) -> None:
|
||||
delays.append(delay)
|
||||
|
||||
result = await retry_async(
|
||||
operation,
|
||||
attempts=3,
|
||||
base_delay=1,
|
||||
sleep=record_sleep,
|
||||
)
|
||||
|
||||
assert result == "processed"
|
||||
assert calls == 3
|
||||
assert delays == [1, 2]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_retry_raises_last_error_after_three_attempts() -> None:
|
||||
calls = 0
|
||||
|
||||
async def operation() -> None:
|
||||
nonlocal calls
|
||||
calls += 1
|
||||
raise RuntimeError(f"failure {calls}")
|
||||
|
||||
async def no_sleep(_: float) -> None:
|
||||
pass
|
||||
|
||||
with pytest.raises(RuntimeError, match="failure 3"):
|
||||
await retry_async(
|
||||
operation,
|
||||
attempts=3,
|
||||
base_delay=1,
|
||||
sleep=no_sleep,
|
||||
)
|
||||
|
||||
assert calls == 3
|
||||
Reference in New Issue
Block a user