test: prove a rejected call's reason reaches the telemetry table

Issue #10 Task 5, the acceptance claim. Before the fix this asserted
against 'qwen_1 请求被拒: 400' and failed on the first substring - which
is exactly what the downstream batch was left with. Uses the real body
from the issue, and checks the trailing code too, since a head-only cut
would drop the one field you quote when chasing the provider.
This commit is contained in:
2026-08-16 06:17:10 -04:00
parent a3f4cc323f
commit 9dada0be9d
+40 -1
View File
@@ -11,7 +11,12 @@ import sqlite3
import httpx
import pytest
from polygateway import CircuitOpenError, GatewayClient, TransientError
from polygateway import (
CircuitOpenError,
GatewayClient,
RequestRejectedError,
TransientError,
)
from polygateway.backends.memory.breaker import InMemoryGate
from polygateway.backends.memory.cache import InMemoryCache
from polygateway.backends.memory.limiter import InMemoryLimiter
@@ -173,6 +178,40 @@ class TestTelemetryAcrossPaths:
assert len({cid for _, cid in rows}) == 2 # call_id 逐次独立
class TestRejectionReasonIsQueryable:
"""issue #10 的验收主张: 400 之后,网关说的话必须能在遥测表里查到。
下游一轮 1050 张影像的批处理里,1 张在读表格时收到 400 被判确定性失败,
事后"这张图到底哪里不合规"无从查起——响应体在 transport 翻译层就没了。
"""
# issue #10 原文给出的真实响应体(一字不改)
_BODY = (
'{"error":{"message":"<400> ***.***.InvalidParameter: The image format is illegal '
'and cannot be opened","type":"invalid_request_error","param":"",'
'"code":"invalid_parameter_error"}}'
)
async def test_rejected_call_leaves_the_reason_in_telemetry(self, tmp_path):
recorder = SQLiteRecorder(tmp_path / "t.db")
client = _full_client(
lambda req: httpx.Response(400, content=self._BODY.encode()), telemetry=recorder
)
with pytest.raises(RequestRejectedError):
await client.chat([{"role": "user", "content": "hi"}])
recorder.close()
rows = sqlite3.connect(tmp_path / "t.db").execute("SELECT error FROM llm_calls").fetchall()
assert rows, "400 必须留下遥测行(遥测必录)"
errors = " ".join(r[0] or "" for r in rows)
# 修复前这里只有 "qwen_1 请求被拒: 400"——诊断信息一个字都不在
assert "InvalidParameter" in errors
assert "The image format is illegal" in errors
# 尾部的 code 才是向网关方追查的凭据,头部硬切正好会丢掉它
assert "invalid_parameter_error" in errors
class TestStructuredThroughStack:
async def test_feedback_reask_passes_through_governance(self):
"""重问经过内层治理: 第二次真实请求同样被限流/熔断记账。"""