mirror of
https://github.com/snowy-yang/xiaonuan.git
synced 2026-10-21 08:04:48 +00:00
完善测试:pytest 套件(路由器/工具循环/WS全链路/投递/PG集成)
- tests/conftest.py: 内存版 FakeDB 复刻 db.py 全部签名,绕过 lifespan 的测试应用 - test_chat_flow.py: WebSocket 全链路(回声/路由信号落库/档案/慢信/连续天数) - test_delivery.py: 事件/每日任务/关怀投递(在线与离线)、天气工具城市链、system prompt 注入 - test_router.py: 小模型路由清洗(去重/丢过去事件/非法作息/500优雅降级/无模型空判定) - test_tool_loop.py: 原生工具调用循环(喂结果/超轮次强制收尾/坏参数) - test_pure.py: 纯逻辑(连续天数/哈希槽位/时间间隔/模板/向量) - test_db_pg.py: PG 集成测试,无 PG_DSN 自动跳过,配好即真实跑库 - 旧散装脚本移除;tools_live/ws_client/tui_smoke 保留为手动脚本
This commit is contained in:
1 parent
fe96acbda2
commit
6981c6df4d
13 files changed
+1107
-192
No files matched your search
@@ -0,0 +1,143 @@
|
||||
"""PostgreSQL 集成测试:真实跑一遍 db.py 的每一层。
|
||||
|
||||
未设置 PG_DSN 时整组跳过;设置后需要库已存在(表会自动建)。
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
import app.db as db
|
||||
from app.connector import hash_embed
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not os.getenv("PG_DSN", "").strip(),
|
||||
reason="未配置 PG_DSN,跳过 PG 集成测试")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
async def conn():
|
||||
await db.init(os.environ["PG_DSN"].strip())
|
||||
yield
|
||||
await db.close()
|
||||
|
||||
|
||||
def session():
|
||||
return "test-" + uuid.uuid4().hex[:8]
|
||||
|
||||
|
||||
async def test_history_roundtrip(conn):
|
||||
s = session()
|
||||
await db.add_message(s, "user", "第一条")
|
||||
await db.add_message(s, "assistant", "第二条")
|
||||
await db.add_message(s, "user", "第三条")
|
||||
rows = await db.get_history(s)
|
||||
assert [(r["role"], r["content"]) for r in rows] == [
|
||||
("user", "第一条"), ("assistant", "第二条"), ("user", "第三条")]
|
||||
rows = await db.get_history(s, limit=2)
|
||||
assert len(rows) == 2 and rows[0]["content"] == "第二条"
|
||||
|
||||
|
||||
async def test_memories_and_semantic_search(conn):
|
||||
s = session()
|
||||
facts = ["用户喜欢打篮球", "用户住在杭州", "用户叫小明"]
|
||||
vecs = [hash_embed(f) for f in facts]
|
||||
await db.add_memories(s, facts, vecs)
|
||||
rows = await db.get_memories(s)
|
||||
assert [r["text"] for r in rows] == facts
|
||||
hits = await db.search_memories(s, hash_embed("打篮球真开心"), k=2)
|
||||
assert hits and hits[0]["text"] == "用户喜欢打篮球"
|
||||
# 整组替换(夜间巩固用)
|
||||
new_facts = ["用户叫小明", "用户在杭州上学"]
|
||||
await db.replace_memories(s, new_facts, [hash_embed(f) for f in new_facts])
|
||||
rows = await db.get_memories(s)
|
||||
assert [r["text"] for r in rows] == new_facts
|
||||
|
||||
|
||||
async def test_routine_upsert_averaging(conn):
|
||||
s = session()
|
||||
await db.upsert_routine(s, "到校", 7 * 60 + 40, "inferred")
|
||||
await db.upsert_routine(s, "到校", 7 * 60 + 50, "inferred")
|
||||
rows = await db.get_routines(s)
|
||||
assert len(rows) == 1
|
||||
assert rows[0]["minute"] == (7 * 60 + 40 + 7 * 60 + 50) // 2
|
||||
assert rows[0]["evidence"] == 2
|
||||
# explicit 直接定时间
|
||||
await db.upsert_routine(s, "到校", 7 * 60 + 30, "explicit")
|
||||
rows = await db.get_routines(s)
|
||||
assert rows[0]["minute"] == 7 * 60 + 30 and rows[0]["kind"] == "explicit"
|
||||
|
||||
|
||||
async def test_events_one_shot_and_daily(conn):
|
||||
s = session()
|
||||
now = time.time()
|
||||
eid = await db.add_event(s, "reminder", now - 10, "喝水", "once", 0)
|
||||
did = await db.add_event(s, "reminder", now + 3600, "吃药", "daily", 22 * 60)
|
||||
|
||||
due = await db.due_events(s)
|
||||
assert [e["id"] for e in due] == [eid]
|
||||
today = time.strftime("%Y-%m-%d")
|
||||
daily = await db.due_daily_events(today, 22 * 60 + 1, window=10)
|
||||
assert [e["id"] for e in daily] == [did]
|
||||
await db.mark_event_fired(did, today)
|
||||
assert await db.due_daily_events(today, 22 * 60 + 1, window=10) == []
|
||||
|
||||
rows = await db.today_events(s, now - 60)
|
||||
assert {e["id"] for e in rows} == {eid, did}
|
||||
await db.mark_event_done(eid)
|
||||
assert await db.due_events(s) == []
|
||||
|
||||
|
||||
async def test_care_and_letters(conn):
|
||||
s = session()
|
||||
cid = await db.add_care(s, "emotion", "心情不好", time.time() - 5)
|
||||
due = await db.due_care(time.time())
|
||||
assert [c["id"] for c in due] == [cid]
|
||||
await db.mark_care_done(cid)
|
||||
assert await db.due_care(time.time()) == []
|
||||
|
||||
lid = await db.add_letter(s, "给未来", time.time() - 5)
|
||||
assert [l["id"] for l in await db.due_letters()] == [lid]
|
||||
await db.mark_letter_delivered(lid)
|
||||
assert await db.pending_letters(s) == []
|
||||
|
||||
|
||||
async def test_meta_lore_diary_digest(conn):
|
||||
s = session()
|
||||
await db.set_meta(s, "streak", "3")
|
||||
assert await db.get_meta(s, "streak") == "3"
|
||||
assert await db.get_meta(s, "nope", "d") == "d"
|
||||
|
||||
await db.upsert_lore(s, "诞生", "v1")
|
||||
await db.upsert_lore(s, "诞生", "v2") # 同话题=更正
|
||||
lore = await db.get_lore(s)
|
||||
assert lore == [{"topic": "诞生", "body": "v2"}]
|
||||
|
||||
day = time.strftime("%Y-%m-%d")
|
||||
await db.add_diary(s, day, "今天…")
|
||||
assert (await db.get_diary(s))[0]["body"] == "今天…"
|
||||
|
||||
await db.add_digest(s, day, "回顾")
|
||||
assert await db.get_digest(s, day) == "回顾"
|
||||
assert await db.count_digests(s) == 1
|
||||
|
||||
|
||||
async def test_stats_and_day_counts(conn):
|
||||
s = session()
|
||||
await db.add_message(s, "user", "计数")
|
||||
await db.add_memories(s, ["用户是测试"], None)
|
||||
stats = await db.get_stats(s)
|
||||
assert stats["messages"] == 1 and stats["memories"] == 1
|
||||
assert stats["first_ts"] and stats["db_bytes"] > 0
|
||||
counts = await db.day_counts(s, time.time() - 60)
|
||||
assert counts["msgs"] == 1 and counts["mem"] == 1
|
||||
|
||||
|
||||
async def test_memory_from_days_ago(conn):
|
||||
s = session()
|
||||
await db.add_message(s, "user", "半个月前的话")
|
||||
rows = await db.memory_from_days_ago(s, 15, time.time())
|
||||
assert rows == [] # 刚插入的不在 15 天前
|
||||
rows = await db.memory_from_days_ago(s, 0, time.time() + 86400)
|
||||
assert any(r["content"] == "半个月前的话" for r in rows)
|
||||
Reference in new issue
Block a user