85 lines
2.9 KiB
Python
85 lines
2.9 KiB
Python
"""
|
||
对外接口统一清单 / 能力矩阵 · 离线回归冒烟
|
||
(仅作回归,不替代真机 E2E;默认对 http://127.0.0.1:8899 发只读 GET)
|
||
|
||
跑法:
|
||
SDK_BASE=http://127.0.0.1:8899 python3 -m pytest sdk/tests/test_integration_manifest.py -q
|
||
或直接:
|
||
python3 sdk/tests/test_integration_manifest.py
|
||
"""
|
||
|
||
import os
|
||
import json
|
||
import urllib.request
|
||
|
||
BASE = os.environ.get("SDK_BASE", "http://127.0.0.1:8899")
|
||
DEVICE = os.environ.get("SDK_DEVICE_ID", "xgfe65eimrrofyws")
|
||
|
||
CONSUMERS = {"cunkebao", "superadmin", "ai_employee", "common"}
|
||
STATUSES = {"ready", "degraded", "offline"}
|
||
|
||
|
||
def _get(path: str) -> dict:
|
||
with urllib.request.urlopen(f"{BASE}{path}", timeout=15) as resp:
|
||
return json.loads(resp.read().decode("utf-8"))
|
||
|
||
|
||
def test_manifest_structure():
|
||
d = _get("/api/v3/integration/manifest")["data"]
|
||
assert d["total_endpoints"] > 100, "端点数应 >100"
|
||
assert d["module_count"] >= 20, "模块数应 >=20"
|
||
# other 桶应清零(全部归类)
|
||
others = [m for m in d["modules"] if m["module"] == "other"]
|
||
assert sum(m["endpoint_count"] for m in others) == 0, "other 桶必须清零"
|
||
for m in d["modules"]:
|
||
assert m["consumers"], f"模块 {m['module']} 必须有消费方"
|
||
|
||
|
||
def test_modules_runtime_tagged():
|
||
d = _get("/api/v3/integration/modules")["data"]
|
||
for m in d["modules"]:
|
||
assert m.get("runtime") in {"server", "device", "hook"}, m
|
||
|
||
|
||
def test_consumer_views():
|
||
for c in CONSUMERS:
|
||
d = _get(f"/api/v3/integration/consumers/{c}")["data"]
|
||
assert d["consumer"] == c
|
||
assert d["total_endpoints"] >= 0
|
||
for m in d["modules"]:
|
||
assert c in m["consumers"]
|
||
|
||
|
||
def test_capability_matrix():
|
||
d = _get(f"/api/v3/integration/capability/{DEVICE}?consumer=cunkebao")["data"]
|
||
assert d["device_id"] == DEVICE
|
||
assert set(d["summary"].keys()) == STATUSES
|
||
for m in d["modules"]:
|
||
assert m["status"] in STATUSES
|
||
assert m["runtime"] in {"server", "device", "hook"}
|
||
# server 模块无论设备是否在线都应 ready
|
||
server_mods = [m for m in d["modules"] if m["runtime"] == "server"]
|
||
for m in server_mods:
|
||
assert m["status"] == "ready", f"server 模块 {m['module']} 应 ready"
|
||
|
||
|
||
def test_health():
|
||
d = _get("/api/v3/integration/health")["data"]
|
||
assert "checks" in d
|
||
for key in ("websocket", "connection_provider", "cunkebao", "ai_gateway"):
|
||
assert key in d["checks"], f"health 缺少 {key}"
|
||
|
||
|
||
if __name__ == "__main__":
|
||
fails = 0
|
||
for name, fn in list(globals().items()):
|
||
if name.startswith("test_") and callable(fn):
|
||
try:
|
||
fn()
|
||
print(f" PASS {name}")
|
||
except Exception as e: # noqa: BLE001
|
||
fails += 1
|
||
print(f" FAIL {name}: {e}")
|
||
print("OK" if fails == 0 else f"{fails} FAILED")
|
||
raise SystemExit(1 if fails else 0)
|