完善测试: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:
snowy-yang committed 2026-09-23 20:20:37 +08:00
1 parent fe96acbda2
commit 6981c6df4d
13 files changed
+1107 -192

No files matched your search

+98
View File
@@ -0,0 +1,98 @@
"""纯逻辑测试:连续天数 / 彩蛋时刻 / 时间间隔 / 模板 / 向量"""
from datetime import datetime
from app.connector import ASSISTANT_NAME, hash_embed
from app.db import cosine
from app.main import (_daily_slot, absence_text, compute_streak, digest_echo,
human_gap)
NOW = datetime(2026, 9, 21, 19, 30) # 周一晚上
# ---- 连续陪伴天数 ----
def test_streak_yesterday_increments():
assert compute_streak("2026-09-20", 5, NOW) == 6
def test_streak_gap_resets():
assert compute_streak("2026-09-19", 5, NOW) == 1
def test_streak_first_time():
assert compute_streak("", 0, NOW) == 1
def test_streak_same_day_unchanged():
assert compute_streak("2026-09-21", 7, NOW) == 7
# ---- 每日彩蛋时刻(哈希槽位)----
def test_daily_slot_deterministic():
a = _daily_slot("sess-a", "replay", 19 * 60, 22 * 60, "2026-09-21")
b = _daily_slot("sess-a", "replay", 19 * 60, 22 * 60, "2026-09-21")
assert a == b
def test_daily_slot_within_window():
for key in ("replay", "share", "diary", "digest"):
slot = _daily_slot("sess-a", key, 10 * 60, 21 * 60, "2026-09-21")
assert 10 * 60 <= slot < 21 * 60
def test_daily_slot_differs_per_session():
a = _daily_slot("sess-a", "replay", 19 * 60, 22 * 60, "2026-09-21")
b = _daily_slot("sess-b", "replay", 19 * 60, 22 * 60, "2026-09-21")
# 不保证必然不同,但同窗口内两者都合法;这里验证可分布
assert 19 * 60 <= a < 22 * 60 and 19 * 60 <= b < 22 * 60
# ---- 时间间隔说法 ----
def test_human_gap_minutes():
assert human_gap(59) == "1 分钟"
assert human_gap(5 * 60) == "5 分钟"
def test_human_gap_hours():
assert human_gap(2 * 3600 + 47 * 60) == "2 小时 47 分钟"
assert human_gap(2 * 3600) == "2 小时"
def test_human_gap_days():
assert human_gap(3 * 86400) == "3 天"
# ---- 缺勤迎接(回声模板)----
async def test_absence_text_mentions_the_gap():
line = await absence_text("s1", 3700)
assert "小时" in line
assert ("安静" in line) or ("心跳" in line) or ("开了灯" in line)
# ---- 学徒回顾模板 ----
def test_digest_echo_signature_and_numbers():
d = digest_echo({"msgs": 12, "mem": 3}, 45)
assert "12" in d and "3" in d and "45" in d and ASSISTANT_NAME in d
# ---- 向量(回声模式哈希 embedding)----
def test_hash_embed_self_similarity():
v = hash_embed("我喜欢打篮球")
assert len(v) == 256
assert abs(cosine(v, v) - 1.0) < 1e-9
def test_hash_embed_related_beats_unrelated():
base = hash_embed("我喜欢打篮球")
near = hash_embed("打篮球的时候我很开心")
far = hash_embed("明天北京的天气怎么样")
assert cosine(base, near) > cosine(base, far)
def test_cosine_handles_empty():
assert cosine(hash_embed("x"), []) == 0.0