Files
xieyi-weixin-/test_proactive_delete.py
2026-11-02 14:05:03 +08:00

92 lines
4.7 KiB
Python

"""Task removal preserves delivery evidence and never creates another send."""
import tempfile
import time
import unittest
from pathlib import Path
from proactive_contact_service import ContactService
from proactive_contact_scheduler import ContactScheduler
from proactive_contact_store import ContactStore
from test_proactive_contact import FakeGateway, FakeTransport
class DeleteTest(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.gateway, self.transport = FakeGateway(), FakeTransport()
self.service = ContactService(self.temp.name, self.gateway, self.transport)
def task(self, conversation='M:2'):
key = self.service.add('owner', [dict(account='1', conversation=conversation, binding_id='binding')])['added'][0]
p = self.service.preview('owner', [key], {}, text='请问下午方便联系吗?')['preview']
self.service.confirm('owner', p['id'])
return self.service.store.tasks('owner')[0]
def test_delete_unsent_batch_survives_restart_and_cannot_resume(self):
tasks = [self.task('M:2'), self.task('M:3')]
result = self.service.delete_tasks('owner', [t['id'] for t in tasks])
self.assertEqual(len(result['deleted']), 2)
store = ContactStore(self.temp.name)
self.assertEqual(store.tasks('owner'), [])
for task in tasks:
self.assertIsNone(store.claim('owner', task['id'], time.time()+100))
self.assertFalse(store.update('owner', task['id'], 'scheduled'))
ContactScheduler(self.service).tick('owner')
self.assertEqual(self.transport.sent, [])
self.assertEqual(len(store.customers('owner')), 2)
def test_delete_sent_keeps_receipt_pacing_and_dedup(self):
task = self.task()
ContactScheduler(self.service).tick('owner')
pacing = self.service.store.pacing('1', time.time())
result = self.service.delete_tasks('owner', [task['id']])
self.assertEqual(result['deleted'], [task['id']])
self.assertIsNone(self.service.store.get_task('owner', task['id']))
saved = self.service.store.get_task('owner', task['id'], include_deleted=True)
self.assertEqual(saved['status'], 'succeeded')
self.assertEqual(saved['receipt']['serverId'], 'server-1')
self.assertEqual(self.service.store.pacing('1', time.time()), pacing)
p = self.service.preview('owner', [task['customer']], {}, text=task['text'])['preview']
with self.assertRaisesRegex(ValueError, '相同内容'):
self.service.confirm('owner', p['id'])
self.assertEqual(len(self.transport.sent), 1)
self.assertEqual(self.service.delete_tasks('owner', [task['id']])['deleted'], [])
def test_mixed_batch_rejects_sending_and_foreign_ids(self):
a, b = self.task(), self.task('M:3')
self.service.store.claim('owner', a['id'], time.time()+1)
result = self.service.delete_tasks('owner', [a['id'], b['id'], 'missing'])
self.assertEqual(result['deleted'], [b['id']])
self.assertEqual(len(result['errors']), 2)
self.assertEqual(self.service.store.get_task('owner', a['id'])['status'], 'sending')
deleted, errors = self.service.store.delete_tasks('other', [a['id']])
self.assertEqual(deleted, [])
self.assertTrue(errors)
self.gateway.identity = 'other'
with self.assertRaisesRegex(ValueError, '账号已切换'):
self.service.delete_tasks('owner', [a['id']])
def test_unknown_deleted_task_can_reconcile_but_never_resend(self):
task = self.task()
claimed = self.service.store.claim('owner', task['id'], time.time()+1)
self.service.store.finish(claimed, 'delivery_unknown', error='回执未到')
self.service.delete_tasks('owner', [task['id']])
p = self.service.preview('owner', [task['customer']], {}, text=task['text'])['preview']
with self.assertRaisesRegex(ValueError, '相同内容'):
self.service.confirm('owner', p['id'])
self.transport.receipt = lambda t: dict(status='confirmed', accountId=t['account'], conversationId=t['conversation'], serverId='12', senderVerified=True, textVerified=True)
self.assertEqual(self.service.reconcile_receipts('owner'), 1)
self.assertEqual(self.service.snapshot('owner')['tasks'], [])
self.assertEqual(self.transport.sent, [])
def test_invalid_selection_does_not_delete(self):
task = self.task()
for ids in ([], None, [None], [task['id']]*101):
with self.assertRaises(ValueError):
self.service.delete_tasks('owner', ids)
self.assertEqual(len(self.service.store.tasks('owner')), 1)
if __name__ == '__main__':
unittest.main()