Files
kefu/wechat_rpa/tmp/test_pending_expire.py
T
2026-08-27 14:04:28 +08:00

99 lines
3.8 KiB
Python

"""验证 _expire_unreachable_pending 的快速放弃逻辑。
覆盖场景:
1. 有 staged_reply_text 的任务:失败 >=3 次即放弃(阈值 3)
2. 有 staged_reply_text 的任务:失败 <3 次保留
3. 无 staged_reply_text 的任务:失败 <8 次保留(原阈值 8)
4. 无 staged_reply_text 的任务:失败 >=8 次放弃
5. 放弃后任务从队列移除(_clear_reply_pending 被调用)
6. 放弃后不落档(_commit_staged_exchange 不被调用)
"""
import os
import sys
import time
from unittest import mock
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + "/..")
from wechat_bot import WeChatBot # noqa: E402
def make_bot():
bot = WeChatBot.__new__(WeChatBot)
bot._pending_lock = None
bot._pending_reply_sessions = {}
bot._pending_reply_path = ""
bot._pending_scan_progress = {}
bot._pending_exchanges = {}
bot._cancelled_reply_sessions = set()
bot._unrepliable_sessions = {}
bot._uncertain_tracking = {}
bot._last_send_receipt_visible_text = ""
bot._reset_pending_batch = lambda fp: None
bot._forget_uncertain_tracking = lambda fp: None
bot._persist_pending_replies = lambda: None
bot._persist_unrepliable_sessions = lambda: None
bot.store = mock.MagicMock()
bot.remember_exchange = mock.MagicMock()
bot._commit_staged_exchange = mock.MagicMock()
return bot
def run():
passed = 0
def check(name, cond):
nonlocal passed
if cond:
passed += 1
print(f" [PASS] {name}")
else:
print(f" [FAIL] {name}")
print("== 有 AI 回复的任务快速放弃 ==")
bot = make_bot()
fp = bytes.fromhex("a1" * 20)
# 失败 2 次 + 有回复 → 保留
state = {"resume_failures": 2, "staged_reply_text": "在呢,有什么事你慢慢说"}
bot._pending_reply_sessions[fp.hex()] = state
r = bot._expire_unreachable_pending(fp, state)
check("staged 回复失败2次 → 保留", r is False and fp.hex() in bot._pending_reply_sessions)
# 失败 3 次 + 有回复 → 放弃
state["resume_failures"] = 3
r = bot._expire_unreachable_pending(fp, state)
check("staged 回复失败3次 → 放弃", r is True and fp.hex() not in bot._pending_reply_sessions)
check("放弃时不落档(回复未发出)", bot._commit_staged_exchange.call_count == 0)
print("== 纯定位任务保持原阈值 8 ==")
bot = make_bot()
fp2 = bytes.fromhex("b2" * 20)
state2 = {"resume_failures": 7} # 无 staged_reply_text
bot._pending_reply_sessions[fp2.hex()] = state2
r = bot._expire_unreachable_pending(fp2, state2)
check("无回复失败7次 → 保留", r is False and fp2.hex() in bot._pending_reply_sessions)
state2["resume_failures"] = 8
r = bot._expire_unreachable_pending(fp2, state2)
check("无回复失败8次 → 放弃", r is True and fp2.hex() not in bot._pending_reply_sessions)
print("== 边界与异常 ==")
bot = make_bot()
fp3 = bytes.fromhex("c3" * 20)
state3 = {"resume_failures": "invalid", "staged_reply_text": " "}
bot._pending_reply_sessions[fp3.hex()] = state3
r = bot._expire_unreachable_pending(fp3, state3)
check("非法 failures 且空回复 → 按0处理保留", r is False and fp3.hex() in bot._pending_reply_sessions)
bot = make_bot()
fp4 = bytes.fromhex("d4" * 20)
state4 = {"resume_failures": 3, "staged_reply_text": " ", "reply_text": "x"}
bot._pending_reply_sessions[fp4.hex()] = state4
r = bot._expire_unreachable_pending(fp4, state4)
check("空白 staged 回复按纯定位处理(3次保留)", r is False and fp4.hex() in bot._pending_reply_sessions)
print(f"\n结果: {passed}/7 通过")
return passed == 7
if __name__ == "__main__":
ok = run()
sys.exit(0 if ok else 1)