fix(avatar): acknowledge BOXIM messages as read

This commit is contained in:
stefanfeng
2026-08-20 17:10:54 +08:00
parent 64b7680ec4
commit e2b928273c
4 changed files with 90 additions and 1 deletions
@@ -32,6 +32,7 @@ class FakeBoxIM:
def __init__(self):
self.messages = []
self.sent = []
self.read_receipts = []
async def exchange_access_token(self, huihui_token):
assert huihui_token == "prod-huihui-token"
@@ -45,6 +46,12 @@ class FakeBoxIM:
assert access_token == "box-token"
return [item.copy() for item in self.messages if int(item["id"]) > int(min_id)]
async def mark_private_messages_read(self, access_token, friend_id, message_id):
assert access_token == "box-token"
self.read_receipts.append(
{"friendId": str(friend_id), "messageId": str(message_id)}
)
async def send_private_message(self, access_token, peer_id, content, *, local_id=None):
self.sent.append({"peerId": str(peer_id), "content": content, "localId": str(local_id)})
return {"id": 900 + len(self.sent), "localId": int(local_id)}
@@ -101,6 +108,7 @@ async def test_first_sync_primes_cursor_without_replying_to_history(service_cont
assert db.query(TakeoverMessage).count() == 1
assert db.query(TakeoverReplyTask).count() == 0
assert boxim.sent == []
assert boxim.read_receipts == [{"friendId": "200", "messageId": "10"}]
finally:
db.close()
@@ -116,6 +124,7 @@ async def test_incoming_message_is_prepared_then_sent_at_three_seconds(service_c
with patch("routers.chat._resolve_reply", return_value={"answer": "**你好**\n\n很高兴见到你"}):
await service.poll_and_process_messages()
assert boxim.sent == []
assert boxim.read_receipts == [{"friendId": "200", "messageId": "11"}]
clock.advance(2)
await service.poll_and_process_messages()
@@ -134,6 +143,40 @@ async def test_incoming_message_is_prepared_then_sent_at_three_seconds(service_c
db.close()
@pytest.mark.asyncio
async def test_read_receipt_failure_does_not_advance_cursor(service_context):
session_factory, service, boxim, clock = service_context
await service.poll_and_process_messages()
boxim.messages.append(
{"id": 12, "localId": 3, "sendId": 200, "recvId": 100, "sendTime": clock.millis(), "type": 0, "content": "未读消息"}
)
boxim.mark_private_messages_read = AsyncMock(side_effect=BoxIMError("回执失败"))
with patch("routers.chat._resolve_reply", return_value={"answer": "稍后回复"}):
await service.poll_and_process_messages()
db = session_factory()
try:
cursor = db.query(TakeoverCursor).one()
assert cursor.last_message_id == "0"
assert db.query(TakeoverMessage).count() == 0
assert db.query(TakeoverReplyTask).count() == 0
finally:
db.close()
boxim.mark_private_messages_read = AsyncMock(return_value=None)
with patch("routers.chat._resolve_reply", return_value={"answer": "稍后回复"}):
await service.poll_and_process_messages()
db = session_factory()
try:
assert db.query(TakeoverCursor).one().last_message_id == "12"
assert db.query(TakeoverMessage).count() == 1
assert db.query(TakeoverReplyTask).count() == 1
finally:
db.close()
@pytest.mark.asyncio
async def test_owner_message_cancels_pending_reply(service_context):
session_factory, service, boxim, clock = service_context