Files
kefu/wechat_rpa/test_handoff_evidence.py
T
2026-09-21 10:34:06 +08:00

98 lines
4.7 KiB
Python

"""Handoff records remain durable evidence, not a delivery confirmation."""
import json
from pathlib import Path
import tempfile
import unittest
from unittest import mock
from gui_runtime import handoff_pending_reply_file
class OfflineEvidenceTests(unittest.TestCase):
def test_legacy_visual_queue_upgrades_to_envelope_and_retains_full_evidence(self):
with tempfile.TemporaryDirectory() as tmp:
root=Path(tmp)
path=root/'pending_replies.json'
state={'stage':'receipt_check','send_state':'sent_uncommitted','reply_text':'合成发送正文','send_dispatched_at':123.0}
path.write_text(json.dumps({'task':state,'other':{'stage':'queued'}}),encoding='utf-8')
with mock.patch('queue_log.application_data_dir',return_value=root):
result=handoff_pending_reply_file(['task'],str(path),confirm_uncertain=True)
self.assertEqual(result['handed_off'],['task'])
saved=json.loads(path.read_text(encoding='utf-8'))
self.assertEqual(saved['pending'],{'other':{'stage':'queued'}})
record=saved['manual_handoffs']['task']
self.assertEqual(record['state'],state)
self.assertTrue(record['receipt_checked_by_user'])
self.assertFalse(record['delivery_confirmed'])
self.assertGreater(record['handed_off_at'],0)
def test_write_failure_preserves_original_queue_and_evidence(self):
with tempfile.TemporaryDirectory() as tmp:
root=Path(tmp)
path=root/'pending_replies.json'
original=json.dumps({'pending':{'task':{'send_state':'uncertain'}},'manual_handoffs':{'old':{'state':{}}}})
path.write_text(original,encoding='utf-8')
with mock.patch('gui_runtime.os.replace',side_effect=OSError('synthetic disk error')):
result=handoff_pending_reply_file(['task'],str(path),confirm_uncertain=True)
self.assertIn('error',result)
self.assertFalse(result['handed_off'])
self.assertEqual(path.read_text(encoding='utf-8'),original)
try:
from protocol_engine import ProtocolBot,session_key
from test_native_protocol_pipeline import Database,Sender,ACCOUNT,CONV,message
except ImportError:
ProtocolBot=None
@unittest.skipIf(ProtocolBot is None,'visual-only distribution has no protocol engine')
class ProtocolEvidenceTests(unittest.TestCase):
def setUp(self):
self.tmp=tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.root=Path(self.tmp.name)
self.db=Database();self.sender=Sender(self.db)
for patcher in (mock.patch('protocol_engine.application_data_dir',return_value=self.root),
mock.patch('queue_log.application_data_dir',return_value=self.root)):
patcher.start();self.addCleanup(patcher.stop)
self.bot=self.make_bot()
self.key=session_key(ACCOUNT,CONV)
self.state={'account':ACCOUNT,'conv_id':CONV,'stage':'receipt_check','send_state':'uncertain',
'reply_text':'可能已发送的回复','dedup_key':message()['dedup_key']}
self.bot._pending[self.key]=dict(self.state)
self.bot.needs_attention=True
self.bot._save()
def make_bot(self):
return ProtocolBot(db=self.db,sender=self.sender,identity={'accountId':ACCOUNT,'pid':1},
path=self.root/'queue.json',generate=lambda _: '合成回复',log=lambda _:None)
def test_takeover_record_survives_restart_and_poll_without_becoming_pending(self):
self.bot.handoff_pending_replies([self.key],confirm_uncertain=True)
restored=self.make_bot()
restored.poll_once()
self.assertFalse(restored._pending)
record=restored._manual_handoffs[self.key]
self.assertEqual(record['state'],self.state)
self.assertTrue(record['receipt_checked_by_user'])
self.assertFalse(record['delivery_confirmed'])
self.assertFalse(self.sender.calls)
saved=json.loads(restored.path.read_text(encoding='utf-8'))
self.assertEqual(saved['manual_handoffs'][self.key],record)
def test_failed_persist_rolls_back_memory_and_keeps_pause(self):
original=self.bot.path.read_text(encoding='utf-8')
with mock.patch.object(self.bot,'_save',side_effect=OSError('synthetic disk error')):
with self.assertRaises(OSError):
self.bot.handoff_pending_replies([self.key],confirm_uncertain=True)
self.assertEqual(self.bot._pending[self.key],self.state)
self.assertTrue(self.bot.needs_attention)
self.assertFalse(self.bot._manual_handoffs)
self.assertEqual(self.bot.path.read_text(encoding='utf-8'),original)
self.assertFalse(self.sender.calls)
if __name__=='__main__':
unittest.main()