From d97a7fed081d42ed024ee574b7e48394ff0f91db Mon Sep 17 00:00:00 2001 From: FrenchGithubUser Date: Thu, 5 Feb 2026 16:31:59 +0100 Subject: [PATCH 1/2] test --- .../storage/databases/main/registration.py | 6 +- tests/rest/client/test_read_marker.py | 76 ++++++++++++++++++- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/synapse/storage/databases/main/registration.py b/synapse/storage/databases/main/registration.py index c99faa29ca..0082ecbede 100644 --- a/synapse/storage/databases/main/registration.py +++ b/synapse/storage/databases/main/registration.py @@ -2589,7 +2589,6 @@ def user_delete_access_tokens_for_devices_txn( """ txn.execute(sql, args) tokens_and_devices = txn.fetchall() - self._invalidate_cache_and_stream_bulk( txn, self.get_user_by_access_token, @@ -2605,7 +2604,10 @@ def user_delete_access_tokens_for_devices_txn( batch_device_ids, ) results.extend(tokens_and_devices) - + # Print after transaction completes (cache invalidation has happened) + if tokens_and_devices: + print(tokens_and_devices) + print(self.get_user_by_access_token(tokens_and_devices[0][0])) return results async def delete_access_token(self, access_token: str) -> None: diff --git a/tests/rest/client/test_read_marker.py b/tests/rest/client/test_read_marker.py index c8bb0da5e6..1dd2a2f2bf 100644 --- a/tests/rest/client/test_read_marker.py +++ b/tests/rest/client/test_read_marker.py @@ -18,12 +18,13 @@ # [This file includes modifications made by New Vector Limited] # # + from twisted.internet.testing import MemoryReactor import synapse.rest.admin from synapse.api.constants import EventTypes from synapse.rest import admin -from synapse.rest.client import login, read_marker, register, room +from synapse.rest.client import devices, login, read_marker, register, room from synapse.server import HomeServer from synapse.util.clock import Clock @@ -39,6 +40,7 @@ class ReadMarkerTestCase(unittest.HomeserverTestCase): register.register_servlets, read_marker.register_servlets, room.register_servlets, + devices.register_servlets, synapse.rest.admin.register_servlets, admin.register_servlets, ] @@ -149,3 +151,75 @@ def send_message() -> str: access_token=self.owner_tok, ) self.assertEqual(channel.code, 200, channel.result) + + def test_deleted_device_cannot_set_read_marker_or_send_message(self) -> None: + """ + Test that a deleted device cannot set a read marker or send a message. + """ + # Register a user and login with a specific device_id + user_id = self.register_user("testuser", "password") + device_id = "TEST_DEVICE_123" + access_token = self.login("testuser", "password", device_id=device_id) + print("access token: ", access_token) + + # Create a room + room_id = self.helper.create_room_as(user_id, tok=access_token) + + # Send a message + message_result = self.helper.send( + room_id=room_id, body="Hello", tok=access_token + ) + event_id = message_result["event_id"] + + # Delete the device + channel = self.make_request( + "DELETE", + f"devices/{device_id}", + access_token=access_token, + ) + + # If UI auth is required, provide it + if channel.code == 401: + session = channel.json_body["session"] + channel = self.make_request( + "DELETE", + f"devices/{device_id}", + access_token=access_token, + content={ + "auth": { + "type": "m.login.password", + "user": "testuser", + "password": "password", + "session": session, + }, + }, + ) + + self.assertEqual(channel.code, 200, channel.result) + + # Try to set a read marker with the deleted device's token + channel = self.make_request( + "POST", + f"/rooms/{room_id}/read_markers", + content={ + "m.fully_read": event_id, + }, + access_token=access_token, + ) + # Should fail with 401 (unauthorized) since the device is deleted + self.assertEqual(channel.code, 401, channel.result) + self.assertEqual(channel.json_body["errcode"], "M_UNKNOWN_TOKEN") + + # Try to send a message with the deleted device's token + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/send/m.room.message/test_msg", + content={ + "msgtype": "m.text", + "body": "This should fail", + }, + access_token=access_token, + ) + # Should fail with 401 (unauthorized) since the device is deleted + self.assertEqual(channel.code, 401, channel.result) + self.assertEqual(channel.json_body["errcode"], "M_UNKNOWN_TOKEN") From 141df8d1dad6a18bb4f2a924536ef34aca982ce7 Mon Sep 17 00:00:00 2001 From: FrenchGithubUser Date: Thu, 5 Feb 2026 16:59:05 +0100 Subject: [PATCH 2/2] use 2 workers in tests --- .../storage/databases/main/registration.py | 2 +- tests/rest/client/test_read_marker.py | 79 ++++++++++++++++--- 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/synapse/storage/databases/main/registration.py b/synapse/storage/databases/main/registration.py index 0082ecbede..291bb8d01e 100644 --- a/synapse/storage/databases/main/registration.py +++ b/synapse/storage/databases/main/registration.py @@ -2607,7 +2607,7 @@ def user_delete_access_tokens_for_devices_txn( # Print after transaction completes (cache invalidation has happened) if tokens_and_devices: print(tokens_and_devices) - print(self.get_user_by_access_token(tokens_and_devices[0][0])) + print(await self.get_user_by_access_token(tokens_and_devices[0][0])) return results async def delete_access_token(self, access_token: str) -> None: diff --git a/tests/rest/client/test_read_marker.py b/tests/rest/client/test_read_marker.py index 1dd2a2f2bf..f5fd40d77b 100644 --- a/tests/rest/client/test_read_marker.py +++ b/tests/rest/client/test_read_marker.py @@ -29,12 +29,14 @@ from synapse.util.clock import Clock from tests import unittest +from tests.replication._base import BaseMultiWorkerStreamTestCase +from tests.server import make_request ONE_HOUR_MS = 3600000 ONE_DAY_MS = ONE_HOUR_MS * 24 -class ReadMarkerTestCase(unittest.HomeserverTestCase): +class ReadMarkerTestCase(BaseMultiWorkerStreamTestCase): servlets = [ login.register_servlets, register.register_servlets, @@ -155,12 +157,17 @@ def send_message() -> str: def test_deleted_device_cannot_set_read_marker_or_send_message(self) -> None: """ Test that a deleted device cannot set a read marker or send a message. + This test removes the first device on one worker and tries the next requests on another worker. + It also verifies that a second device (not deleted) can still make requests successfully. """ # Register a user and login with a specific device_id user_id = self.register_user("testuser", "password") device_id = "TEST_DEVICE_123" access_token = self.login("testuser", "password", device_id=device_id) - print("access token: ", access_token) + + # Login with a second device to get a second access token + device_id_2 = "TEST_DEVICE_456" + access_token_2 = self.login("testuser", "password", device_id=device_id_2) # Create a room room_id = self.helper.create_room_as(user_id, tok=access_token) @@ -171,8 +178,24 @@ def test_deleted_device_cannot_set_read_marker_or_send_message(self) -> None: ) event_id = message_result["event_id"] - # Delete the device - channel = self.make_request( + # Create two workers + worker1 = self.make_worker_hs( + "synapse.app.generic_worker", + extra_config={"worker_name": "worker1"}, + ) + worker2 = self.make_worker_hs( + "synapse.app.generic_worker", + extra_config={"worker_name": "worker2"}, + ) + + # Get the sites for the workers + worker1_site = self._hs_to_site[worker1] + worker2_site = self._hs_to_site[worker2] + + # Delete the first device on worker1 + channel = make_request( + self.reactor, + worker1_site, "DELETE", f"devices/{device_id}", access_token=access_token, @@ -181,7 +204,9 @@ def test_deleted_device_cannot_set_read_marker_or_send_message(self) -> None: # If UI auth is required, provide it if channel.code == 401: session = channel.json_body["session"] - channel = self.make_request( + channel = make_request( + self.reactor, + worker1_site, "DELETE", f"devices/{device_id}", access_token=access_token, @@ -197,8 +222,13 @@ def test_deleted_device_cannot_set_read_marker_or_send_message(self) -> None: self.assertEqual(channel.code, 200, channel.result) - # Try to set a read marker with the deleted device's token - channel = self.make_request( + # Replicate to ensure the deletion propagates to other workers + # self.replicate() + + # Try to set a read marker with the deleted device's token on worker2 + channel = make_request( + self.reactor, + worker2_site, "POST", f"/rooms/{room_id}/read_markers", content={ @@ -210,8 +240,10 @@ def test_deleted_device_cannot_set_read_marker_or_send_message(self) -> None: self.assertEqual(channel.code, 401, channel.result) self.assertEqual(channel.json_body["errcode"], "M_UNKNOWN_TOKEN") - # Try to send a message with the deleted device's token - channel = self.make_request( + # Try to send a message with the deleted device's token on worker2 + channel = make_request( + self.reactor, + worker2_site, "PUT", f"/rooms/{room_id}/send/m.room.message/test_msg", content={ @@ -223,3 +255,32 @@ def test_deleted_device_cannot_set_read_marker_or_send_message(self) -> None: # Should fail with 401 (unauthorized) since the device is deleted self.assertEqual(channel.code, 401, channel.result) self.assertEqual(channel.json_body["errcode"], "M_UNKNOWN_TOKEN") + + # Verify that the second device's token still works - it should be able to set a read marker + channel = make_request( + self.reactor, + worker2_site, + "POST", + f"/rooms/{room_id}/read_markers", + content={ + "m.fully_read": event_id, + }, + access_token=access_token_2, + ) + # Should succeed since the second device is not deleted + self.assertEqual(channel.code, 200, channel.result) + + # Verify that the second device's token can still send a message + channel = make_request( + self.reactor, + worker2_site, + "PUT", + f"/rooms/{room_id}/send/m.room.message/test_msg_2", + content={ + "msgtype": "m.text", + "body": "This should work", + }, + access_token=access_token_2, + ) + # Should succeed since the second device is not deleted + self.assertEqual(channel.code, 200, channel.result)