mirror of
https://github.com/zhinianboke/xianyu-auto-reply.git
synced 2025-08-02 20:47:35 +08:00
169 lines
6.4 KiB
Python
169 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
测试重复通知修复
|
||
验证Token刷新失败时不会发送重复通知
|
||
"""
|
||
|
||
import asyncio
|
||
import time
|
||
from unittest.mock import AsyncMock, patch, MagicMock
|
||
import sys
|
||
import os
|
||
|
||
# 添加项目根目录到路径
|
||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
async def test_duplicate_notification_fix():
|
||
"""测试重复通知修复"""
|
||
print("🧪 测试Token刷新失败重复通知修复")
|
||
print("=" * 60)
|
||
|
||
# 动态导入,避免配置问题
|
||
try:
|
||
from XianyuAutoAsync import XianyuLive
|
||
print("✅ 成功导入 XianyuLive")
|
||
except Exception as e:
|
||
print(f"❌ 导入失败: {e}")
|
||
return
|
||
|
||
# 创建测试用的XianyuLive实例
|
||
test_cookies = "unb=test123; _m_h5_tk=test_token_123456789"
|
||
|
||
try:
|
||
xianyu = XianyuLive(test_cookies, "test_account")
|
||
print("✅ XianyuLive 实例创建成功")
|
||
except Exception as e:
|
||
print(f"❌ 创建 XianyuLive 实例失败: {e}")
|
||
return
|
||
|
||
# Mock外部依赖
|
||
with patch('XianyuAutoAsync.db_manager') as mock_db, \
|
||
patch('aiohttp.ClientSession') as mock_session:
|
||
|
||
# 配置数据库mock
|
||
mock_db.get_account_notifications.return_value = [
|
||
{
|
||
'enabled': True,
|
||
'channel_type': 'qq',
|
||
'channel_name': 'Test QQ',
|
||
'channel_config': {'qq_number': '123456', 'api_url': 'http://test.com'}
|
||
}
|
||
]
|
||
|
||
# Mock HTTP session
|
||
mock_response = MagicMock()
|
||
mock_response.status = 200
|
||
mock_response.text = AsyncMock(return_value='{"ret": ["FAIL_SYS_SESSION_EXPIRED::Session过期"]}')
|
||
mock_session_instance = AsyncMock()
|
||
mock_session_instance.post.return_value.__aenter__.return_value = mock_response
|
||
mock_session.return_value = mock_session_instance
|
||
xianyu.session = mock_session_instance
|
||
|
||
# Mock QQ通知发送方法
|
||
xianyu._send_qq_notification = AsyncMock()
|
||
|
||
print("\n📋 测试场景: Cookie过期导致Token刷新失败")
|
||
print("-" * 40)
|
||
|
||
# 重置状态
|
||
xianyu.current_token = None
|
||
xianyu.last_token_refresh_time = 0
|
||
xianyu._send_qq_notification.reset_mock()
|
||
|
||
print("1️⃣ 模拟 init() 方法调用...")
|
||
|
||
# 创建一个mock websocket
|
||
mock_ws = MagicMock()
|
||
|
||
try:
|
||
# 调用init方法,这会触发refresh_token,然后检查token
|
||
await xianyu.init(mock_ws)
|
||
except Exception as e:
|
||
print(f" 预期的异常: {e}")
|
||
|
||
# 检查通知发送次数
|
||
call_count = xianyu._send_qq_notification.call_count
|
||
print(f"\n📊 通知发送统计:")
|
||
print(f" 总调用次数: {call_count}")
|
||
|
||
if call_count == 1:
|
||
print(" ✅ 成功!只发送了一次通知")
|
||
print(" 💡 说明: refresh_token失败后,init不会发送重复通知")
|
||
elif call_count == 2:
|
||
print(" ❌ 失败!发送了两次重复通知")
|
||
print(" 🔧 需要进一步优化防重复机制")
|
||
elif call_count == 0:
|
||
print(" ⚠️ 没有发送通知(可能是mock配置问题)")
|
||
else:
|
||
print(f" ❓ 异常的调用次数: {call_count}")
|
||
|
||
# 显示调用详情
|
||
if xianyu._send_qq_notification.call_args_list:
|
||
print(f"\n📝 通知调用详情:")
|
||
for i, call in enumerate(xianyu._send_qq_notification.call_args_list, 1):
|
||
args, kwargs = call
|
||
if len(args) >= 2:
|
||
message = args[1]
|
||
# 提取关键信息
|
||
if "异常信息:" in message:
|
||
error_info = message.split("异常信息:")[1].split("\n")[0].strip()
|
||
print(f" 第{i}次: {error_info}")
|
||
|
||
print("\n🔍 防重复机制分析:")
|
||
print(" • 方案1: 时间冷却期 - 5分钟内不重复发送相同类型通知")
|
||
print(" • 方案2: 逻辑判断 - init()检查是否刚刚尝试过refresh_token")
|
||
print(" • 当前使用: 方案2 (更精确,避免逻辑重复)")
|
||
|
||
print(f"\n⏰ 通知时间记录:")
|
||
for notification_type, last_time in xianyu.last_notification_time.items():
|
||
print(f" {notification_type}: {time.strftime('%H:%M:%S', time.localtime(last_time))}")
|
||
|
||
def show_optimization_summary():
|
||
"""显示优化总结"""
|
||
print("\n\n📋 优化总结")
|
||
print("=" * 60)
|
||
|
||
print("🎯 问题描述:")
|
||
print(" 用户反馈每次Token刷新异常都会收到两个相同的通知")
|
||
|
||
print("\n🔍 问题根因:")
|
||
print(" 1. refresh_token() 失败时发送第一次通知")
|
||
print(" 2. init() 检查 current_token 为空时发送第二次通知")
|
||
print(" 3. 两次通知内容基本相同,造成用户困扰")
|
||
|
||
print("\n🛠️ 解决方案:")
|
||
print(" 方案A: 添加通知防重复机制")
|
||
print(" • 为不同场景使用不同的通知类型")
|
||
print(" • 设置5分钟冷却期,避免短时间重复通知")
|
||
print(" • 保留详细的错误信息用于调试")
|
||
|
||
print("\n 方案B: 优化逻辑判断")
|
||
print(" • 在 init() 中跟踪是否刚刚尝试过 refresh_token")
|
||
print(" • 如果刚刚尝试过且失败,则不发送重复通知")
|
||
print(" • 更精确地避免逻辑重复")
|
||
|
||
print("\n✅ 实施的优化:")
|
||
print(" • 采用方案A + 方案B的组合")
|
||
print(" • 添加了通知防重复机制(时间冷却)")
|
||
print(" • 优化了 init() 方法的逻辑判断")
|
||
print(" • 为不同错误场景使用不同的通知类型")
|
||
|
||
print("\n🎉 预期效果:")
|
||
print(" • 用户只会收到一次Token刷新异常通知")
|
||
print(" • 通知内容更加精确,便于问题定位")
|
||
print(" • 避免了通知轰炸,改善用户体验")
|
||
print(" • 保留了完整的错误信息用于调试")
|
||
|
||
if __name__ == "__main__":
|
||
try:
|
||
asyncio.run(test_duplicate_notification_fix())
|
||
show_optimization_summary()
|
||
|
||
print("\n" + "=" * 60)
|
||
print("🎊 Token刷新重复通知修复测试完成!")
|
||
|
||
except Exception as e:
|
||
print(f"❌ 测试过程中发生错误: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|