89 lines
3.2 KiB
Python
89 lines
3.2 KiB
Python
|
|
"""临时 E2E:对比 → 采用 → 存档 → 回滚。跑完可删。"""
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import json
|
|||
|
|
import sys
|
|||
|
|
import urllib.request
|
|||
|
|
|
|||
|
|
# Windows 控制台避免 ✅ 等字符触发 GBK 编码错误
|
|||
|
|
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def chat(text: str, sid: str | None = None) -> list[dict]:
|
|||
|
|
body = json.dumps({"text": text, "sessionId": sid}).encode()
|
|||
|
|
req = urllib.request.Request(
|
|||
|
|
"http://localhost:8000/api/chat",
|
|||
|
|
data=body,
|
|||
|
|
headers={"Content-Type": "application/json"},
|
|||
|
|
)
|
|||
|
|
events: list[dict] = []
|
|||
|
|
with urllib.request.urlopen(req, timeout=60) as resp:
|
|||
|
|
buf = ""
|
|||
|
|
for chunk in resp:
|
|||
|
|
buf += chunk.decode()
|
|||
|
|
while "\n\n" in buf:
|
|||
|
|
frame, buf = buf.split("\n\n", 1)
|
|||
|
|
if frame.startswith("data: "):
|
|||
|
|
events.append(json.loads(frame[6:]))
|
|||
|
|
return events
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get(url: str) -> dict:
|
|||
|
|
with urllib.request.urlopen(url, timeout=30) as r:
|
|||
|
|
return json.loads(r.read())
|
|||
|
|
|
|||
|
|
|
|||
|
|
def post(url: str, data: dict) -> dict:
|
|||
|
|
body = json.dumps(data).encode()
|
|||
|
|
req = urllib.request.Request(url, data=body, headers={"Content-Type": "application/json"})
|
|||
|
|
with urllib.request.urlopen(req, timeout=60) as r:
|
|||
|
|
return json.loads(r.read())
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main() -> None:
|
|||
|
|
# 1) compare
|
|||
|
|
ev = chat("对比几种策略", "e2e-m2")
|
|||
|
|
blocks = [e for e in ev if e.get("type") == "block"]
|
|||
|
|
assert any(b["block"]["type"] == "scenario-cards" for b in blocks), blocks
|
|||
|
|
cards = next(b["block"]["props"]["cards"] for b in blocks if b["block"]["type"] == "scenario-cards")
|
|||
|
|
print("compare OK", len(cards), "cards:", [c["label"] for c in cards])
|
|||
|
|
tl0 = get("http://localhost:8000/api/timeline")
|
|||
|
|
v0 = len(tl0["versions"])
|
|||
|
|
|
|||
|
|
# 2) apply best
|
|||
|
|
best = min(cards, key=lambda c: (c["kpi"]["totalTardiness"], c["kpi"]["conflictCount"]))
|
|||
|
|
r = post(
|
|||
|
|
"http://localhost:8000/api/actions/scenario/apply",
|
|||
|
|
{"sessionId": "e2e-m2", "strategy": best["strategy"], "engine": best["engine"]},
|
|||
|
|
)
|
|||
|
|
print("apply OK", (r.get("message") or "")[:80])
|
|||
|
|
tl1 = get("http://localhost:8000/api/timeline")
|
|||
|
|
assert len(tl1["versions"]) >= v0, (v0, len(tl1["versions"]))
|
|||
|
|
print("versions", v0, "->", len(tl1["versions"]))
|
|||
|
|
|
|||
|
|
# 3) checkpoint create
|
|||
|
|
ev2 = chat("存个档 叫 e2e基线", "e2e-m2")
|
|||
|
|
text = "".join(e.get("text", "") for e in ev2 if e.get("type") == "token")
|
|||
|
|
print("checkpoint create:", text[:100])
|
|||
|
|
tl2 = get("http://localhost:8000/api/timeline")
|
|||
|
|
assert tl2["checkpoints"], tl2
|
|||
|
|
pair = tl2["checkpoints"][-1]
|
|||
|
|
print("pair", pair["pairId"], pair["label"])
|
|||
|
|
|
|||
|
|
# 4) rollback stage + approve
|
|||
|
|
ev3 = chat(f"回滚到检查点 {pair['pairId']}", "e2e-m2")
|
|||
|
|
blocks3 = [e for e in ev3 if e.get("type") == "block"]
|
|||
|
|
assert any(b["block"]["type"] == "confirm-card" for b in blocks3), blocks3
|
|||
|
|
cid = next(b["block"]["props"]["confirmId"] for b in blocks3 if b["block"]["type"] == "confirm-card")
|
|||
|
|
print("rollback staged", cid)
|
|||
|
|
r2 = post(
|
|||
|
|
"http://localhost:8000/api/actions/confirm",
|
|||
|
|
{"sessionId": "e2e-m2", "confirmId": cid, "approve": True},
|
|||
|
|
)
|
|||
|
|
print("rollback OK", (r2.get("message") or "")[:100])
|
|||
|
|
print("E2E M2 PASS")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|