2016-04-19 19:11:44 +03:00
|
|
|
#
|
2023-11-21 23:29:58 +03:00
|
|
|
# This file is licensed under the Affero General Public License (AGPL) version 3.
|
|
|
|
#
|
2024-01-23 14:26:48 +03:00
|
|
|
# Copyright 2016 OpenMarket Ltd
|
2023-11-21 23:29:58 +03:00
|
|
|
# Copyright (C) 2023 New Vector, Ltd
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU Affero General Public License as
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# See the GNU Affero General Public License for more details:
|
|
|
|
# <https://www.gnu.org/licenses/agpl-3.0.html>.
|
|
|
|
#
|
|
|
|
# Originally licensed under the Apache License, Version 2.0:
|
|
|
|
# <http://www.apache.org/licenses/LICENSE-2.0>.
|
|
|
|
#
|
|
|
|
# [This file includes modifications made by New Vector Limited]
|
2016-04-19 19:11:44 +03:00
|
|
|
#
|
|
|
|
#
|
|
|
|
|
2022-09-29 14:07:31 +03:00
|
|
|
from typing import Collection, Optional
|
2022-08-05 18:09:33 +03:00
|
|
|
|
2022-12-09 20:36:32 +03:00
|
|
|
from twisted.test.proto_helpers import MemoryReactor
|
|
|
|
|
2022-04-28 20:34:12 +03:00
|
|
|
from synapse.api.constants import ReceiptTypes
|
2022-12-09 20:36:32 +03:00
|
|
|
from synapse.server import HomeServer
|
2022-05-04 18:59:22 +03:00
|
|
|
from synapse.types import UserID, create_requester
|
2022-12-09 20:36:32 +03:00
|
|
|
from synapse.util import Clock
|
2022-05-04 18:59:22 +03:00
|
|
|
|
|
|
|
from tests.test_utils.event_injection import create_event
|
2022-07-21 20:56:45 +03:00
|
|
|
from tests.unittest import HomeserverTestCase
|
2016-04-19 19:11:44 +03:00
|
|
|
|
2022-05-04 18:59:22 +03:00
|
|
|
OTHER_USER_ID = "@other:test"
|
|
|
|
OUR_USER_ID = "@our:test"
|
2016-04-19 19:11:44 +03:00
|
|
|
|
|
|
|
|
2022-07-21 20:56:45 +03:00
|
|
|
class ReceiptTestCase(HomeserverTestCase):
|
2022-12-09 20:36:32 +03:00
|
|
|
def prepare(
|
|
|
|
self, reactor: MemoryReactor, clock: Clock, homeserver: HomeServer
|
|
|
|
) -> None:
|
2022-05-04 18:59:22 +03:00
|
|
|
super().prepare(reactor, clock, homeserver)
|
2022-07-21 20:56:45 +03:00
|
|
|
|
|
|
|
self.store = homeserver.get_datastores().main
|
|
|
|
|
2022-05-04 18:59:22 +03:00
|
|
|
self.room_creator = homeserver.get_room_creation_handler()
|
2023-02-14 22:03:35 +03:00
|
|
|
persist_event_storage_controller = self.hs.get_storage_controllers().persistence
|
|
|
|
assert persist_event_storage_controller is not None
|
|
|
|
self.persist_event_storage_controller = persist_event_storage_controller
|
2022-05-04 18:59:22 +03:00
|
|
|
|
|
|
|
# Create a test user
|
|
|
|
self.ourUser = UserID.from_string(OUR_USER_ID)
|
|
|
|
self.ourRequester = create_requester(self.ourUser)
|
|
|
|
|
|
|
|
# Create a second test user
|
|
|
|
self.otherUser = UserID.from_string(OTHER_USER_ID)
|
|
|
|
self.otherRequester = create_requester(self.otherUser)
|
|
|
|
|
|
|
|
# Create a test room
|
2023-02-22 14:07:28 +03:00
|
|
|
self.room_id1, _, _ = self.get_success(
|
|
|
|
self.room_creator.create_room(self.ourRequester, {})
|
|
|
|
)
|
2022-05-04 18:59:22 +03:00
|
|
|
|
|
|
|
# Create a second test room
|
2023-02-22 14:07:28 +03:00
|
|
|
self.room_id2, _, _ = self.get_success(
|
|
|
|
self.room_creator.create_room(self.ourRequester, {})
|
|
|
|
)
|
2022-05-04 18:59:22 +03:00
|
|
|
|
|
|
|
# Join the second user to the first room
|
|
|
|
memberEvent, memberEventContext = self.get_success(
|
|
|
|
create_event(
|
|
|
|
self.hs,
|
|
|
|
room_id=self.room_id1,
|
|
|
|
type="m.room.member",
|
|
|
|
sender=self.otherRequester.user.to_string(),
|
|
|
|
state_key=self.otherRequester.user.to_string(),
|
|
|
|
content={"membership": "join"},
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.get_success(
|
2022-05-31 15:17:50 +03:00
|
|
|
self.persist_event_storage_controller.persist_event(
|
|
|
|
memberEvent, memberEventContext
|
|
|
|
)
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
# Join the second user to the second room
|
|
|
|
memberEvent, memberEventContext = self.get_success(
|
|
|
|
create_event(
|
|
|
|
self.hs,
|
|
|
|
room_id=self.room_id2,
|
|
|
|
type="m.room.member",
|
|
|
|
sender=self.otherRequester.user.to_string(),
|
|
|
|
state_key=self.otherRequester.user.to_string(),
|
|
|
|
content={"membership": "join"},
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.get_success(
|
2022-05-31 15:17:50 +03:00
|
|
|
self.persist_event_storage_controller.persist_event(
|
|
|
|
memberEvent, memberEventContext
|
|
|
|
)
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
|
2022-09-29 14:07:31 +03:00
|
|
|
def get_last_unthreaded_receipt(
|
|
|
|
self, receipt_types: Collection[str], room_id: Optional[str] = None
|
|
|
|
) -> Optional[str]:
|
|
|
|
"""
|
|
|
|
Fetch the event ID for the latest unthreaded receipt in the test room for the test user.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
receipt_types: The receipt types to fetch.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
The latest receipt, if one exists.
|
|
|
|
"""
|
|
|
|
result = self.get_success(
|
|
|
|
self.store.db_pool.runInteraction(
|
|
|
|
"get_last_receipt_event_id_for_user",
|
|
|
|
self.store.get_last_unthreaded_receipt_for_user_txn,
|
|
|
|
OUR_USER_ID,
|
|
|
|
room_id or self.room_id1,
|
|
|
|
receipt_types,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
if not result:
|
|
|
|
return None
|
|
|
|
|
|
|
|
event_id, _ = result
|
|
|
|
return event_id
|
|
|
|
|
2022-08-05 18:09:33 +03:00
|
|
|
def test_return_empty_with_no_data(self) -> None:
|
2022-05-04 18:59:22 +03:00
|
|
|
res = self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.get_receipts_for_user(
|
2022-08-05 18:09:33 +03:00
|
|
|
OUR_USER_ID,
|
|
|
|
[
|
|
|
|
ReceiptTypes.READ,
|
|
|
|
ReceiptTypes.READ_PRIVATE,
|
|
|
|
],
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertEqual(res, {})
|
|
|
|
|
|
|
|
res = self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.get_receipts_for_user_with_orderings(
|
2022-05-04 18:59:22 +03:00
|
|
|
OUR_USER_ID,
|
2022-08-05 18:09:33 +03:00
|
|
|
[
|
|
|
|
ReceiptTypes.READ,
|
|
|
|
ReceiptTypes.READ_PRIVATE,
|
|
|
|
],
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertEqual(res, {})
|
|
|
|
|
2022-12-09 20:36:32 +03:00
|
|
|
res2 = self.get_last_unthreaded_receipt(
|
2022-09-29 14:07:31 +03:00
|
|
|
[ReceiptTypes.READ, ReceiptTypes.READ_PRIVATE]
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
2022-09-29 14:07:31 +03:00
|
|
|
|
2022-12-09 20:36:32 +03:00
|
|
|
self.assertIsNone(res2)
|
2022-05-04 18:59:22 +03:00
|
|
|
|
2022-09-01 15:31:54 +03:00
|
|
|
def test_get_receipts_for_user(self) -> None:
|
2022-05-04 18:59:22 +03:00
|
|
|
# Send some events into the first room
|
|
|
|
event1_1_id = self.create_and_send_event(
|
|
|
|
self.room_id1, UserID.from_string(OTHER_USER_ID)
|
|
|
|
)
|
|
|
|
event1_2_id = self.create_and_send_event(
|
|
|
|
self.room_id1, UserID.from_string(OTHER_USER_ID)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Send public read receipt for the first event
|
|
|
|
self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.insert_receipt(
|
2022-09-23 17:33:28 +03:00
|
|
|
self.room_id1, ReceiptTypes.READ, OUR_USER_ID, [event1_1_id], None, {}
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
# Send private read receipt for the second event
|
2018-09-03 19:21:48 +03:00
|
|
|
self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.insert_receipt(
|
2022-09-23 17:33:28 +03:00
|
|
|
self.room_id1,
|
|
|
|
ReceiptTypes.READ_PRIVATE,
|
|
|
|
OUR_USER_ID,
|
|
|
|
[event1_2_id],
|
|
|
|
None,
|
|
|
|
{},
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Test we get the latest event when we want both private and public receipts
|
|
|
|
res = self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.get_receipts_for_user(
|
2022-09-01 15:31:54 +03:00
|
|
|
OUR_USER_ID, [ReceiptTypes.READ, ReceiptTypes.READ_PRIVATE]
|
2022-04-28 20:34:12 +03:00
|
|
|
)
|
2016-04-19 19:11:44 +03:00
|
|
|
)
|
2022-05-04 18:59:22 +03:00
|
|
|
self.assertEqual(res, {self.room_id1: event1_2_id})
|
|
|
|
|
|
|
|
# Test we get the older event when we want only public receipt
|
|
|
|
res = self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.get_receipts_for_user(OUR_USER_ID, [ReceiptTypes.READ])
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
self.assertEqual(res, {self.room_id1: event1_1_id})
|
|
|
|
|
|
|
|
# Test we get the latest event when we want only the public receipt
|
|
|
|
res = self.get_success(
|
2022-09-01 15:31:54 +03:00
|
|
|
self.store.get_receipts_for_user(OUR_USER_ID, [ReceiptTypes.READ_PRIVATE])
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
self.assertEqual(res, {self.room_id1: event1_2_id})
|
|
|
|
|
|
|
|
# Test receipt updating
|
|
|
|
self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.insert_receipt(
|
2022-09-23 17:33:28 +03:00
|
|
|
self.room_id1, ReceiptTypes.READ, OUR_USER_ID, [event1_2_id], None, {}
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
res = self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.get_receipts_for_user(OUR_USER_ID, [ReceiptTypes.READ])
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
self.assertEqual(res, {self.room_id1: event1_2_id})
|
|
|
|
|
|
|
|
# Send some events into the second room
|
|
|
|
event2_1_id = self.create_and_send_event(
|
|
|
|
self.room_id2, UserID.from_string(OTHER_USER_ID)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Test new room is reflected in what the method returns
|
|
|
|
self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.insert_receipt(
|
2022-09-23 17:33:28 +03:00
|
|
|
self.room_id2,
|
|
|
|
ReceiptTypes.READ_PRIVATE,
|
|
|
|
OUR_USER_ID,
|
|
|
|
[event2_1_id],
|
|
|
|
None,
|
|
|
|
{},
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
res = self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.get_receipts_for_user(
|
2022-09-01 15:31:54 +03:00
|
|
|
OUR_USER_ID, [ReceiptTypes.READ, ReceiptTypes.READ_PRIVATE]
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertEqual(res, {self.room_id1: event1_2_id, self.room_id2: event2_1_id})
|
|
|
|
|
2022-09-01 15:31:54 +03:00
|
|
|
def test_get_last_receipt_event_id_for_user(self) -> None:
|
2022-05-04 18:59:22 +03:00
|
|
|
# Send some events into the first room
|
|
|
|
event1_1_id = self.create_and_send_event(
|
|
|
|
self.room_id1, UserID.from_string(OTHER_USER_ID)
|
|
|
|
)
|
|
|
|
event1_2_id = self.create_and_send_event(
|
|
|
|
self.room_id1, UserID.from_string(OTHER_USER_ID)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Send public read receipt for the first event
|
|
|
|
self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.insert_receipt(
|
2022-09-23 17:33:28 +03:00
|
|
|
self.room_id1, ReceiptTypes.READ, OUR_USER_ID, [event1_1_id], None, {}
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
# Send private read receipt for the second event
|
|
|
|
self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.insert_receipt(
|
2022-09-23 17:33:28 +03:00
|
|
|
self.room_id1,
|
|
|
|
ReceiptTypes.READ_PRIVATE,
|
|
|
|
OUR_USER_ID,
|
|
|
|
[event1_2_id],
|
|
|
|
None,
|
|
|
|
{},
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Test we get the latest event when we want both private and public receipts
|
2022-09-29 14:07:31 +03:00
|
|
|
res = self.get_last_unthreaded_receipt(
|
|
|
|
[ReceiptTypes.READ, ReceiptTypes.READ_PRIVATE]
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
self.assertEqual(res, event1_2_id)
|
|
|
|
|
|
|
|
# Test we get the older event when we want only public receipt
|
2022-09-29 14:07:31 +03:00
|
|
|
res = self.get_last_unthreaded_receipt([ReceiptTypes.READ])
|
2022-05-04 18:59:22 +03:00
|
|
|
self.assertEqual(res, event1_1_id)
|
|
|
|
|
|
|
|
# Test we get the latest event when we want only the private receipt
|
2022-09-29 14:07:31 +03:00
|
|
|
res = self.get_last_unthreaded_receipt([ReceiptTypes.READ_PRIVATE])
|
2022-05-04 18:59:22 +03:00
|
|
|
self.assertEqual(res, event1_2_id)
|
|
|
|
|
|
|
|
# Test receipt updating
|
|
|
|
self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.insert_receipt(
|
2022-09-23 17:33:28 +03:00
|
|
|
self.room_id1, ReceiptTypes.READ, OUR_USER_ID, [event1_2_id], None, {}
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
2022-09-29 14:07:31 +03:00
|
|
|
res = self.get_last_unthreaded_receipt([ReceiptTypes.READ])
|
2022-05-04 18:59:22 +03:00
|
|
|
self.assertEqual(res, event1_2_id)
|
|
|
|
|
|
|
|
# Send some events into the second room
|
|
|
|
event2_1_id = self.create_and_send_event(
|
|
|
|
self.room_id2, UserID.from_string(OTHER_USER_ID)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Test new room is reflected in what the method returns
|
|
|
|
self.get_success(
|
2022-07-21 20:56:45 +03:00
|
|
|
self.store.insert_receipt(
|
2022-09-23 17:33:28 +03:00
|
|
|
self.room_id2,
|
|
|
|
ReceiptTypes.READ_PRIVATE,
|
|
|
|
OUR_USER_ID,
|
|
|
|
[event2_1_id],
|
|
|
|
None,
|
|
|
|
{},
|
2022-05-04 18:59:22 +03:00
|
|
|
)
|
|
|
|
)
|
2022-09-29 14:07:31 +03:00
|
|
|
res = self.get_last_unthreaded_receipt(
|
|
|
|
[ReceiptTypes.READ, ReceiptTypes.READ_PRIVATE], room_id=self.room_id2
|
2022-04-28 20:34:12 +03:00
|
|
|
)
|
2022-05-04 18:59:22 +03:00
|
|
|
self.assertEqual(res, event2_1_id)
|