feat: 安全应用采购规格解析结果 (#257)
This commit is contained in:
@@ -206,6 +206,107 @@ class HttpAdminGatewayTest(unittest.TestCase):
|
||||
self.assertTrue(receipt.accepted)
|
||||
self.assertTrue(receipt.result_id.startswith("legacy-failure-"))
|
||||
|
||||
def test_resolve_purchase_spec_posts_once_and_parses_whitelisted_match(self):
|
||||
response = {
|
||||
"schema_version": 1,
|
||||
"resolution_id": "psr-001",
|
||||
"outcome": "matched",
|
||||
"source": "rule",
|
||||
"candidate_snapshot_hash": "a" * 64,
|
||||
"match": {
|
||||
"candidate_id": "c1",
|
||||
"raw_text": "120斤",
|
||||
"options": {"color": "黑色", "size": "120斤"},
|
||||
},
|
||||
"confidence_bps": 10000,
|
||||
"reason": "唯一等价",
|
||||
"resolved_at": "2026-08-17T08:00:01Z",
|
||||
"future_field": "ignored",
|
||||
}
|
||||
opener = RecordingOpener(FakeResponse(200, response))
|
||||
gateway = HttpAdminGateway(
|
||||
opener=opener, client_id="CLIENT-001", timeout_seconds=5
|
||||
)
|
||||
|
||||
receipt = gateway.resolve_purchase_spec(
|
||||
"PUR-001", "spec-resolution-v1:key", {"schema_version": 1}
|
||||
)
|
||||
|
||||
self.assertEqual(receipt.resolution_id, "psr-001")
|
||||
self.assertEqual(receipt.match.raw_text, "120斤")
|
||||
self.assertTrue(opener.request.full_url.endswith(
|
||||
"/api/v1/client/tasks/PUR-001/spec-resolution"
|
||||
))
|
||||
headers = {
|
||||
key.lower(): value for key, value in opener.request.header_items()
|
||||
}
|
||||
self.assertEqual(
|
||||
headers["idempotency-key"], "spec-resolution-v1:key"
|
||||
)
|
||||
self.assertEqual(opener.timeout, 5)
|
||||
|
||||
def test_resolve_purchase_spec_accepts_all_nonmatched_business_outcomes(self):
|
||||
for outcome in ("uncertain", "rejected", "failed"):
|
||||
with self.subTest(outcome=outcome):
|
||||
gateway = HttpAdminGateway(
|
||||
opener=RecordingOpener(
|
||||
FakeResponse(
|
||||
200,
|
||||
{
|
||||
"schema_version": 1,
|
||||
"resolution_id": f"psr-{outcome}",
|
||||
"outcome": outcome,
|
||||
"source": None,
|
||||
"candidate_snapshot_hash": "b" * 64,
|
||||
"match": None,
|
||||
"confidence_bps": None,
|
||||
"reason": "没有唯一安全候选",
|
||||
"resolved_at": "2026-08-17T08:00:01Z",
|
||||
},
|
||||
)
|
||||
),
|
||||
client_id="CLIENT-001",
|
||||
)
|
||||
|
||||
receipt = gateway.resolve_purchase_spec(
|
||||
"PUR-001", "spec-resolution-v1:key", {}
|
||||
)
|
||||
|
||||
self.assertEqual(receipt.outcome, outcome)
|
||||
self.assertIsNone(receipt.match)
|
||||
|
||||
def test_resolve_purchase_spec_rejects_match_on_nonmatched_outcome(self):
|
||||
gateway = HttpAdminGateway(
|
||||
opener=RecordingOpener(
|
||||
FakeResponse(
|
||||
200,
|
||||
{
|
||||
"schema_version": 1,
|
||||
"resolution_id": "psr-invalid",
|
||||
"outcome": "uncertain",
|
||||
"source": "ai",
|
||||
"candidate_snapshot_hash": "c" * 64,
|
||||
"match": {
|
||||
"candidate_id": "c1",
|
||||
"raw_text": "120斤",
|
||||
"options": {"color": "黑色", "size": "120斤"},
|
||||
},
|
||||
"confidence_bps": 5000,
|
||||
"reason": "响应自相矛盾",
|
||||
"resolved_at": "2026-08-17T08:00:01Z",
|
||||
},
|
||||
)
|
||||
),
|
||||
client_id="CLIENT-001",
|
||||
)
|
||||
|
||||
with self.assertRaises(AdminGatewayError) as raised:
|
||||
gateway.resolve_purchase_spec(
|
||||
"PUR-001", "spec-resolution-v1:key", {}
|
||||
)
|
||||
|
||||
self.assertEqual(raised.exception.code, "ADMIN_INVALID_RESPONSE")
|
||||
|
||||
def test_malformed_2xx_submission_is_retryable_and_not_called_rejected(self):
|
||||
gateway = HttpAdminGateway(
|
||||
opener=RecordingOpener(FakeResponse(200, {"accepted": True})),
|
||||
|
||||
Reference in New Issue
Block a user