Files
xiaozhi-esp32-server/main/manager-api-fastapi/tests/compatibility/route_surface_runner.py
T

98 lines
3.2 KiB
Python

from __future__ import annotations
import argparse
import json
import re
import sys
from pathlib import Path
from typing import Any, cast
from tests.compatibility.differential_runner import ContractRunner, _build_report
TARGET_ROOT = Path(__file__).resolve().parents[2]
JAVA_MANIFEST = TARGET_ROOT / "compatibility" / "java-routes.json"
PATH_PARAMETER = re.compile(r"\{([^/{}]+)\}")
SAFE_PATH_VALUES = {
"agentId": "contract-agent-1",
"audioId": "contract-audio",
"deviceCode": "000000",
"deviceId": "contract-device-1",
"dictType": "FIRMWARE_TYPE",
"document_id": "contract-document",
"dataset_id": "contract-dataset",
"fileId": "contract-words",
"id": "contract-id",
"macAddress": "AA:BB:CC:DD:EE:01",
"modelId": "contract-model",
"modelType": "LLM",
"provideCode": "OpenAI",
"sessionId": "contract-session",
"snapshotId": "contract-snapshot",
"status": "1",
"userId": "contract-user",
"uuid": "contract-unknown-token",
}
def _safe_path(template: str) -> str:
return PATH_PARAMETER.sub(lambda match: SAFE_PATH_VALUES.get(match.group(1), "contract-value"), template)
def _load_routes() -> list[dict[str, Any]]:
manifest = json.loads(JAVA_MANIFEST.read_text(encoding="utf-8"))
routes = cast(list[dict[str, Any]], manifest["routes"])
if manifest["count"] != 154 or len(routes) != 154:
raise RuntimeError("Java route manifest is not closed at 154 routes")
return routes
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--java-base", default="http://127.0.0.1:18082/xiaozhi")
parser.add_argument("--fastapi-base", default="http://127.0.0.1:18083/xiaozhi")
parser.add_argument("--mock-base", default="http://127.0.0.1:18084")
parser.add_argument("--mysql-port", type=int, default=13316)
parser.add_argument(
"--output",
type=Path,
default=Path("compatibility/route-surface-results.json"),
)
args = parser.parse_args()
runner = ContractRunner(args.java_base, args.fastapi_base, args.mock_base, args.mysql_port)
try:
for route in _load_routes():
method = str(route["method"])
template = str(route["path"])
runner.request_pair(
f"{method} {template}",
f"route-surface:{route['auth']}",
method,
_safe_path(template),
exact_headers=("content-type",),
)
finally:
runner.close()
report = _build_report(runner)
report["coverage"] = {
"java_routes": len(runner.results),
"request_profile": "missing-auth-or-safe-invalid-input",
"side_effect_policy": "no successful write request is issued",
}
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(
json.dumps(report, ensure_ascii=False, indent=2, default=str) + "\n",
encoding="utf-8",
)
summary = report["summary"]
print(json.dumps(summary, ensure_ascii=False))
for result in runner.results:
if not result.passed:
print(f"FAIL {result.name}: {result.difference}")
sys.exit(1 if summary["failed"] else 0)
if __name__ == "__main__":
main()