d041077bb6
- main.py: 删全局 engine/async_session;lifespan 装配 TenantRegistry (seed_profiles → 仓库根 tenants/,路径锚定),预热默认租户 jiancai 挂 app.state.default_runtime,逐 active 租户(库文件已存在)跑 sweep_stale_pending,退出 dispose_all。app.state.registry 预置即沿用 (测试注入缝) - routes/runtime.py(过渡,Task 7 删): get_runtime——state.tenant 优先, 缺省落 default_runtime;chat.py/chat_rest.py 全部改走它,消除 main↔routes 循环依赖 - ConversationManager 构造线: 新增 runtime 可选参(持 session_factory/ compiled_wall/config 引用;prompts 仍模块级,Task 6;业务接线 Task 9), fire_pending_pushes 随任务传 session_factory(后台写回派发租户的库) - lead_push_service: 去 app.main import;写库入口显式收 session_factory, 模块级 async_session=None 仅作测试注入兜底 - conftest: client 夹具 = 每测试独立 Registry(tmp data_dir)+ 真实 lifespan 在 TestClient 循环内预热;删 _dispose_main_engine; async_db 保持 NullPool(跨 asyncio.run 循环安全,刻意不换 Registry 引擎) - 测试仅动夹具/桩签名(断言零改动): wiring 桩补 session_factory 形参; history-404 用例改经真实 WS 路由造 widget 会话(引擎常驻连接绑定 TestClient 循环,测试线程不得直开 session_factory) Co-Authored-By: Claude Code <noreply@anthropic.com>
39 lines
1.5 KiB
Python
39 lines
1.5 KiB
Python
# `client` fixture from conftest (per-test Registry on tmp data_dir; default
|
|
# tenant runtime pre-warmed by the app lifespan inside the TestClient loop).
|
|
|
|
import json
|
|
|
|
|
|
def test_session_creates_new(client):
|
|
r = client.post("/api/chat/session", json={})
|
|
assert r.status_code == 200
|
|
d = r.json()
|
|
assert "session_id" in d and d["is_new"] is True and d["ended"] is False
|
|
|
|
|
|
def test_session_resume_active(client):
|
|
sid = client.post("/api/chat/session", json={}).json()["session_id"]
|
|
r = client.post("/api/chat/session", json={"session_id": sid})
|
|
assert r.json()["is_new"] is False
|
|
|
|
|
|
def test_history_new_session_empty(client):
|
|
sid = client.post("/api/chat/session", json={}).json()["session_id"]
|
|
r = client.get(f"/api/chat/{sid}/messages")
|
|
assert r.status_code == 200 and r.json() == []
|
|
|
|
|
|
def test_history_404_unknown_sid(client):
|
|
assert client.get("/api/chat/nope/messages").status_code == 404
|
|
|
|
|
|
def test_history_rejects_non_app_session(client):
|
|
# widget-source conversations are not readable via this public endpoint
|
|
# (narrow the read surface to app only). 经真实 WS 路由造 widget 会话:
|
|
# 租户 engine 的常驻连接绑定 TestClient 的事件循环,测试线程不得另起
|
|
# asyncio.run 直开其 session_factory(跨循环复用会死锁)。
|
|
with client.websocket_connect("/ws/chat") as ws:
|
|
ws.send_text(json.dumps({"source": "widget"}))
|
|
sid = ws.receive_json()["session_id"]
|
|
assert client.get(f"/api/chat/{sid}/messages").status_code == 404
|