"""Client contract checks: exact signed bytes, gzip decoding, idempotency and report identity.""" import base64 import gzip import hashlib import hmac import json import httpx import pytest from scripts.test_plm_risk_report import DEFAULT_PAYLOAD, PLMReportTest SECRET = "client-test-secret-at-least-32-characters" URL = "http://test/api/v1/integrations/risk-assessments/report" DIMENSIONS = ("供应商表现", "物料品类", "产品品类", "加工厂质量", "标准符合性", "节点阶段", "缺陷等级") REPORT = ( "# 新品风险评估报告\n\n" + "\n".join(f"| {name} | 50 | 10% | default | 默认分 |" for name in DIMENSIONS) ).encode() def test_client_sends_signed_snapshot_and_handles_compression(tmp_path): payload = json.loads(DEFAULT_PAYLOAD.read_text(encoding="utf-8")) methods, nonces, post_bodies = [], [], [] def handler(request): methods.append(request.method) timestamp, nonce = request.headers["X-Timestamp"], request.headers["X-Nonce"] nonces.append(nonce) prefix = timestamp.encode() + b"\n" + nonce.encode() + b"\n" assert request.method == "POST" message = prefix + request.content assert request.headers["Idempotency-Key"] == payload["requestId"] post_bodies.append(request.content) expected = base64.b64encode(hmac.new(SECRET.encode(), message, hashlib.sha256).digest()).decode() assert request.headers["X-Signature"] == expected content = json.dumps( { "code": 200, "data": { "requestId": payload["requestId"], "reportMarkdown": REPORT.decode("utf-8"), }, }, ensure_ascii=False, ).encode() return httpx.Response( 200, headers={ "Content-Type": "application/json", "Content-Encoding": "gzip", "X-Request-Id": payload["requestId"], "X-Assessment-Id": "2", "X-Risk-Score": "44.00", "X-Risk-Level": "medium", "X-Model-Version": "database-seven-dimension-v1", }, content=gzip.compress(content), ) with httpx.Client(transport=httpx.MockTransport(handler)) as client: result = PLMReportTest(client, URL, SECRET, payload, tmp_path).run() assert result["success"] and result["score"] == 44 and result["dimensionCount"] == 7 assert methods == ["POST", "POST"] assert len(set(nonces)) == 2 assert post_bodies[0] == post_bodies[1] == (tmp_path / "request.json").read_bytes() assert (tmp_path / "report.md").read_bytes() == REPORT assert SECRET not in json.dumps(result) and "x-signature" not in json.dumps(result).lower() def test_client_rejects_report_for_different_request(tmp_path): payload = json.loads(DEFAULT_PAYLOAD.read_text(encoding="utf-8")) def handler(request): return httpx.Response(200, headers={"Content-Type": "application/json", "X-Request-Id": "wrong"}, json={}) with httpx.Client(transport=httpx.MockTransport(handler)) as client: with pytest.raises(ValueError, match="X-Request-Id"): PLMReportTest(client, URL, SECRET, payload, tmp_path).run() assert not (tmp_path / "report.md").exists()