feat: let every gateway error carry what the gateway said
Issue #10 Task 1: a rejected call's reason had nowhere to live. The field goes on the base class because these errors all come from one HTTP response - which class it is and what the peer said are orthogonal.
This commit is contained in:
@@ -34,6 +34,43 @@ class TestBaseShape:
|
||||
assert TransientError("429", retry_after_s=2.5).retry_after_s == 2.5
|
||||
|
||||
|
||||
class TestBodyText:
|
||||
"""issue #10: 非 2xx 的响应体摘要必须有承载处,否则拒绝理由事后不可查。"""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"cls", (PolyGatewayError, TransientError, SourceDeadError, RequestRejectedError)
|
||||
)
|
||||
def test_defaults_empty_and_accepts_summary(self, cls):
|
||||
assert cls("boom").body_text == ""
|
||||
assert cls("boom", body_text='{"error":{"code":"bad"}}').body_text == (
|
||||
'{"error":{"code":"bad"}}'
|
||||
)
|
||||
|
||||
def test_result_invalid_keeps_both_fields_apart(self):
|
||||
"""`body_text`(非 2xx 的拒绝理由)与 `raw_text`(2xx 的不可解析输出)不得混用。"""
|
||||
exc = ResultInvalidError("bad json", raw_text="{oops", body_text="")
|
||||
assert exc.raw_text == "{oops"
|
||||
assert exc.body_text == ""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exc",
|
||||
(
|
||||
AllSourcesExhausted(scope="llm", reason="stalled", retry_after_s=1.0),
|
||||
CircuitOpenError(scope="llm", retry_after_s=1.0),
|
||||
GovernanceBackendError("redis down", scope="llm"),
|
||||
),
|
||||
)
|
||||
def test_scope_level_errors_carry_no_body(self, exc):
|
||||
"""scope 级失败没有单一响应体可言,空串是如实表达而非噪音。"""
|
||||
assert exc.body_text == ""
|
||||
|
||||
def test_body_text_does_not_leak_into_str(self):
|
||||
"""字段是旁路数据: 加了它不得改变任何既有异常的 str() 输出。"""
|
||||
assert str(RequestRejectedError("qwen_1 请求被拒: 400", body_text="whatever")) == (
|
||||
"qwen_1 请求被拒: 400"
|
||||
)
|
||||
|
||||
|
||||
class TestResultInvalid:
|
||||
def test_carries_diagnosis(self):
|
||||
exc = ResultInvalidError(
|
||||
@@ -134,9 +171,7 @@ class TestGovernanceBackendReason:
|
||||
assert "governance_backend_down" in SCOPE_REASONS
|
||||
|
||||
def test_gateway_unavailable_accepts_the_new_reason(self):
|
||||
exc = AllSourcesExhausted(
|
||||
scope="LLM", reason="governance_backend_down", retry_after_s=0.0
|
||||
)
|
||||
exc = AllSourcesExhausted(scope="LLM", reason="governance_backend_down", retry_after_s=0.0)
|
||||
assert exc.reason == "governance_backend_down"
|
||||
|
||||
def test_retry_after_default_is_non_zero(self):
|
||||
|
||||
Reference in New Issue
Block a user