Files
xiaonuan/tests/test_chat_flow.py
snowy-yang ea83b5df4b OneBot 11 适配器:反向 WS 接入 QQ(NapCat/Lagrange)
- app/onebot.py: /onebot/v11/ws 反向 WS;私聊全回、群聊仅回应 @她 并自动 @ 回去
- CQ 码字符串与消息段数组双格式解析;会话 id ob-<self_id>-p/g-<目标> 与 TUI 隔离
- action echo 配对调用(send_private_msg / send_group_msg),retcode==0 才落历史
- remember_later 的推送(事件确认/关怀/连续天数/身世)自动转成 QQ 消息
- 主动消息路由:push_proactive 优先 TUI、ob- 会话走 QQ,均不在线保持 pending
- 主干重构:chat_turn() 供 TUI 与 OneBot 共用;助手消息由传输层确认送达后落库
- 可选 OB_ACCESS_TOKEN 令牌校验;8 个新测试(回复/CQ剥离/群@/通知转换/主动推送/令牌)
2026-09-29 20:27:13 +08:00

94 lines
3.9 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.
"""WebSocket 全链路流测试:路由信号 → 回复 → 落库(FakeDB,无需 PG)"""
import asyncio
import time
from datetime import datetime, timedelta
from app import main
def test_echo_reply_and_history(client, route_sig, run_chat, reply_text):
route_sig({}) # 路由器:什么信号都没有
received = run_chat([{"type": "chat", "text": "你好呀"}])
text = reply_text(received)
assert "回声模式" in text and "你好呀" in text
assert received[-1]["type"] == "done"
def test_route_signals_land_in_db(client, route_sig, fdb, run_chat):
future = datetime.now() + timedelta(hours=1)
route_sig({
"facts": ["用户叫小明"],
"events": [{"kind": "alarm", "fire_at": future,
"text": "起床", "repeat": "once"}],
"negative_mood": True,
"promises": [{"note": "面试",
"due_at": datetime.now() + timedelta(days=1)}],
"lore": [{"topic": "诞生", "body": "小暖是用户亲手造的"}],
})
run_chat([{"type": "chat", "text": "我叫小明,明早叫我起床,"
"昨天心情不好,明天面试,你是我造的"}])
# remember_later 是后台任务,等它跑完
time.sleep(0.5)
assert [m["text"] for m in fdb.memories] == ["用户叫小明"]
assert len(fdb.events) == 1 and fdb.events[0]["text"] == "起床"
assert len(fdb.care) == 2 # 情绪回访 + 承诺追踪
kinds = {c["kind"] for c in fdb.care}
assert kinds == {"emotion", "promise"}
assert fdb.lore[("s1", "诞生")] == "小暖是用户亲手造的"
# 对话历史:user + assistant
assert len(fdb.history) == 2
def test_view_reply_reads_db(client, route_sig, fdb, run_chat, reply_text):
asyncio.run(fdb.add_memories("s1", ["用户叫小明", "用户喜欢打篮球"], None))
route_sig({"view": "memories"})
received = run_chat([{"type": "chat", "text": "你的记忆里有什么"}])
text = reply_text(received)
assert "用户叫小明" in text and "用户喜欢打篮球" in text
# 档案回复也进历史(assistant 角色)
assert any(h["role"] == "assistant" and "小明" in h["content"]
for h in fdb.history)
def test_letter_flow(client, route_sig, fdb, run_chat, reply_text):
route_sig({"letter": (7, "给未来的我:加油")})
received = run_chat([{"type": "chat", "text": "给7天后的自己写信:加油"}])
assert "✉️" in reply_text(received)
assert len(fdb.letters) == 1 and fdb.letters[0]["body"] == "给未来的我:加油"
def test_letter_ask_when_incomplete(client, route_sig, fdb, run_chat,
reply_text):
route_sig({"letter": ("ask", "")})
received = run_chat([{"type": "chat", "text": "我想写慢信"}])
assert "给7天后的自己写信" in reply_text(received)
assert fdb.letters == []
def test_streak_increments(fdb, offline):
yesterday = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
asyncio.run(fdb.set_meta("s1", "last_active", yesterday))
asyncio.run(fdb.set_meta("s1", "streak", "3"))
sig = {"facts": [], "events": [], "routines": [], "promises": [],
"lore": [], "letter": None, "view": None, "negative_mood": False}
class FakeWS:
async def send_json(self, payload):
pass
asyncio.run(main.remember_later(FakeWS().send_json, "s1", "我来了", sig))
assert asyncio.run(fdb.get_meta("s1", "streak")) == "4"
def test_streak_resets_after_gap(fdb, offline):
asyncio.run(fdb.set_meta("s1", "last_active", "2020-01-01"))
sig = {"facts": [], "events": [], "routines": [], "promises": [],
"lore": [], "letter": None, "view": None, "negative_mood": False}
class FakeWS:
async def send_json(self, payload):
pass
asyncio.run(main.remember_later(FakeWS().send_json, "s1", "好久不见", sig))
assert asyncio.run(fdb.get_meta("s1", "streak")) == "1"