MaiBot/tests/test_private_chat.py

133 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import pytest
import asyncio
from src.chat.heart_flow.sub_heartflow import SubHeartflow, ChatState
from src.chat.heart_flow.subheartflow_manager import SubHeartflowManager
from src.chat.message_receive.message import MessageRecv, MessageInfo, UserInfo
from src.chat.message_receive.chat_stream import ChatStream
from unittest.mock import MagicMock, AsyncMock, patch
@pytest.fixture
async def subheartflow_manager():
manager = SubHeartflowManager()
yield manager
# 清理所有子心流
for subflow in manager.get_all_subheartflows():
await subflow.shutdown()
@pytest.fixture
def mock_chat_stream():
stream = MagicMock(spec=ChatStream)
stream.group_info = None # 私聊没有群信息
stream.platform = "test"
return stream
@pytest.fixture
def mock_message():
message = MagicMock(spec=MessageRecv)
message.message_info = MagicMock(spec=MessageInfo)
message.message_info.user_info = MagicMock(spec=UserInfo)
message.message_info.message_id = "test_msg_1"
message.message_info.time = 1234567890
message.message_info.platform = "test"
message.processed_plain_text = "测试消息"
return message
@pytest.mark.asyncio
async def test_private_chat_absent_to_focused(subheartflow_manager, mock_chat_stream, mock_message):
"""测试私聊从ABSENT到FOCUSED的转换"""
# 创建私聊子心流
subflow_id = "private_test_1"
subflow = await subheartflow_manager.get_or_create_subheartflow(subflow_id)
assert subflow is not None
# 确认初始状态为ABSENT
assert subflow.chat_state.chat_status == ChatState.ABSENT
# 模拟新消息
with patch("src.chat.heart_flow.observation.chatting_observation.ChattingObservation") as mock_obs:
mock_obs_instance = mock_obs.return_value
mock_obs_instance.has_new_messages_since.return_value = True
# 触发状态检查
await subheartflow_manager.sbhf_absent_private_into_focus()
# 验证状态已转换为FOCUSED
assert subflow.chat_state.chat_status == ChatState.FOCUSED
@pytest.mark.asyncio
async def test_private_chat_focused_to_absent(subheartflow_manager, mock_chat_stream, mock_message):
"""测试私聊从FOCUSED到ABSENT的转换"""
# 创建私聊子心流
subflow_id = "private_test_2"
subflow = await subheartflow_manager.get_or_create_subheartflow(subflow_id)
assert subflow is not None
# 设置初始状态为FOCUSED
await subflow.change_chat_state(ChatState.FOCUSED)
assert subflow.chat_state.chat_status == ChatState.FOCUSED
# 触发状态转换
await subheartflow_manager.sbhf_focus_into_normal(subflow_id)
# 验证状态已转换为ABSENT私聊特殊处理
assert subflow.chat_state.chat_status == ChatState.ABSENT
@pytest.mark.asyncio
async def test_private_chat_stop_keywords(subheartflow_manager, mock_chat_stream, mock_message):
"""测试私聊停止关键词触发状态转换"""
# 创建私聊子心流
subflow_id = "private_test_3"
subflow = await subheartflow_manager.get_or_create_subheartflow(subflow_id)
assert subflow is not None
# 设置初始状态为FOCUSED
await subflow.change_chat_state(ChatState.FOCUSED)
# 模拟包含停止关键词的消息
mock_message.processed_plain_text = "再见啦"
# 模拟处理消息
with patch("src.chat.focus_chat.planners.planner.ActionPlanner") as mock_planner:
mock_planner_instance = mock_planner.return_value
mock_planner_instance.plan_simple.return_value = {
"action_type": "stop_focus_chat",
"action_data": {},
"reasoning": "检测到停止专注聊天的信号"
}
# 触发状态转换
await subheartflow_manager.sbhf_focus_into_normal(subflow_id)
# 验证状态已转换为ABSENT
assert subflow.chat_state.chat_status == ChatState.ABSENT
@pytest.mark.asyncio
async def test_private_chat_error_recovery(subheartflow_manager, mock_chat_stream, mock_message):
"""测试私聊错误恢复"""
# 创建私聊子心流
subflow_id = "private_test_4"
subflow = await subheartflow_manager.get_or_create_subheartflow(subflow_id)
assert subflow is not None
# 设置初始状态为FOCUSED
await subflow.change_chat_state(ChatState.FOCUSED)
# 模拟处理器错误
with patch("src.chat.focus_chat.heartFC_chat.HeartFChatting._process_processors") as mock_proc:
mock_proc.side_effect = Exception("处理器错误")
# 触发处理
# 注:这里需要实际调用处理逻辑
# 验证状态保持为FOCUSED错误不应导致状态改变
assert subflow.chat_state.chat_status == ChatState.FOCUSED
# 验证错误后的下一次处理仍然正常
mock_proc.side_effect = None # 清除错误
mock_proc.return_value = ([], {}) # 返回空结果
# 再次触发处理
# 注:这里需要实际调用处理逻辑
# 验证状态仍然正常
assert subflow.chat_state.chat_status == ChatState.FOCUSED