Files

101 lines
3.8 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.
import asyncio
import threading
from fastapi.testclient import TestClient
from genesis.server.app import create_app
from genesis.server.hub import ProgressHub, hub
from genesis.server.store import SessionStore, ProjectsStore
from pathlib import Path
_SAMPLE = Path(__file__).resolve().parents[1] / "sample"
def _client(tmp_path, engine="fake"):
return TestClient(create_app(
store=SessionStore(db_path=str(tmp_path / "s.db")),
data_root=str(tmp_path / "data"), engine=engine))
def test_ws_progress_during_generate(tmp_path):
client = TestClient(create_app(
store=SessionStore(db_path=str(tmp_path / "s.db")),
data_root=str(tmp_path / "data"), engine="fake"))
sid = client.post("/api/sessions", json={"user_id": "u1"}).json()["session_id"]
for ft, name in [("requirements", "requirements_newdev.xlsx"),
("template", "template_design_ja.docx"),
("write_instruction", "rules_design_ja.docx"),
("rules", "rules_entry_ja.docx")]:
client.post(f"/api/sessions/{sid}/files", data={"file_type": ft},
files={"file": (name, (_SAMPLE / name).read_bytes())})
received = []
def trigger():
hub.emit(sid, {"type": "progress", "step": "generate", "status": "ok", "detail": "生成完成"})
with client.websocket_connect(f"/api/sessions/{sid}/ws") as ws:
threading.Thread(target=trigger).start()
data = ws.receive_json()
received.append(data)
assert any(e["type"] == "progress" and e["step"] == "generate" for e in received)
def test_ws_progress_second_emit_after_disconnect(tmp_path):
# 客户端读取首条后退出,服务端在第二条 send_json 时触发 WebSocketDisconnect
# 覆盖 app.py 中 except WebSocketDisconnect: pass 分支
client = _client(tmp_path)
sid = client.post("/api/sessions", json={"user_id": "u1"}).json()["session_id"]
def trigger_twice():
hub.emit(sid, {"type": "progress", "step": "a", "status": "ok"})
hub.emit(sid, {"type": "progress", "step": "b", "status": "ok"})
with client.websocket_connect(f"/api/sessions/{sid}/ws") as ws:
threading.Thread(target=trigger_twice).start()
ws.receive_json()
def test_static_chat_ws_served(tmp_path):
# 覆盖 app.py 中 /chat_ws.js 与 /chat_state.js 端点
client = _client(tmp_path)
assert client.get("/chat_ws.js").status_code == 200
assert client.get("/chat_state.js").status_code == 200
def test_projects_endpoints_noop(tmp_path):
# 覆盖 app.py 中项目配置端点的既有分支
client = _client(tmp_path)
assert client.get("/api/projects").status_code == 200
assert client.get("/api/projects/nope").status_code == 404
assert client.delete("/api/projects/nope").status_code == 200
def test_app_real_engine_skips_fake_branch(tmp_path):
# 覆盖 app.py 中 engine 既非 fake 亦非 None 的跳转分支(91->94
client = _client(tmp_path, engine="real")
assert client.get("/api/health").status_code == 200
async def test_hub_emit_without_loop_fallback():
# 未注册事件循环时,emit 走同步兜底分支(hub.py:41
h = ProgressHub()
q = h.subscribe("s1")
h.emit("s1", {"type": "progress", "step": "x"})
assert q.get_nowait()["step"] == "x"
async def test_hub_unsubscribe_unknown_queue_noop():
# 退订不存在的队列时安全跳过(hub.py:31->exit
h = ProgressHub()
h.register_loop(asyncio.get_running_loop())
h.subscribe("s1")
h.unsubscribe("s1", object())
async def test_hub_unsubscribe_leaves_other_subscribers():
# 退订后仍有其他订阅者时不清理 sidhub.py:33->exit
h = ProgressHub()
h.register_loop(asyncio.get_running_loop())
q1 = h.subscribe("s1")
h.subscribe("s1")
h.unsubscribe("s1", q1)
assert h._subs.get("s1") is not None