diff --git a/tests/rest/client/sliding_sync/test_server_announcements.py b/tests/rest/client/sliding_sync/test_server_announcements.py index 760e72e3f7..2de5b1e650 100644 --- a/tests/rest/client/sliding_sync/test_server_announcements.py +++ b/tests/rest/client/sliding_sync/test_server_announcements.py @@ -21,7 +21,7 @@ from synapse.api.constants import EventTypes, Membership, ReceiptTypes, Relation from synapse.config.server_announcements import ServerAnnouncementRoom from synapse.handlers.server_announcements import SYNTHETIC_JOIN_EVENT_ID_PREFIX from synapse.handlers.sliding_sync import StateValues -from synapse.rest.client import devices, login, receipts, room, sync +from synapse.rest.client import devices, login, read_marker, receipts, room, sync from synapse.server import HomeServer from synapse.types import JsonDict from synapse.util.clock import Clock @@ -50,6 +50,7 @@ class SlidingSyncServerAnnouncementsTestCase(SlidingSyncBase): room.register_servlets, sync.register_servlets, devices.register_servlets, + read_marker.register_servlets, receipts.register_servlets, ] @@ -589,6 +590,15 @@ class SlidingSyncServerAnnouncementsTestCase(SlidingSyncBase): ) self.assertEqual(channel.code, 200, channel.json_body) + def _set_read_markers(self, event_id: str, tok: str) -> None: + channel = self.make_request( + "POST", + f"/rooms/{self.room_id}/read_markers", + {ReceiptTypes.FULLY_READ: event_id, ReceiptTypes.READ: event_id}, + access_token=tok, + ) + self.assertEqual(channel.code, 200, channel.json_body) + def _receipts_sync_body(self) -> JsonDict: sync_body = self._sync_body() sync_body["extensions"] = {"receipts": {"enabled": True}} @@ -751,3 +761,33 @@ class SlidingSyncServerAnnouncementsTestCase(SlidingSyncBase): response, _ = self.do_sync(self._receipts_sync_body(), tok=tok) self.assertIn(self.room_id, response["rooms"]) self.assertEqual(self._receipt_readers(response, reply_id), set()) + + def test_non_member_read_markers_receipt_on_other_device(self) -> None: + """The read receipt a non-member sets with `/read_markers` is sent to an + existing and a new connection of their other devices. + """ + event_id = self._announce("hello") + _, pos = self.do_sync(self._receipts_sync_body(), tok=self.bob_other_tok) + + self._set_read_markers(event_id, self.bob_tok) + + response, _ = self.do_sync( + self._receipts_sync_body(), since=pos, tok=self.bob_other_tok + ) + self.assertEqual(self._receipt_readers(response, event_id), {self.bob}) + + response, _ = self.do_sync(self._receipts_sync_body(), tok=self.bob_other_tok) + self.assertEqual(self._receipt_readers(response, event_id), {self.bob}) + + def test_non_member_read_markers_receipt_hidden_from_other_users(self) -> None: + """The read receipt a non-member sets with `/read_markers` is not sent to + a member of the announcement room, nor to another non-member. + """ + event_id = self._announce("hello") + + self._set_read_markers(event_id, self.bob_tok) + + for tok in (self.announcer_tok, self.dan_tok): + response, _ = self.do_sync(self._receipts_sync_body(), tok=tok) + self.assertIn(self.room_id, response["rooms"]) + self.assertEqual(self._receipt_readers(response, event_id), set()) diff --git a/tests/rest/client/test_receipts.py b/tests/rest/client/test_receipts.py index 9391d82552..f3bb98f573 100644 --- a/tests/rest/client/test_receipts.py +++ b/tests/rest/client/test_receipts.py @@ -32,7 +32,7 @@ from synapse.api.constants import ( ) from synapse.api.errors import Codes from synapse.config.server_announcements import ServerAnnouncementRoom -from synapse.rest.client import login, receipts, room, sync +from synapse.rest.client import login, read_marker, receipts, room, sync from synapse.server import HomeServer from synapse.types import JsonDict from synapse.util.clock import Clock @@ -437,6 +437,7 @@ class ServerAnnouncementsReceiptsTestCase(unittest.HomeserverTestCase): servlets = [ synapse.rest.admin.register_servlets, login.register_servlets, + read_marker.register_servlets, receipts.register_servlets, room.register_servlets, sync.register_servlets, @@ -523,6 +524,15 @@ class ServerAnnouncementsReceiptsTestCase(unittest.HomeserverTestCase): ) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) + def _set_read_markers(self, event_id: str, tok: str) -> None: + channel = self.make_request( + "POST", + f"/rooms/{self.room_id}/read_markers", + {ReceiptTypes.FULLY_READ: event_id, ReceiptTypes.READ: event_id}, + access_token=tok, + ) + self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) + def _sync(self, tok: str, since: str | None = None) -> JsonDict: url = "/sync" if since is None else f"/sync?since={since}" channel = self.make_request("GET", url, access_token=tok) @@ -713,3 +723,53 @@ class ServerAnnouncementsReceiptsTestCase(unittest.HomeserverTestCase): response = self._sync(tok) self._assert_room_in_sync(response) self.assertEqual(self._receipt_readers(response, reply_id), set()) + + def test_non_member_sets_read_markers(self) -> None: + """A user who is not a member of the announcement room can set their + fully read marker and read receipt on an announcement with + `/read_markers`. + """ + event_id = self._announce("hello") + + self._set_read_markers(event_id, self.bob_tok) + + fully_read = self.get_success( + self.store.get_account_data_for_room_and_type( + self.bob, self.room_id, ReceiptTypes.FULLY_READ + ) + ) + self.assertEqual(fully_read, {"event_id": event_id}) + receipts = self.get_success( + self.store.get_receipts_for_user(self.bob, [ReceiptTypes.READ]) + ) + self.assertEqual(receipts, {self.room_id: event_id}) + + def test_non_member_read_markers_receipt_on_sync_of_other_device(self) -> None: + """The read receipt a non-member sets with `/read_markers` is in the + initial and next incremental sync of their other devices. + """ + event_id = self._announce("hello") + since = self._sync(self.bob_other_tok)["next_batch"] + + self._set_read_markers(event_id, self.bob_tok) + + for response in ( + self._sync(self.bob_other_tok), + self._sync(self.bob_other_tok, since), + ): + self.assertEqual(self._receipt_readers(response, event_id), {self.bob}) + + def test_non_member_read_markers_receipt_hidden_from_other_users_sync( + self, + ) -> None: + """The read receipt a non-member sets with `/read_markers` is not in the + sync of a member of the announcement room, nor of another non-member. + """ + event_id = self._announce("hello") + + self._set_read_markers(event_id, self.bob_tok) + + for tok in (self.announcer_tok, self.dan_tok): + response = self._sync(tok) + self._assert_room_in_sync(response) + self.assertEqual(self._receipt_readers(response, event_id), set())