Files
meida_backend/tests/integration/test_vertical_slice.py
T
xsl 93b88db2f5 test: unit suite for the gateway invariants plus an integration slice
Covers routing, failover, the circuit breaker, structured-output retries, the
cache-prefix validator, cost computation including cached-token pricing, the
daily budget breaker, the quota protocol, the task state machine and log
redaction. HTTP is mocked -- no unit test spends money. The integration test
runs the real slice against PostgreSQL and Redis with a faked provider.
2026-08-14 00:26:39 +08:00

103 lines
3.2 KiB
Python
Executable File

"""End-to-end vertical slice against real PostgreSQL + Redis.
Run with ``make up && make migrate`` first, or let ``scripts/smoke.sh`` do it.
Skipped automatically when the infrastructure is not reachable, so ``make test``
stays fast and hermetic.
The LLM provider is faked here — ``scripts/smoke.sh`` is the one that proves the
real DeepSeek path.
"""
from __future__ import annotations
import os
import uuid
from decimal import Decimal
from typing import Any
import pytest
pytestmark = pytest.mark.integration
def _infra_available() -> bool:
return bool(os.getenv("MEIDA_RUN_INTEGRATION"))
pytestmark = [
pytest.mark.integration,
pytest.mark.skipif(
not _infra_available(),
reason="set MEIDA_RUN_INTEGRATION=1 with PostgreSQL and Redis running",
),
]
@pytest.fixture
async def client() -> Any:
import httpx
from apps.api.main import create_app
from packages.llm.types import ProviderResponse, Usage
from packages.shared.config import get_settings
app = create_app(get_settings())
class FakeProvider:
name = "deepseek"
default_model = "deepseek-v4-flash"
async def complete(self, request: Any) -> ProviderResponse:
return ProviderResponse(
text="建议白衬衫配西裤。",
model="deepseek-v4-flash",
usage=Usage(tokens_in=800, tokens_out=120, tokens_cached=600),
)
async def aclose(self) -> None:
return None
transport = httpx.ASGITransport(app=app)
async with (
httpx.AsyncClient(transport=transport, base_url="http://test") as http,
app.router.lifespan_context(app),
):
app.state.llm_gateway._providers["deepseek"] = FakeProvider()
yield http
async def test_chat_slice_reserves_commits_and_records_cost(client: Any) -> None:
token_resp = await client.post(
"/api/v1/auth/dev-token", json={"device_key": f"it-{uuid.uuid4().hex[:8]}"}
)
assert token_resp.json()["code"] == 0
headers = {"Authorization": f"Bearer {token_resp.json()['data']['access_token']}"}
before = (await client.get("/api/v1/quota", headers=headers)).json()["data"]
chat = await client.post("/api/v1/agent/chat", json={"message": "面试穿什么"}, headers=headers)
body = chat.json()
assert body["code"] == 0
assert body["data"]["reply"]
assert body["data"]["prompt_version"] == "v1"
assert Decimal(body["data"]["usage"]["cost_cents"]) > 0
after = (await client.get("/api/v1/quota", headers=headers)).json()["data"]
assert after["used"] == before["used"] + 1
ledger = (await client.get("/api/v1/quota/ledger", headers=headers)).json()["data"]
assert ledger[0]["tx_type"] == "consume"
assert ledger[0]["status"] == "committed"
async def test_alias_path_v1_matches_api_v1(client: Any) -> None:
assert (await client.get("/healthz")).status_code == 200
token = await client.post("/v1/auth/dev-token", json={"device_key": "alias-check"})
assert token.json()["code"] == 0
async def test_unauthenticated_requests_get_the_unified_envelope(client: Any) -> None:
resp = await client.post("/api/v1/agent/chat", json={"message": "hi"})
assert resp.status_code == 401
assert resp.json()["code"] == 40100