docs+test: 发布包对拍计划、pytest 双端 API 对拍与 run_elevator_parity 脚本

- docs/elevator-api-parity: 计划/报告模板/示例
- tools/elevator_api_parity: 端点目录、fixtures、对拍 client/compare、报告生成
- scripts/run_elevator_parity: JDK8 构建 + 单测/对拍(无服务时跳过对拍用例)

Made-with: Cursor

Former-commit-id: 3d54a40e1a7ae0b1724261d4f18910a6f415f853
This commit is contained in:
反编译工作区
2026-04-25 09:50:32 +08:00
parent 2cd9da61da
commit 038f846dad
24 changed files with 712 additions and 0 deletions
@@ -0,0 +1,58 @@
from __future__ import annotations
import json
from pathlib import Path
import pytest
from parity.catalog_loader import load as load_catalog
from parity.client import call_both
_DIR = Path(__file__).resolve().parent.parent
_FIX = _DIR / "fixtures"
@pytest.mark.usefixtures("two_instances_ready")
@pytest.mark.live
def test_parity_from_catalog(
request,
base_old,
base_new,
session_http,
):
"""按 api_catalog 双端对拍。compare_mode: deep | code_only | status_only"""
cat = load_catalog()["endpoints"] # type: ignore[operator]
for ep in cat:
name = ep["id"]
fixture = ep.get("fixture")
body: dict
if fixture:
body = json.loads((_FIX / fixture).read_text(encoding="utf-8"))
else:
body = {}
pr = call_both(
name=ep.get("name", name),
method=ep.get("method", "POST"),
path=ep["path"],
body=body,
base_old=base_old,
base_new=base_new,
session=session_http,
compare_mode=ep.get("compare_mode", "code_only"),
)
row = {
"id": name,
"name": ep.get("name", name),
"method": pr.method,
"path": pr.path,
"old_status": pr.old_status,
"new_status": pr.new_status,
"match": pr.match,
"message": pr.message,
}
request.config._parity_rows.append(row) # type: ignore
# 在 code_only 下通常允许两边同一业务 code;若都非 200 也记录
assert pr.match, (
f"{name} mismatch: {pr.message}\n"
f"old_http={pr.old_status} new_http={pr.new_status}\n"
f"old_head={pr.old_text[:500]!r}\nnew_head={pr.new_text[:500]!r}"
)
@@ -0,0 +1,17 @@
"""不依赖联调机:纯比较逻辑自测。"""
from __future__ import annotations
from parity import compare as C
def test_normalize_equal():
a = {"b": 2, "a": 1, "c": {"z": 1, "y": 2}}
b = {"c": {"y": 2, "z": 1}, "a": 1, "b": 2}
assert C.normalize(a) == C.normalize(b)
def test_business_code_from_cloudwalk_result():
j = '{"code":"0","data":{}}'
p = C.parse_json_loose(j)
assert C.business_code(p) == "0"