Files
projectAIpopular/tests/test_gateway.py
tzt 43e2bceae7 feat(v3): T26 两级智能体(大模型规划/审查 + 本地小模型执行,D7)
- run_dual 编排:规划者两阶段 JSON(plan/review,失败回喂重试一次再降级),
  redo 时裁决意见回喂执行者,交接上限 agent.max_handoffs(默认 2)
- 交接文档 agent_runs/{id}/handoff.json(智能体版交流文本:instructions/acceptance/exchanges)
- /agent 新增 executor_pool_id;规划者==执行者条目拒绝;整体 token_cap 覆盖两级调用
- ToolLoop 增 emit_final 开关(内层循环不发终态,防前端 SSE 提前收口)
- 前端:执行者选择器 + phase/message 事件渲染(阶段徽标 + 双色消息卡)
- 测试 +3(done/redo/执行者故障),全量 277 passed
- fix(tests): test_config_get_put_reset 增加设置备份/恢复隔离,防止清掉用户真实配置
2026-09-01 11:45:33 +08:00

136 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""FastAPI 网关测试:v1 legacy 端点保持 + v2 端点(封闭,注入 mock 管线)。"""
import pytest
pytest.importorskip("fastapi")
pytest.importorskip("httpx")
from fastapi.testclient import TestClient
import gateway.api as ga
from gateway.api import app
@pytest.fixture()
def client():
return TestClient(app)
@pytest.fixture()
def v2_client(client):
# 用 mock worker 构建真实 v2 管线并注入(无需 API key / 真实模型)
pipe = ga.build_v2_pipeline(worker_cfg_override={"backend": "mock"})
ga.set_pipeline(pipe)
return client
def test_health(client):
resp = client.get("/health")
assert resp.status_code == 200
data = resp.json()
assert data["status"] == "ok"
assert "code" in data["domains"]
def test_chat_legacy(client):
resp = client.post("/chat/legacy", json={"query": "用 Python 写一个快速排序函数"})
assert resp.status_code == 200
data = resp.json()
assert data["response"]
assert data["domain"] == "code"
assert "route" in data
def test_chat_v2(v2_client):
# POST /chat 立即返回 request_id(异步协议)
resp = v2_client.post("/chat", json={"query": "请介绍快速排序算法"})
assert resp.status_code == 200
data = resp.json()
assert "request_id" in data
assert data["status"] == "pending"
# 轮询 /runs/{id}/status 直到完成
import time
for _ in range(50): # 最多 5s
time.sleep(0.1)
status_resp = v2_client.get(f"/runs/{data['request_id']}/status")
assert status_resp.status_code == 200
s = status_resp.json()
if s["status"] in ("done", "failed"):
break
assert s["status"] == "done", f"期望 done,实际 {s['status']}error={s.get('error')}"
assert s["response"]
assert "pipeline_status" in s
assert s["pipeline_status"] in ("fast_path", "done", "escalated")
# fast_path 不写 workspace.json,所以 workspace_path 可能为 None
if s["pipeline_status"] != "fast_path":
assert s["workspace_path"] is not None
def test_chat_empty_query(client):
resp = client.post("/chat", json={"query": ""})
assert resp.status_code == 422
def test_metrics(client):
resp = client.get("/metrics")
assert resp.status_code == 200
data = resp.json()
assert "router" in data
assert "cache" in data
assert "v2" in data
assert "review" in data
def test_config_get_put_reset(client):
"""/config 端到端。settings.json 是活文件(用户真实配置),
测试前后必须备份/恢复,禁止把用户配置清掉。"""
import json
store = ga.settings_store()
snapshot = json.loads(json.dumps(store._data, ensure_ascii=False))
try:
# GET 默认
r = client.get("/config")
assert r.status_code == 200
assert r.json()["worker"]["backend"] in ("llama_server", "openai", "mock")
# PUT 更新 worker
r2 = client.put("/config", json={"worker": {"backend": "mock", "temperature": 0.5}})
assert r2.status_code == 200
assert r2.json()["worker"]["temperature"] == 0.5
# 重置
r3 = client.post("/config/reset")
assert r3.status_code == 200
assert r3.json()["worker"]["backend"] == "llama_server"
finally:
store._data = snapshot
store.save()
ga.rebuild_pipeline()
def test_workspace_not_found(client):
resp = client.get("/runs/nonexistent/workspace")
assert resp.status_code == 404
def test_web_ui_served(client):
resp = client.get("/")
assert resp.status_code == 200
assert resp.headers["content-type"].startswith("text/html")
# Vue SPA:由 Vite 生成,特征是 <div id="app"> 和 /static/assets/ 引用
assert '<div id="app">' in resp.text
assert '/static/assets/' in resp.text
def test_review_flow(client):
q = ga.get_review()
rid = q.enqueue("req-x", "q", "ans", tags=["safety"], reason="test")
assert q.count() >= 1
resp = client.get("/review/queue")
assert resp.status_code == 200
resp2 = client.post(f"/review/{rid}", params={"verdict": "approve"})
assert resp2.status_code == 200
assert resp2.json()["ok"] is True