diff --git a/packages/overlays/matrix-synapse/patches/0035-Convert-Sliding-Sync-tests-to-use-higher-level-compu.patch b/packages/overlays/matrix-synapse/patches/0035-Convert-Sliding-Sync-tests-to-use-higher-level-compu.patch
deleted file mode 100644
index d34a1be..0000000
--- a/packages/overlays/matrix-synapse/patches/0035-Convert-Sliding-Sync-tests-to-use-higher-level-compu.patch
+++ /dev/null
@@ -1,2816 +0,0 @@
-From ae877aa101796a0cd57c3637a875140ddb25ed51 Mon Sep 17 00:00:00 2001
-From: Devon Hudson <devon.dmytro@gmail.com>
-Date: Wed, 7 May 2025 15:07:58 +0000
-Subject: [PATCH 35/74] Convert Sliding Sync tests to use higher-level
- `compute_interested_rooms` (#18399)
-
-Spawning from
-https://github.com/element-hq/synapse/pull/18375#discussion_r2071768635,
-
-This updates some sliding sync tests to use a higher level function in
-order to move test coverage to cover both fallback & new tables.
-Important when https://github.com/element-hq/synapse/pull/18375 is
-merged.
-
-In other words, adjust tests to target `compute_interested_room(...)`
-(relevant to both new and fallback path) instead of the lower level
-`get_room_membership_for_user_at_to_token(...)` that only applies to the
-fallback path.
-
-### Dev notes
-
-```
-SYNAPSE_TEST_LOG_LEVEL=INFO poetry run trial tests.handlers.test_sliding_sync.ComputeInterestedRoomsTestCase_new
-```
-
-```
-SYNAPSE_TEST_LOG_LEVEL=INFO poetry run trial tests.rest.client.sliding_sync
-```
-
-```
-SYNAPSE_POSTGRES=1 SYNAPSE_POSTGRES_USER=postgres SYNAPSE_TEST_LOG_LEVEL=INFO poetry run trial tests.handlers.test_sliding_sync.ComputeInterestedRoomsTestCase_new.test_display_name_changes_leave_after_token_range
-```
-
-### Pull Request Checklist
-
-<!-- Please read
-https://element-hq.github.io/synapse/latest/development/contributing_guide.html
-before submitting your pull request -->
-
-* [x] Pull request is based on the develop branch
-* [x] Pull request includes a [changelog
-file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
-The entry should:
-- Be a short description of your change which makes sense to users.
-"Fixed a bug that prevented receiving messages from other servers."
-instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
- - Use markdown where necessary, mostly for `code blocks`.
- - End with either a period (.) or an exclamation mark (!).
- - Start with a capital letter.
-- Feel free to credit yourself, by adding a sentence "Contributed by
-@github_username." or "Contributed by [Your Name]." to the end of the
-entry.
-* [x] [Code
-style](https://element-hq.github.io/synapse/latest/code_style.html) is
-correct
-(run the
-[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))
-
----------
-
-Co-authored-by: Eric Eastwood <erice@element.io>
----
- changelog.d/18399.misc | 1 +
- synapse/handlers/sliding_sync/room_lists.py | 122 +-
- synapse/storage/_base.py | 10 +-
- synapse/storage/databases/main/cache.py | 23 +-
- synapse/storage/databases/main/roommember.py | 135 +-
- synapse/storage/databases/main/stream.py | 2 +
- tests/handlers/test_sliding_sync.py | 1382 +++++++++++++-----
- 7 files changed, 1238 insertions(+), 437 deletions(-)
- create mode 100644 changelog.d/18399.misc
-
-diff --git a/changelog.d/18399.misc b/changelog.d/18399.misc
-new file mode 100644
-index 0000000000..847dc9a2b1
---- /dev/null
-+++ b/changelog.d/18399.misc
-@@ -0,0 +1 @@
-+Refactor [MSC4186](https://github.com/matrix-org/matrix-spec-proposals/pull/4186) Simplified Sliding Sync room list tests to cover both new and fallback logic paths.
-diff --git a/synapse/handlers/sliding_sync/room_lists.py b/synapse/handlers/sliding_sync/room_lists.py
-index a1730b7e05..7e3cf539df 100644
---- a/synapse/handlers/sliding_sync/room_lists.py
-+++ b/synapse/handlers/sliding_sync/room_lists.py
-@@ -244,14 +244,47 @@ class SlidingSyncRoomLists:
- # Note: this won't include rooms the user has left themselves. We add back
- # `newly_left` rooms below. This is more efficient than fetching all rooms and
- # then filtering out the old left rooms.
-- room_membership_for_user_map = await self.store.get_sliding_sync_rooms_for_user(
-- user_id
-+ room_membership_for_user_map = (
-+ await self.store.get_sliding_sync_rooms_for_user_from_membership_snapshots(
-+ user_id
-+ )
-+ )
-+ # To play nice with the rewind logic below, we need to go fetch the rooms the
-+ # user has left themselves but only if it changed after the `to_token`.
-+ #
-+ # If a leave happens *after* the token range, we may have still been joined (or
-+ # any non-self-leave which is relevant to sync) to the room before so we need to
-+ # include it in the list of potentially relevant rooms and apply our rewind
-+ # logic (outside of this function) to see if it's actually relevant.
-+ #
-+ # We do this separately from
-+ # `get_sliding_sync_rooms_for_user_from_membership_snapshots` as those results
-+ # are cached and the `to_token` isn't very cache friendly (people are constantly
-+ # requesting with new tokens) so we separate it out here.
-+ self_leave_room_membership_for_user_map = (
-+ await self.store.get_sliding_sync_self_leave_rooms_after_to_token(
-+ user_id, to_token
-+ )
- )
-+ if self_leave_room_membership_for_user_map:
-+ # FIXME: It would be nice to avoid this copy but since
-+ # `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
-+ # can't return a mutable value like a `dict`. We make the copy to get a
-+ # mutable dict that we can change. We try to only make a copy when necessary
-+ # (if we actually need to change something) as in most cases, the logic
-+ # doesn't need to run.
-+ room_membership_for_user_map = dict(room_membership_for_user_map)
-+ room_membership_for_user_map.update(self_leave_room_membership_for_user_map)
-
- # Remove invites from ignored users
- ignored_users = await self.store.ignored_users(user_id)
- if ignored_users:
-- # TODO: It would be nice to avoid these copies
-+ # FIXME: It would be nice to avoid this copy but since
-+ # `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
-+ # can't return a mutable value like a `dict`. We make the copy to get a
-+ # mutable dict that we can change. We try to only make a copy when necessary
-+ # (if we actually need to change something) as in most cases, the logic
-+ # doesn't need to run.
- room_membership_for_user_map = dict(room_membership_for_user_map)
- # Make a copy so we don't run into an error: `dictionary changed size during
- # iteration`, when we remove items
-@@ -263,11 +296,23 @@ class SlidingSyncRoomLists:
- ):
- room_membership_for_user_map.pop(room_id, None)
-
-+ (
-+ newly_joined_room_ids,
-+ newly_left_room_map,
-+ ) = await self._get_newly_joined_and_left_rooms(
-+ user_id, from_token=from_token, to_token=to_token
-+ )
-+
- changes = await self._get_rewind_changes_to_current_membership_to_token(
- sync_config.user, room_membership_for_user_map, to_token=to_token
- )
- if changes:
-- # TODO: It would be nice to avoid these copies
-+ # FIXME: It would be nice to avoid this copy but since
-+ # `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
-+ # can't return a mutable value like a `dict`. We make the copy to get a
-+ # mutable dict that we can change. We try to only make a copy when necessary
-+ # (if we actually need to change something) as in most cases, the logic
-+ # doesn't need to run.
- room_membership_for_user_map = dict(room_membership_for_user_map)
- for room_id, change in changes.items():
- if change is None:
-@@ -278,7 +323,7 @@ class SlidingSyncRoomLists:
- existing_room = room_membership_for_user_map.get(room_id)
- if existing_room is not None:
- # Update room membership events to the point in time of the `to_token`
-- room_membership_for_user_map[room_id] = RoomsForUserSlidingSync(
-+ room_for_user = RoomsForUserSlidingSync(
- room_id=room_id,
- sender=change.sender,
- membership=change.membership,
-@@ -290,18 +335,18 @@ class SlidingSyncRoomLists:
- room_type=existing_room.room_type,
- is_encrypted=existing_room.is_encrypted,
- )
--
-- (
-- newly_joined_room_ids,
-- newly_left_room_map,
-- ) = await self._get_newly_joined_and_left_rooms(
-- user_id, from_token=from_token, to_token=to_token
-- )
-- dm_room_ids = await self._get_dm_rooms_for_user(user_id)
-+ if filter_membership_for_sync(
-+ user_id=user_id,
-+ room_membership_for_user=room_for_user,
-+ newly_left=room_id in newly_left_room_map,
-+ ):
-+ room_membership_for_user_map[room_id] = room_for_user
-+ else:
-+ room_membership_for_user_map.pop(room_id, None)
-
- # Add back `newly_left` rooms (rooms left in the from -> to token range).
- #
-- # We do this because `get_sliding_sync_rooms_for_user(...)` doesn't include
-+ # We do this because `get_sliding_sync_rooms_for_user_from_membership_snapshots(...)` doesn't include
- # rooms that the user left themselves as it's more efficient to add them back
- # here than to fetch all rooms and then filter out the old left rooms. The user
- # only leaves a room once in a blue moon so this barely needs to run.
-@@ -310,7 +355,12 @@ class SlidingSyncRoomLists:
- newly_left_room_map.keys() - room_membership_for_user_map.keys()
- )
- if missing_newly_left_rooms:
-- # TODO: It would be nice to avoid these copies
-+ # FIXME: It would be nice to avoid this copy but since
-+ # `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
-+ # can't return a mutable value like a `dict`. We make the copy to get a
-+ # mutable dict that we can change. We try to only make a copy when necessary
-+ # (if we actually need to change something) as in most cases, the logic
-+ # doesn't need to run.
- room_membership_for_user_map = dict(room_membership_for_user_map)
- for room_id in missing_newly_left_rooms:
- newly_left_room_for_user = newly_left_room_map[room_id]
-@@ -327,14 +377,21 @@ class SlidingSyncRoomLists:
- # If the membership exists, it's just a normal user left the room on
- # their own
- if newly_left_room_for_user_sliding_sync is not None:
-- room_membership_for_user_map[room_id] = (
-- newly_left_room_for_user_sliding_sync
-- )
-+ if filter_membership_for_sync(
-+ user_id=user_id,
-+ room_membership_for_user=newly_left_room_for_user_sliding_sync,
-+ newly_left=room_id in newly_left_room_map,
-+ ):
-+ room_membership_for_user_map[room_id] = (
-+ newly_left_room_for_user_sliding_sync
-+ )
-+ else:
-+ room_membership_for_user_map.pop(room_id, None)
-
- change = changes.get(room_id)
- if change is not None:
- # Update room membership events to the point in time of the `to_token`
-- room_membership_for_user_map[room_id] = RoomsForUserSlidingSync(
-+ room_for_user = RoomsForUserSlidingSync(
- room_id=room_id,
- sender=change.sender,
- membership=change.membership,
-@@ -346,6 +403,14 @@ class SlidingSyncRoomLists:
- room_type=newly_left_room_for_user_sliding_sync.room_type,
- is_encrypted=newly_left_room_for_user_sliding_sync.is_encrypted,
- )
-+ if filter_membership_for_sync(
-+ user_id=user_id,
-+ room_membership_for_user=room_for_user,
-+ newly_left=room_id in newly_left_room_map,
-+ ):
-+ room_membership_for_user_map[room_id] = room_for_user
-+ else:
-+ room_membership_for_user_map.pop(room_id, None)
-
- # If we are `newly_left` from the room but can't find any membership,
- # then we have been "state reset" out of the room
-@@ -367,7 +432,7 @@ class SlidingSyncRoomLists:
- newly_left_room_for_user.event_pos.to_room_stream_token(),
- )
-
-- room_membership_for_user_map[room_id] = RoomsForUserSlidingSync(
-+ room_for_user = RoomsForUserSlidingSync(
- room_id=room_id,
- sender=newly_left_room_for_user.sender,
- membership=newly_left_room_for_user.membership,
-@@ -378,6 +443,16 @@ class SlidingSyncRoomLists:
- room_type=room_type,
- is_encrypted=is_encrypted,
- )
-+ if filter_membership_for_sync(
-+ user_id=user_id,
-+ room_membership_for_user=room_for_user,
-+ newly_left=room_id in newly_left_room_map,
-+ ):
-+ room_membership_for_user_map[room_id] = room_for_user
-+ else:
-+ room_membership_for_user_map.pop(room_id, None)
-+
-+ dm_room_ids = await self._get_dm_rooms_for_user(user_id)
-
- if sync_config.lists:
- sync_room_map = room_membership_for_user_map
-@@ -493,7 +568,12 @@ class SlidingSyncRoomLists:
-
- if sync_config.room_subscriptions:
- with start_active_span("assemble_room_subscriptions"):
-- # TODO: It would be nice to avoid these copies
-+ # FIXME: It would be nice to avoid this copy but since
-+ # `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
-+ # can't return a mutable value like a `dict`. We make the copy to get a
-+ # mutable dict that we can change. We try to only make a copy when necessary
-+ # (if we actually need to change something) as in most cases, the logic
-+ # doesn't need to run.
- room_membership_for_user_map = dict(room_membership_for_user_map)
-
- # Find which rooms are partially stated and may need to be filtered out
-diff --git a/synapse/storage/_base.py b/synapse/storage/_base.py
-index 7251e72e3a..b5fe7dd858 100644
---- a/synapse/storage/_base.py
-+++ b/synapse/storage/_base.py
-@@ -130,7 +130,7 @@ class SQLBaseStore(metaclass=ABCMeta):
- "_get_rooms_for_local_user_where_membership_is_inner", (user_id,)
- )
- self._attempt_to_invalidate_cache(
-- "get_sliding_sync_rooms_for_user", (user_id,)
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", (user_id,)
- )
-
- # Purge other caches based on room state.
-@@ -138,7 +138,9 @@ class SQLBaseStore(metaclass=ABCMeta):
- self._attempt_to_invalidate_cache("get_partial_current_state_ids", (room_id,))
- self._attempt_to_invalidate_cache("get_room_type", (room_id,))
- self._attempt_to_invalidate_cache("get_room_encryption", (room_id,))
-- self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
-+ self._attempt_to_invalidate_cache(
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", None
-+ )
-
- def _invalidate_state_caches_all(self, room_id: str) -> None:
- """Invalidates caches that are based on the current state, but does
-@@ -168,7 +170,9 @@ class SQLBaseStore(metaclass=ABCMeta):
- self._attempt_to_invalidate_cache("get_room_summary", (room_id,))
- self._attempt_to_invalidate_cache("get_room_type", (room_id,))
- self._attempt_to_invalidate_cache("get_room_encryption", (room_id,))
-- self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
-+ self._attempt_to_invalidate_cache(
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", None
-+ )
-
- def _attempt_to_invalidate_cache(
- self, cache_name: str, key: Optional[Collection[Any]]
-diff --git a/synapse/storage/databases/main/cache.py b/synapse/storage/databases/main/cache.py
-index f364464c23..9418fb6dd7 100644
---- a/synapse/storage/databases/main/cache.py
-+++ b/synapse/storage/databases/main/cache.py
-@@ -307,7 +307,7 @@ class CacheInvalidationWorkerStore(SQLBaseStore):
- "get_rooms_for_user", (data.state_key,)
- )
- self._attempt_to_invalidate_cache(
-- "get_sliding_sync_rooms_for_user", None
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", None
- )
- self._membership_stream_cache.entity_has_changed(data.state_key, token) # type: ignore[attr-defined]
- elif data.type == EventTypes.RoomEncryption:
-@@ -319,7 +319,7 @@ class CacheInvalidationWorkerStore(SQLBaseStore):
-
- if (data.type, data.state_key) in SLIDING_SYNC_RELEVANT_STATE_SET:
- self._attempt_to_invalidate_cache(
-- "get_sliding_sync_rooms_for_user", None
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", None
- )
- elif row.type == EventsStreamAllStateRow.TypeId:
- assert isinstance(data, EventsStreamAllStateRow)
-@@ -330,7 +330,9 @@ class CacheInvalidationWorkerStore(SQLBaseStore):
- self._attempt_to_invalidate_cache("get_rooms_for_user", None)
- self._attempt_to_invalidate_cache("get_room_type", (data.room_id,))
- self._attempt_to_invalidate_cache("get_room_encryption", (data.room_id,))
-- self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
-+ self._attempt_to_invalidate_cache(
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", None
-+ )
- else:
- raise Exception("Unknown events stream row type %s" % (row.type,))
-
-@@ -394,7 +396,8 @@ class CacheInvalidationWorkerStore(SQLBaseStore):
- "_get_rooms_for_local_user_where_membership_is_inner", (state_key,)
- )
- self._attempt_to_invalidate_cache(
-- "get_sliding_sync_rooms_for_user", (state_key,)
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots",
-+ (state_key,),
- )
-
- self._attempt_to_invalidate_cache(
-@@ -413,7 +416,9 @@ class CacheInvalidationWorkerStore(SQLBaseStore):
- self._attempt_to_invalidate_cache("get_room_encryption", (room_id,))
-
- if (etype, state_key) in SLIDING_SYNC_RELEVANT_STATE_SET:
-- self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
-+ self._attempt_to_invalidate_cache(
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", None
-+ )
-
- if relates_to:
- self._attempt_to_invalidate_cache(
-@@ -470,7 +475,9 @@ class CacheInvalidationWorkerStore(SQLBaseStore):
- self._attempt_to_invalidate_cache(
- "_get_rooms_for_local_user_where_membership_is_inner", None
- )
-- self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
-+ self._attempt_to_invalidate_cache(
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", None
-+ )
- self._attempt_to_invalidate_cache("did_forget", None)
- self._attempt_to_invalidate_cache("get_forgotten_rooms_for_user", None)
- self._attempt_to_invalidate_cache("get_references_for_event", None)
-@@ -529,7 +536,9 @@ class CacheInvalidationWorkerStore(SQLBaseStore):
- self._attempt_to_invalidate_cache(
- "get_current_hosts_in_room_ordered", (room_id,)
- )
-- self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
-+ self._attempt_to_invalidate_cache(
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots", None
-+ )
- self._attempt_to_invalidate_cache("did_forget", None)
- self._attempt_to_invalidate_cache("get_forgotten_rooms_for_user", None)
- self._attempt_to_invalidate_cache("_get_membership_from_event_id", None)
-diff --git a/synapse/storage/databases/main/roommember.py b/synapse/storage/databases/main/roommember.py
-index b8c78baa6c..2084776543 100644
---- a/synapse/storage/databases/main/roommember.py
-+++ b/synapse/storage/databases/main/roommember.py
-@@ -53,6 +53,7 @@ from synapse.storage.database import (
- )
- from synapse.storage.databases.main.cache import CacheInvalidationWorkerStore
- from synapse.storage.databases.main.events_worker import EventsWorkerStore
-+from synapse.storage.databases.main.stream import _filter_results_by_stream
- from synapse.storage.engines import Sqlite3Engine
- from synapse.storage.roommember import (
- MemberSummary,
-@@ -65,6 +66,7 @@ from synapse.types import (
- PersistedEventPosition,
- StateMap,
- StrCollection,
-+ StreamToken,
- get_domain_from_id,
- )
- from synapse.util.caches.descriptors import _CacheContext, cached, cachedList
-@@ -1389,7 +1391,9 @@ class RoomMemberWorkerStore(EventsWorkerStore, CacheInvalidationWorkerStore):
- txn, self.get_forgotten_rooms_for_user, (user_id,)
- )
- self._invalidate_cache_and_stream(
-- txn, self.get_sliding_sync_rooms_for_user, (user_id,)
-+ txn,
-+ self.get_sliding_sync_rooms_for_user_from_membership_snapshots,
-+ (user_id,),
- )
-
- await self.db_pool.runInteraction("forget_membership", f)
-@@ -1421,25 +1425,30 @@ class RoomMemberWorkerStore(EventsWorkerStore, CacheInvalidationWorkerStore):
- )
-
- @cached(iterable=True, max_entries=10000)
-- async def get_sliding_sync_rooms_for_user(
-- self,
-- user_id: str,
-+ async def get_sliding_sync_rooms_for_user_from_membership_snapshots(
-+ self, user_id: str
- ) -> Mapping[str, RoomsForUserSlidingSync]:
-- """Get all the rooms for a user to handle a sliding sync request.
-+ """
-+ Get all the rooms for a user to handle a sliding sync request from the
-+ `sliding_sync_membership_snapshots` table. These will be current memberships and
-+ need to be rewound to the token range.
-
- Ignores forgotten rooms and rooms that the user has left themselves.
-
-+ Args:
-+ user_id: The user ID to get the rooms for.
-+
- Returns:
- Map from room ID to membership info
- """
-
-- def get_sliding_sync_rooms_for_user_txn(
-+ def _txn(
- txn: LoggingTransaction,
- ) -> Dict[str, RoomsForUserSlidingSync]:
- # XXX: If you use any new columns that can change (like from
- # `sliding_sync_joined_rooms` or `forgotten`), make sure to bust the
-- # `get_sliding_sync_rooms_for_user` cache in the appropriate places (and add
-- # tests).
-+ # `get_sliding_sync_rooms_for_user_from_membership_snapshots` cache in the
-+ # appropriate places (and add tests).
- sql = """
- SELECT m.room_id, m.sender, m.membership, m.membership_event_id,
- r.room_version,
-@@ -1455,6 +1464,7 @@ class RoomMemberWorkerStore(EventsWorkerStore, CacheInvalidationWorkerStore):
- AND (m.membership != 'leave' OR m.user_id != m.sender)
- """
- txn.execute(sql, (user_id,))
-+
- return {
- row[0]: RoomsForUserSlidingSync(
- room_id=row[0],
-@@ -1475,8 +1485,113 @@ class RoomMemberWorkerStore(EventsWorkerStore, CacheInvalidationWorkerStore):
- }
-
- return await self.db_pool.runInteraction(
-- "get_sliding_sync_rooms_for_user",
-- get_sliding_sync_rooms_for_user_txn,
-+ "get_sliding_sync_rooms_for_user_from_membership_snapshots",
-+ _txn,
-+ )
-+
-+ async def get_sliding_sync_self_leave_rooms_after_to_token(
-+ self,
-+ user_id: str,
-+ to_token: StreamToken,
-+ ) -> Dict[str, RoomsForUserSlidingSync]:
-+ """
-+ Get all the self-leave rooms for a user after the `to_token` (outside the token
-+ range) that are potentially relevant[1] and needed to handle a sliding sync
-+ request. The results are from the `sliding_sync_membership_snapshots` table and
-+ will be current memberships and need to be rewound to the token range.
-+
-+ [1] If a leave happens after the token range, we may have still been joined (or
-+ any non-self-leave which is relevant to sync) to the room before so we need to
-+ include it in the list of potentially relevant rooms and apply
-+ our rewind logic (outside of this function) to see if it's actually relevant.
-+
-+ This is basically a sister-function to
-+ `get_sliding_sync_rooms_for_user_from_membership_snapshots`. We could
-+ alternatively incorporate this logic into
-+ `get_sliding_sync_rooms_for_user_from_membership_snapshots` but those results
-+ are cached and the `to_token` isn't very cache friendly (people are constantly
-+ requesting with new tokens) so we separate it out here.
-+
-+ Args:
-+ user_id: The user ID to get the rooms for.
-+ to_token: Any self-leave memberships after this position will be returned.
-+
-+ Returns:
-+ Map from room ID to membership info
-+ """
-+ # TODO: Potential to check
-+ # `self._membership_stream_cache.has_entity_changed(...)` as an early-return
-+ # shortcut.
-+
-+ def _txn(
-+ txn: LoggingTransaction,
-+ ) -> Dict[str, RoomsForUserSlidingSync]:
-+ sql = """
-+ SELECT m.room_id, m.sender, m.membership, m.membership_event_id,
-+ r.room_version,
-+ m.event_instance_name, m.event_stream_ordering,
-+ m.has_known_state,
-+ m.room_type,
-+ m.is_encrypted
-+ FROM sliding_sync_membership_snapshots AS m
-+ INNER JOIN rooms AS r USING (room_id)
-+ WHERE user_id = ?
-+ AND m.forgotten = 0
-+ AND m.membership = 'leave'
-+ AND m.user_id = m.sender
-+ AND (m.event_stream_ordering > ?)
-+ """
-+ # If a leave happens after the token range, we may have still been joined
-+ # (or any non-self-leave which is relevant to sync) to the room before so we
-+ # need to include it in the list of potentially relevant rooms and apply our
-+ # rewind logic (outside of this function).
-+ #
-+ # To handle tokens with a non-empty instance_map we fetch more
-+ # results than necessary and then filter down
-+ min_to_token_position = to_token.room_key.stream
-+ txn.execute(sql, (user_id, min_to_token_position))
-+
-+ # Map from room_id to membership info
-+ room_membership_for_user_map: Dict[str, RoomsForUserSlidingSync] = {}
-+ for row in txn:
-+ room_for_user = RoomsForUserSlidingSync(
-+ room_id=row[0],
-+ sender=row[1],
-+ membership=row[2],
-+ event_id=row[3],
-+ room_version_id=row[4],
-+ event_pos=PersistedEventPosition(row[5], row[6]),
-+ has_known_state=bool(row[7]),
-+ room_type=row[8],
-+ is_encrypted=bool(row[9]),
-+ )
-+
-+ # We filter out unknown room versions proactively. They shouldn't go
-+ # down sync and their metadata may be in a broken state (causing
-+ # errors).
-+ if row[4] not in KNOWN_ROOM_VERSIONS:
-+ continue
-+
-+ # We only want to include the self-leave membership if it happened after
-+ # the token range.
-+ #
-+ # Since the database pulls out more than necessary, we need to filter it
-+ # down here.
-+ if _filter_results_by_stream(
-+ lower_token=None,
-+ upper_token=to_token.room_key,
-+ instance_name=room_for_user.event_pos.instance_name,
-+ stream_ordering=room_for_user.event_pos.stream,
-+ ):
-+ continue
-+
-+ room_membership_for_user_map[room_for_user.room_id] = room_for_user
-+
-+ return room_membership_for_user_map
-+
-+ return await self.db_pool.runInteraction(
-+ "get_sliding_sync_self_leave_rooms_after_to_token",
-+ _txn,
- )
-
- async def get_sliding_sync_room_for_user(
-diff --git a/synapse/storage/databases/main/stream.py b/synapse/storage/databases/main/stream.py
-index 00e5208674..c52389b8a9 100644
---- a/synapse/storage/databases/main/stream.py
-+++ b/synapse/storage/databases/main/stream.py
-@@ -453,6 +453,8 @@ def _filter_results_by_stream(
- stream_ordering falls between the two tokens (taking a None
- token to mean unbounded).
-
-+ The token range is defined by > `lower_token` and <= `upper_token`.
-+
- Used to filter results from fetching events in the DB against the given
- tokens. This is necessary to handle the case where the tokens include
- position maps, which we handle by fetching more than necessary from the DB
-diff --git a/tests/handlers/test_sliding_sync.py b/tests/handlers/test_sliding_sync.py
-index 5b7e2937f8..cbacf21ae7 100644
---- a/tests/handlers/test_sliding_sync.py
-+++ b/tests/handlers/test_sliding_sync.py
-@@ -22,7 +22,7 @@ from typing import AbstractSet, Dict, Mapping, Optional, Set, Tuple
- from unittest.mock import patch
-
- import attr
--from parameterized import parameterized
-+from parameterized import parameterized, parameterized_class
-
- from twisted.test.proto_helpers import MemoryReactor
-
-@@ -43,13 +43,15 @@ from synapse.rest import admin
- from synapse.rest.client import knock, login, room
- from synapse.server import HomeServer
- from synapse.storage.util.id_generators import MultiWriterIdGenerator
--from synapse.types import JsonDict, StateMap, StreamToken, UserID
--from synapse.types.handlers.sliding_sync import SlidingSyncConfig
-+from synapse.types import JsonDict, StateMap, StreamToken, UserID, create_requester
-+from synapse.types.handlers.sliding_sync import PerConnectionState, SlidingSyncConfig
- from synapse.types.state import StateFilter
- from synapse.util import Clock
-
- from tests import unittest
- from tests.replication._base import BaseMultiWorkerStreamTestCase
-+from tests.rest.client.sliding_sync.test_sliding_sync import SlidingSyncBase
-+from tests.test_utils.event_injection import create_event
- from tests.unittest import HomeserverTestCase, TestCase
-
- logger = logging.getLogger(__name__)
-@@ -572,9 +574,23 @@ class RoomSyncConfigTestCase(TestCase):
- self._assert_room_config_equal(combined_config, expected, "A into B")
-
-
--class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-+# FIXME: This can be removed once we bump `SCHEMA_COMPAT_VERSION` and run the
-+# foreground update for
-+# `sliding_sync_joined_rooms`/`sliding_sync_membership_snapshots` (tracked by
-+# https://github.com/element-hq/synapse/issues/17623)
-+@parameterized_class(
-+ ("use_new_tables",),
-+ [
-+ (True,),
-+ (False,),
-+ ],
-+ class_name_func=lambda cls,
-+ num,
-+ params_dict: f"{cls.__name__}_{'new' if params_dict['use_new_tables'] else 'fallback'}",
-+)
-+class ComputeInterestedRoomsTestCase(SlidingSyncBase):
- """
-- Tests Sliding Sync handler `get_room_membership_for_user_at_to_token()` to make sure it returns
-+ Tests Sliding Sync handler `compute_interested_rooms()` to make sure it returns
- the correct list of rooms IDs.
- """
-
-@@ -596,6 +612,11 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- self.store = self.hs.get_datastores().main
- self.event_sources = hs.get_event_sources()
- self.storage_controllers = hs.get_storage_controllers()
-+ persistence = self.hs.get_storage_controllers().persistence
-+ assert persistence is not None
-+ self.persistence = persistence
-+
-+ super().prepare(reactor, clock, hs)
-
- def test_no_rooms(self) -> None:
- """
-@@ -606,15 +627,28 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- now_token = self.event_sources.get_current_token()
-
-- room_id_results, _, _ = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=now_token,
- to_token=now_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-
-- self.assertEqual(room_id_results.keys(), set())
-+ self.assertIncludes(room_id_results, set(), exact=True)
-
- def test_get_newly_joined_room(self) -> None:
- """
-@@ -633,22 +667,44 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- after_room_token = self.event_sources.get_current_token()
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room_token,
- to_token=after_room_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
-- self.assertEqual(room_id_results.keys(), {room_id})
-+ self.assertIncludes(
-+ room_id_results,
-+ {room_id},
-+ exact=True,
-+ )
- # It should be pointing to the join event (latest membership event in the
- # from/to range)
- self.assertEqual(
-- room_id_results[room_id].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id].event_id,
- join_response["event_id"],
- )
-- self.assertEqual(room_id_results[room_id].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id].membership,
-+ Membership.JOIN,
-+ )
- # We should be considered `newly_joined` because we joined during the token
- # range
- self.assertTrue(room_id in newly_joined)
-@@ -668,22 +724,40 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- after_room_token = self.event_sources.get_current_token()
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room_token,
- to_token=after_room_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
-- self.assertEqual(room_id_results.keys(), {room_id})
-+ self.assertIncludes(room_id_results, {room_id}, exact=True)
- # It should be pointing to the join event (latest membership event in the
- # from/to range)
- self.assertEqual(
-- room_id_results[room_id].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id].event_id,
- join_response["event_id"],
- )
-- self.assertEqual(room_id_results[room_id].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id].membership,
-+ Membership.JOIN,
-+ )
- # We should *NOT* be `newly_joined` because we joined before the token range
- self.assertTrue(room_id not in newly_joined)
- self.assertTrue(room_id not in newly_left)
-@@ -742,46 +816,71 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- after_room_token = self.event_sources.get_current_token()
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room_token,
- to_token=after_room_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Ensure that the invited, ban, and knock rooms show up
-- self.assertEqual(
-- room_id_results.keys(),
-+ self.assertIncludes(
-+ room_id_results,
- {
- invited_room_id,
- ban_room_id,
- knock_room_id,
- },
-+ exact=True,
- )
- # It should be pointing to the the respective membership event (latest
- # membership event in the from/to range)
- self.assertEqual(
-- room_id_results[invited_room_id].event_id,
-+ interested_rooms.room_membership_for_user_map[invited_room_id].event_id,
- invite_response["event_id"],
- )
-- self.assertEqual(room_id_results[invited_room_id].membership, Membership.INVITE)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[invited_room_id].membership,
-+ Membership.INVITE,
-+ )
- self.assertTrue(invited_room_id not in newly_joined)
- self.assertTrue(invited_room_id not in newly_left)
-
- self.assertEqual(
-- room_id_results[ban_room_id].event_id,
-+ interested_rooms.room_membership_for_user_map[ban_room_id].event_id,
- ban_response["event_id"],
- )
-- self.assertEqual(room_id_results[ban_room_id].membership, Membership.BAN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[ban_room_id].membership,
-+ Membership.BAN,
-+ )
- self.assertTrue(ban_room_id not in newly_joined)
- self.assertTrue(ban_room_id not in newly_left)
-
- self.assertEqual(
-- room_id_results[knock_room_id].event_id,
-+ interested_rooms.room_membership_for_user_map[knock_room_id].event_id,
- knock_room_membership_state_event.event_id,
- )
-- self.assertEqual(room_id_results[knock_room_id].membership, Membership.KNOCK)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[knock_room_id].membership,
-+ Membership.KNOCK,
-+ )
- self.assertTrue(knock_room_id not in newly_joined)
- self.assertTrue(knock_room_id not in newly_left)
-
-@@ -814,23 +913,43 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- after_kick_token = self.event_sources.get_current_token()
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_kick_token,
- to_token=after_kick_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # The kicked room should show up
-- self.assertEqual(room_id_results.keys(), {kick_room_id})
-+ self.assertIncludes(room_id_results, {kick_room_id}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[kick_room_id].event_id,
-+ interested_rooms.room_membership_for_user_map[kick_room_id].event_id,
- kick_response["event_id"],
- )
-- self.assertEqual(room_id_results[kick_room_id].membership, Membership.LEAVE)
-- self.assertNotEqual(room_id_results[kick_room_id].sender, user1_id)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[kick_room_id].membership,
-+ Membership.LEAVE,
-+ )
-+ self.assertNotEqual(
-+ interested_rooms.room_membership_for_user_map[kick_room_id].sender, user1_id
-+ )
- # We should *NOT* be `newly_joined` because we were not joined at the the time
- # of the `to_token`.
- self.assertTrue(kick_room_id not in newly_joined)
-@@ -907,16 +1026,29 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- )
- self.assertEqual(channel.code, 200, channel.result)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room_forgets,
- to_token=before_room_forgets,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-
- # We shouldn't see the room because it was forgotten
-- self.assertEqual(room_id_results.keys(), set())
-+ self.assertIncludes(room_id_results, set(), exact=True)
-
- def test_newly_left_rooms(self) -> None:
- """
-@@ -927,7 +1059,7 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- # Leave before we calculate the `from_token`
- room_id1 = self.helper.create_room_as(user1_id, tok=user1_tok)
-- leave_response1 = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-+ _leave_response1 = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
- after_room1_token = self.event_sources.get_current_token()
-
-@@ -937,31 +1069,52 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- after_room2_token = self.event_sources.get_current_token()
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_room2_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
-- self.assertEqual(room_id_results.keys(), {room_id1, room_id2})
--
-- self.assertEqual(
-- room_id_results[room_id1].event_id,
-- leave_response1["event_id"],
-+ # `room_id1` should not show up because it was left before the token range.
-+ # `room_id2` should show up because it is `newly_left` within the token range.
-+ self.assertIncludes(
-+ room_id_results,
-+ {room_id2},
-+ exact=True,
-+ message="Corresponding map to disambiguate the opaque room IDs: "
-+ + str(
-+ {
-+ "room_id1": room_id1,
-+ "room_id2": room_id2,
-+ }
-+ ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.LEAVE)
-- # We should *NOT* be `newly_joined` or `newly_left` because that happened before
-- # the from/to range
-- self.assertTrue(room_id1 not in newly_joined)
-- self.assertTrue(room_id1 not in newly_left)
-
- self.assertEqual(
-- room_id_results[room_id2].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id2].event_id,
- leave_response2["event_id"],
- )
-- self.assertEqual(room_id_results[room_id2].membership, Membership.LEAVE)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id2].membership,
-+ Membership.LEAVE,
-+ )
- # We should *NOT* be `newly_joined` because we are instead `newly_left`
- self.assertTrue(room_id2 not in newly_joined)
- self.assertTrue(room_id2 in newly_left)
-@@ -987,21 +1140,39 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- room_id2 = self.helper.create_room_as(user2_id, tok=user2_tok)
- self.helper.join(room_id2, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_response1["event_id"],
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should be `newly_joined` because we joined during the token range
- self.assertTrue(room_id1 in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-@@ -1027,20 +1198,35 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- # Leave the room after we already have our tokens
- leave_response = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # We should still see the room because we were joined during the
- # from_token/to_token time period.
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_response["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1050,7 +1236,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should be `newly_joined` because we joined during the token range
- self.assertTrue(room_id1 in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-@@ -1074,19 +1263,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- # Leave the room after we already have our tokens
- leave_response = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # We should still see the room because we were joined before the `from_token`
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_response["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1096,7 +1300,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should *NOT* be `newly_joined` because we joined before the token range
- self.assertTrue(room_id1 not in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-@@ -1138,19 +1345,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- join_response2 = self.helper.join(kick_room_id, user1_id, tok=user1_tok)
- leave_response = self.helper.leave(kick_room_id, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_kick_token,
- to_token=after_kick_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # We shouldn't see the room because it was forgotten
-- self.assertEqual(room_id_results.keys(), {kick_room_id})
-+ self.assertIncludes(room_id_results, {kick_room_id}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[kick_room_id].event_id,
-+ interested_rooms.room_membership_for_user_map[kick_room_id].event_id,
- kick_response["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1162,8 +1384,13 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[kick_room_id].membership, Membership.LEAVE)
-- self.assertNotEqual(room_id_results[kick_room_id].sender, user1_id)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[kick_room_id].membership,
-+ Membership.LEAVE,
-+ )
-+ self.assertNotEqual(
-+ interested_rooms.room_membership_for_user_map[kick_room_id].sender, user1_id
-+ )
- # We should *NOT* be `newly_joined` because we were kicked
- self.assertTrue(kick_room_id not in newly_joined)
- self.assertTrue(kick_room_id not in newly_left)
-@@ -1194,19 +1421,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- join_response2 = self.helper.join(room_id1, user1_id, tok=user1_tok)
- leave_response2 = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should still show up because it's newly_left during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- leave_response1["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1218,7 +1460,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.LEAVE)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.LEAVE,
-+ )
- # We should *NOT* be `newly_joined` because we are actually `newly_left` during
- # the token range
- self.assertTrue(room_id1 not in newly_joined)
-@@ -1249,19 +1494,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- # Join the room after we already have our tokens
- join_response2 = self.helper.join(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should still show up because it's newly_left during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- leave_response1["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1272,7 +1532,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.LEAVE)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.LEAVE,
-+ )
- # We should *NOT* be `newly_joined` because we are actually `newly_left` during
- # the token range
- self.assertTrue(room_id1 not in newly_joined)
-@@ -1301,47 +1564,53 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- # Join and leave the room2 before the `to_token`
- self.helper.join(room_id2, user1_id, tok=user1_tok)
-- leave_response2 = self.helper.leave(room_id2, user1_id, tok=user1_tok)
-+ _leave_response2 = self.helper.leave(room_id2, user1_id, tok=user1_tok)
-
- after_room1_token = self.event_sources.get_current_token()
-
- # Join the room2 after we already have our tokens
- self.helper.join(room_id2, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=None,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Only rooms we were joined to before the `to_token` should show up
-- self.assertEqual(room_id_results.keys(), {room_id1, room_id2})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
-
- # Room1
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_response1["event_id"],
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-- # We should *NOT* be `newly_joined`/`newly_left` because there is no
-- # `from_token` to define a "live" range to compare against
-- self.assertTrue(room_id1 not in newly_joined)
-- self.assertTrue(room_id1 not in newly_left)
--
-- # Room2
-- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id2].event_id,
-- leave_response2["event_id"],
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
- )
-- self.assertEqual(room_id_results[room_id2].membership, Membership.LEAVE)
- # We should *NOT* be `newly_joined`/`newly_left` because there is no
- # `from_token` to define a "live" range to compare against
-- self.assertTrue(room_id2 not in newly_joined)
-- self.assertTrue(room_id2 not in newly_left)
-+ self.assertTrue(room_id1 not in newly_joined)
-+ self.assertTrue(room_id1 not in newly_left)
-
- def test_from_token_ahead_of_to_token(self) -> None:
- """
-@@ -1365,7 +1634,7 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- # Join and leave the room2 before `to_token`
- _join_room2_response1 = self.helper.join(room_id2, user1_id, tok=user1_tok)
-- leave_room2_response1 = self.helper.leave(room_id2, user1_id, tok=user1_tok)
-+ _leave_room2_response1 = self.helper.leave(room_id2, user1_id, tok=user1_tok)
-
- # Note: These are purposely swapped. The `from_token` should come after
- # the `to_token` in this test
-@@ -1390,55 +1659,70 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- # Join the room4 after we already have our tokens
- self.helper.join(room_id4, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=from_token,
- to_token=to_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # In the "current" state snapshot, we're joined to all of the rooms but in the
- # from/to token range...
- self.assertIncludes(
-- room_id_results.keys(),
-+ room_id_results,
- {
- # Included because we were joined before both tokens
- room_id1,
-- # Included because we had membership before the to_token
-- room_id2,
-+ # Excluded because we left before the `from_token` and `to_token`
-+ # room_id2,
- # Excluded because we joined after the `to_token`
- # room_id3,
- # Excluded because we joined after the `to_token`
- # room_id4,
- },
- exact=True,
-+ message="Corresponding map to disambiguate the opaque room IDs: "
-+ + str(
-+ {
-+ "room_id1": room_id1,
-+ "room_id2": room_id2,
-+ "room_id3": room_id3,
-+ "room_id4": room_id4,
-+ }
-+ ),
- )
-
- # Room1
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_room1_response1["event_id"],
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should *NOT* be `newly_joined`/`newly_left` because we joined `room1`
- # before either of the tokens
- self.assertTrue(room_id1 not in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-
-- # Room2
-- # It should be pointing to the latest membership event in the from/to range
-- self.assertEqual(
-- room_id_results[room_id2].event_id,
-- leave_room2_response1["event_id"],
-- )
-- self.assertEqual(room_id_results[room_id2].membership, Membership.LEAVE)
-- # We should *NOT* be `newly_joined`/`newly_left` because we joined and left
-- # `room1` before either of the tokens
-- self.assertTrue(room_id2 not in newly_joined)
-- self.assertTrue(room_id2 not in newly_left)
--
- def test_leave_before_range_and_join_leave_after_to_token(self) -> None:
- """
- Test old left rooms. But we're also testing that joining and leaving after the
-@@ -1455,7 +1739,7 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok, is_public=True)
- # Join and leave the room before the from/to range
- self.helper.join(room_id1, user1_id, tok=user1_tok)
-- leave_response = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-+ self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
- after_room1_token = self.event_sources.get_current_token()
-
-@@ -1463,25 +1747,28 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- self.helper.join(room_id1, user1_id, tok=user1_tok)
- self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-
-- self.assertEqual(room_id_results.keys(), {room_id1})
-- # It should be pointing to the latest membership event in the from/to range
-- self.assertEqual(
-- room_id_results[room_id1].event_id,
-- leave_response["event_id"],
-- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.LEAVE)
-- # We should *NOT* be `newly_joined`/`newly_left` because we joined and left
-- # `room1` before either of the tokens
-- self.assertTrue(room_id1 not in newly_joined)
-- self.assertTrue(room_id1 not in newly_left)
-+ self.assertIncludes(room_id_results, set(), exact=True)
-
- def test_leave_before_range_and_join_after_to_token(self) -> None:
- """
-@@ -1499,32 +1786,35 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok, is_public=True)
- # Join and leave the room before the from/to range
- self.helper.join(room_id1, user1_id, tok=user1_tok)
-- leave_response = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-+ self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
- after_room1_token = self.event_sources.get_current_token()
-
- # Join the room after we already have our tokens
- self.helper.join(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-
-- self.assertEqual(room_id_results.keys(), {room_id1})
-- # It should be pointing to the latest membership event in the from/to range
-- self.assertEqual(
-- room_id_results[room_id1].event_id,
-- leave_response["event_id"],
-- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.LEAVE)
-- # We should *NOT* be `newly_joined`/`newly_left` because we joined and left
-- # `room1` before either of the tokens
-- self.assertTrue(room_id1 not in newly_joined)
-- self.assertTrue(room_id1 not in newly_left)
-+ self.assertIncludes(room_id_results, set(), exact=True)
-
- def test_join_leave_multiple_times_during_range_and_after_to_token(
- self,
-@@ -1556,19 +1846,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- join_response3 = self.helper.join(room_id1, user1_id, tok=user1_tok)
- leave_response3 = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because it was newly_left and joined during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_response2["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1582,7 +1887,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should be `newly_joined` because we joined during the token range
- self.assertTrue(room_id1 in newly_joined)
- # We should *NOT* be `newly_left` because we joined during the token range and
-@@ -1618,19 +1926,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- join_response3 = self.helper.join(room_id1, user1_id, tok=user1_tok)
- leave_response3 = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because we were joined before the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_response2["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1644,7 +1967,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should *NOT* be `newly_joined` because we joined before the token range
- self.assertTrue(room_id1 not in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-@@ -1677,19 +2003,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- join_respsonse = self.helper.join(room_id1, user1_id, tok=user1_tok)
- leave_response = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because we were invited before the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- invite_response["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1700,7 +2041,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.INVITE)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.INVITE,
-+ )
- # We should *NOT* be `newly_joined` because we were only invited before the
- # token range
- self.assertTrue(room_id1 not in newly_joined)
-@@ -1751,19 +2095,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- tok=user1_tok,
- )
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because we were joined during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- displayname_change_during_token_range_response["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1778,7 +2137,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should be `newly_joined` because we joined during the token range
- self.assertTrue(room_id1 in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-@@ -1816,19 +2178,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- after_change1_token = self.event_sources.get_current_token()
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_change1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because we were joined during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- displayname_change_during_token_range_response["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1840,7 +2217,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should *NOT* be `newly_joined` because we joined before the token range
- self.assertTrue(room_id1 not in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-@@ -1888,19 +2268,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- tok=user1_tok,
- )
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because we were joined before the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- displayname_change_before_token_range_response["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1915,18 +2310,22 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should *NOT* be `newly_joined` because we joined before the token range
- self.assertTrue(room_id1 not in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-
-- def test_display_name_changes_leave_after_token_range(
-+ def test_newly_joined_display_name_changes_leave_after_token_range(
- self,
- ) -> None:
- """
- Test that we point to the correct membership event within the from/to range even
-- if there are multiple `join` membership events in a row indicating
-- `displayname`/`avatar_url` updates and we leave after the `to_token`.
-+ if we are `newly_joined` and there are multiple `join` membership events in a
-+ row indicating `displayname`/`avatar_url` updates and we leave after the
-+ `to_token`.
-
- See condition "1a)" comments in the `get_room_membership_for_user_at_to_token()` method.
- """
-@@ -1941,6 +2340,7 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- # leave and can still re-join.
- room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok, is_public=True)
- join_response = self.helper.join(room_id1, user1_id, tok=user1_tok)
-+
- # Update the displayname during the token range
- displayname_change_during_token_range_response = self.helper.send_state(
- room_id1,
-@@ -1970,19 +2370,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- # Leave after the token
- self.helper.leave(room_id1, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because we were joined during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- displayname_change_during_token_range_response["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -1997,11 +2412,118 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should be `newly_joined` because we joined during the token range
- self.assertTrue(room_id1 in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-
-+ def test_display_name_changes_leave_after_token_range(
-+ self,
-+ ) -> None:
-+ """
-+ Test that we point to the correct membership event within the from/to range even
-+ if there are multiple `join` membership events in a row indicating
-+ `displayname`/`avatar_url` updates and we leave after the `to_token`.
-+
-+ See condition "1a)" comments in the `get_room_membership_for_user_at_to_token()` method.
-+ """
-+ user1_id = self.register_user("user1", "pass")
-+ user1_tok = self.login(user1_id, "pass")
-+ user2_id = self.register_user("user2", "pass")
-+ user2_tok = self.login(user2_id, "pass")
-+
-+ _before_room1_token = self.event_sources.get_current_token()
-+
-+ # We create the room with user2 so the room isn't left with no members when we
-+ # leave and can still re-join.
-+ room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok, is_public=True)
-+ join_response = self.helper.join(room_id1, user1_id, tok=user1_tok)
-+
-+ after_join_token = self.event_sources.get_current_token()
-+
-+ # Update the displayname during the token range
-+ displayname_change_during_token_range_response = self.helper.send_state(
-+ room_id1,
-+ event_type=EventTypes.Member,
-+ state_key=user1_id,
-+ body={
-+ "membership": Membership.JOIN,
-+ "displayname": "displayname during token range",
-+ },
-+ tok=user1_tok,
-+ )
-+
-+ after_display_name_change_token = self.event_sources.get_current_token()
-+
-+ # Update the displayname after the token range
-+ displayname_change_after_token_range_response = self.helper.send_state(
-+ room_id1,
-+ event_type=EventTypes.Member,
-+ state_key=user1_id,
-+ body={
-+ "membership": Membership.JOIN,
-+ "displayname": "displayname after token range",
-+ },
-+ tok=user1_tok,
-+ )
-+
-+ # Leave after the token
-+ self.helper.leave(room_id1, user1_id, tok=user1_tok)
-+
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
-+ from_token=after_join_token,
-+ to_token=after_display_name_change_token,
-+ )
-+ )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-+
-+ # Room should show up because we were joined during the from/to range
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
-+ # It should be pointing to the latest membership event in the from/to range
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
-+ displayname_change_during_token_range_response["event_id"],
-+ "Corresponding map to disambiguate the opaque event IDs: "
-+ + str(
-+ {
-+ "join_response": join_response["event_id"],
-+ "displayname_change_during_token_range_response": displayname_change_during_token_range_response[
-+ "event_id"
-+ ],
-+ "displayname_change_after_token_range_response": displayname_change_after_token_range_response[
-+ "event_id"
-+ ],
-+ }
-+ ),
-+ )
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
-+ # We only changed our display name during the token range so we shouldn't be
-+ # considered `newly_joined` or `newly_left`
-+ self.assertTrue(room_id1 not in newly_joined)
-+ self.assertTrue(room_id1 not in newly_left)
-+
- def test_display_name_changes_join_after_token_range(
- self,
- ) -> None:
-@@ -2038,16 +2560,29 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- tok=user1_tok,
- )
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-
- # Room shouldn't show up because we joined after the from/to range
-- self.assertEqual(room_id_results.keys(), set())
-+ self.assertIncludes(room_id_results, set(), exact=True)
-
- def test_newly_joined_with_leave_join_in_token_range(
- self,
-@@ -2074,22 +2609,40 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- after_more_changes_token = self.event_sources.get_current_token()
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=after_room1_token,
- to_token=after_more_changes_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because we were joined during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_response2["event_id"],
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should be considered `newly_joined` because there is some non-join event in
- # between our latest join event.
- self.assertTrue(room_id1 in newly_joined)
-@@ -2139,19 +2692,34 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- after_room1_token = self.event_sources.get_current_token()
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room1_token,
- to_token=after_room1_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room should show up because it was newly_left and joined during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1})
-+ self.assertIncludes(room_id_results, {room_id1}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- displayname_change_during_token_range_response2["event_id"],
- "Corresponding map to disambiguate the opaque event IDs: "
- + str(
-@@ -2166,7 +2734,10 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- }
- ),
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should be `newly_joined` because we first joined during the token range
- self.assertTrue(room_id1 in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-@@ -2192,7 +2763,7 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- # Invited and left the room before the token
- self.helper.invite(room_id1, src=user2_id, targ=user1_id, tok=user2_tok)
-- leave_room1_response = self.helper.leave(room_id1, user1_id, tok=user1_tok)
-+ _leave_room1_response = self.helper.leave(room_id1, user1_id, tok=user1_tok)
- # Invited to room2
- invite_room2_response = self.helper.invite(
- room_id2, src=user2_id, targ=user1_id, tok=user2_tok
-@@ -2215,45 +2786,52 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- # Leave room3
- self.helper.leave(room_id3, user1_id, tok=user1_tok)
-
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_room3_token,
- to_token=after_room3_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
-- self.assertEqual(
-- room_id_results.keys(),
-+ self.assertIncludes(
-+ room_id_results,
- {
-- # Left before the from/to range
-- room_id1,
-+ # Excluded because we left before the from/to range
-+ # room_id1,
- # Invited before the from/to range
- room_id2,
- # `newly_left` during the from/to range
- room_id3,
- },
-+ exact=True,
- )
-
-- # Room1
-- # It should be pointing to the latest membership event in the from/to range
-- self.assertEqual(
-- room_id_results[room_id1].event_id,
-- leave_room1_response["event_id"],
-- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.LEAVE)
-- # We should *NOT* be `newly_joined`/`newly_left` because we were invited and left
-- # before the token range
-- self.assertTrue(room_id1 not in newly_joined)
-- self.assertTrue(room_id1 not in newly_left)
--
- # Room2
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id2].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id2].event_id,
- invite_room2_response["event_id"],
- )
-- self.assertEqual(room_id_results[room_id2].membership, Membership.INVITE)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id2].membership,
-+ Membership.INVITE,
-+ )
- # We should *NOT* be `newly_joined`/`newly_left` because we were invited before
- # the token range
- self.assertTrue(room_id2 not in newly_joined)
-@@ -2262,10 +2840,13 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- # Room3
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id3].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id3].event_id,
- leave_room3_response["event_id"],
- )
-- self.assertEqual(room_id_results[room_id3].membership, Membership.LEAVE)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id3].membership,
-+ Membership.LEAVE,
-+ )
- # We should be `newly_left` because we were invited and left during
- # the token range
- self.assertTrue(room_id3 not in newly_joined)
-@@ -2282,7 +2863,16 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
- user2_tok = self.login(user2_id, "pass")
-
- # The room where the state reset will happen
-- room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok)
-+ room_id1 = self.helper.create_room_as(
-+ user2_id,
-+ is_public=True,
-+ tok=user2_tok,
-+ )
-+ # Create a dummy event for us to point back to for the state reset
-+ dummy_event_response = self.helper.send(room_id1, "test", tok=user2_tok)
-+ dummy_event_id = dummy_event_response["event_id"]
-+
-+ # Join after the dummy event
- join_response1 = self.helper.join(room_id1, user1_id, tok=user1_tok)
-
- # Join another room so we don't hit the short-circuit and return early if they
-@@ -2292,92 +2882,97 @@ class GetRoomMembershipForUserAtToTokenTestCase(HomeserverTestCase):
-
- before_reset_token = self.event_sources.get_current_token()
-
-- # Send another state event to make a position for the state reset to happen at
-- dummy_state_response = self.helper.send_state(
-- room_id1,
-- event_type="foobarbaz",
-- state_key="",
-- body={"foo": "bar"},
-- tok=user2_tok,
-- )
-- dummy_state_pos = self.get_success(
-- self.store.get_position_for_event(dummy_state_response["event_id"])
-- )
--
-- # Mock a state reset removing the membership for user1 in the current state
-- self.get_success(
-- self.store.db_pool.simple_delete(
-- table="current_state_events",
-- keyvalues={
-- "room_id": room_id1,
-- "type": EventTypes.Member,
-- "state_key": user1_id,
-- },
-- desc="state reset user in current_state_events",
-+ # Trigger a state reset
-+ join_rule_event, join_rule_context = self.get_success(
-+ create_event(
-+ self.hs,
-+ prev_event_ids=[dummy_event_id],
-+ type=EventTypes.JoinRules,
-+ state_key="",
-+ content={"join_rule": JoinRules.INVITE},
-+ sender=user2_id,
-+ room_id=room_id1,
-+ room_version=self.get_success(self.store.get_room_version_id(room_id1)),
- )
- )
-- self.get_success(
-- self.store.db_pool.simple_delete(
-- table="local_current_membership",
-- keyvalues={
-- "room_id": room_id1,
-- "user_id": user1_id,
-- },
-- desc="state reset user in local_current_membership",
-- )
-- )
-- self.get_success(
-- self.store.db_pool.simple_insert(
-- table="current_state_delta_stream",
-- values={
-- "stream_id": dummy_state_pos.stream,
-- "room_id": room_id1,
-- "type": EventTypes.Member,
-- "state_key": user1_id,
-- "event_id": None,
-- "prev_event_id": join_response1["event_id"],
-- "instance_name": dummy_state_pos.instance_name,
-- },
-- desc="state reset user in current_state_delta_stream",
-- )
-+ _, join_rule_event_pos, _ = self.get_success(
-+ self.persistence.persist_event(join_rule_event, join_rule_context)
- )
-
-- # Manually bust the cache since we we're just manually messing with the database
-- # and not causing an actual state reset.
-- self.store._membership_stream_cache.entity_has_changed(
-- user1_id, dummy_state_pos.stream
-- )
-+ # Ensure that the state reset worked and only user2 is in the room now
-+ users_in_room = self.get_success(self.store.get_users_in_room(room_id1))
-+ self.assertIncludes(set(users_in_room), {user2_id}, exact=True)
-
- after_reset_token = self.event_sources.get_current_token()
-
- # The function under test
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_reset_token,
- to_token=after_reset_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
- # Room1 should show up because it was `newly_left` via state reset during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1, room_id2})
-+ self.assertIncludes(room_id_results, {room_id1, room_id2}, exact=True)
- # It should be pointing to no event because we were removed from the room
- # without a corresponding leave event
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- None,
-+ "Corresponding map to disambiguate the opaque event IDs: "
-+ + str(
-+ {
-+ "join_response1": join_response1["event_id"],
-+ }
-+ ),
- )
- # State reset caused us to leave the room and there is no corresponding leave event
-- self.assertEqual(room_id_results[room_id1].membership, Membership.LEAVE)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.LEAVE,
-+ )
- # We should *NOT* be `newly_joined` because we joined before the token range
- self.assertTrue(room_id1 not in newly_joined)
- # We should be `newly_left` because we were removed via state reset during the from/to range
- self.assertTrue(room_id1 in newly_left)
-
-
--class GetRoomMembershipForUserAtToTokenShardTestCase(BaseMultiWorkerStreamTestCase):
-+# FIXME: This can be removed once we bump `SCHEMA_COMPAT_VERSION` and run the
-+# foreground update for
-+# `sliding_sync_joined_rooms`/`sliding_sync_membership_snapshots` (tracked by
-+# https://github.com/element-hq/synapse/issues/17623)
-+@parameterized_class(
-+ ("use_new_tables",),
-+ [
-+ (True,),
-+ (False,),
-+ ],
-+ class_name_func=lambda cls,
-+ num,
-+ params_dict: f"{cls.__name__}_{'new' if params_dict['use_new_tables'] else 'fallback'}",
-+)
-+class ComputeInterestedRoomsShardTestCase(
-+ BaseMultiWorkerStreamTestCase, SlidingSyncBase
-+):
- """
-- Tests Sliding Sync handler `get_room_membership_for_user_at_to_token()` to make sure it works with
-+ Tests Sliding Sync handler `compute_interested_rooms()` to make sure it works with
- sharded event stream_writers enabled
- """
-
-@@ -2475,7 +3070,7 @@ class GetRoomMembershipForUserAtToTokenShardTestCase(BaseMultiWorkerStreamTestCa
- join_response1 = self.helper.join(room_id1, user1_id, tok=user1_tok)
- join_response2 = self.helper.join(room_id2, user1_id, tok=user1_tok)
- # Leave room2
-- leave_room2_response = self.helper.leave(room_id2, user1_id, tok=user1_tok)
-+ _leave_room2_response = self.helper.leave(room_id2, user1_id, tok=user1_tok)
- join_response3 = self.helper.join(room_id3, user1_id, tok=user1_tok)
- # Leave room3
- self.helper.leave(room_id3, user1_id, tok=user1_tok)
-@@ -2565,57 +3160,74 @@ class GetRoomMembershipForUserAtToTokenShardTestCase(BaseMultiWorkerStreamTestCa
- self.get_success(actx.__aexit__(None, None, None))
-
- # The function under test
-- room_id_results, newly_joined, newly_left = self.get_success(
-- self.sliding_sync_handler.room_lists.get_room_membership_for_user_at_to_token(
-- UserID.from_string(user1_id),
-+ interested_rooms = self.get_success(
-+ self.sliding_sync_handler.room_lists.compute_interested_rooms(
-+ SlidingSyncConfig(
-+ user=UserID.from_string(user1_id),
-+ requester=create_requester(user_id=user1_id),
-+ lists={
-+ "foo-list": SlidingSyncConfig.SlidingSyncList(
-+ ranges=[(0, 99)],
-+ required_state=[],
-+ timeline_limit=1,
-+ )
-+ },
-+ conn_id=None,
-+ ),
-+ PerConnectionState(),
- from_token=before_stuck_activity_token,
- to_token=stuck_activity_token,
- )
- )
-+ room_id_results = set(interested_rooms.lists["foo-list"].ops[0].room_ids)
-+ newly_joined = interested_rooms.newly_joined_rooms
-+ newly_left = interested_rooms.newly_left_rooms
-
-- self.assertEqual(
-- room_id_results.keys(),
-+ self.assertIncludes(
-+ room_id_results,
- {
- room_id1,
-- room_id2,
-+ # Excluded because we left before the from/to range and the second join
-+ # event happened while worker2 was stuck and technically occurs after
-+ # the `stuck_activity_token`.
-+ # room_id2,
- room_id3,
- },
-+ exact=True,
-+ message="Corresponding map to disambiguate the opaque room IDs: "
-+ + str(
-+ {
-+ "room_id1": room_id1,
-+ "room_id2": room_id2,
-+ "room_id3": room_id3,
-+ }
-+ ),
- )
-
- # Room1
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id1].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id1].event_id,
- join_room1_response["event_id"],
- )
-- self.assertEqual(room_id_results[room_id1].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id1].membership,
-+ Membership.JOIN,
-+ )
- # We should be `newly_joined` because we joined during the token range
- self.assertTrue(room_id1 in newly_joined)
- self.assertTrue(room_id1 not in newly_left)
-
-- # Room2
-- # It should be pointing to the latest membership event in the from/to range
-- self.assertEqual(
-- room_id_results[room_id2].event_id,
-- leave_room2_response["event_id"],
-- )
-- self.assertEqual(room_id_results[room_id2].membership, Membership.LEAVE)
-- # room_id2 should *NOT* be considered `newly_left` because we left before the
-- # from/to range and the join event during the range happened while worker2 was
-- # stuck. This means that from the perspective of the master, where the
-- # `stuck_activity_token` is generated, the stream position for worker2 wasn't
-- # advanced to the join yet. Looking at the `instance_map`, the join technically
-- # comes after `stuck_activity_token`.
-- self.assertTrue(room_id2 not in newly_joined)
-- self.assertTrue(room_id2 not in newly_left)
--
- # Room3
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
-- room_id_results[room_id3].event_id,
-+ interested_rooms.room_membership_for_user_map[room_id3].event_id,
- join_on_worker3_response["event_id"],
- )
-- self.assertEqual(room_id_results[room_id3].membership, Membership.JOIN)
-+ self.assertEqual(
-+ interested_rooms.room_membership_for_user_map[room_id3].membership,
-+ Membership.JOIN,
-+ )
- # We should be `newly_joined` because we joined during the token range
- self.assertTrue(room_id3 in newly_joined)
- self.assertTrue(room_id3 not in newly_left)
-@@ -2645,6 +3257,9 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
- self.store = self.hs.get_datastores().main
- self.event_sources = hs.get_event_sources()
- self.storage_controllers = hs.get_storage_controllers()
-+ persistence = self.hs.get_storage_controllers().persistence
-+ assert persistence is not None
-+ self.persistence = persistence
-
- def _get_sync_room_ids_for_user(
- self,
-@@ -2687,7 +3302,7 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
- to_token=now_token,
- )
-
-- self.assertEqual(room_id_results.keys(), set())
-+ self.assertIncludes(room_id_results.keys(), set(), exact=True)
-
- def test_basic_rooms(self) -> None:
- """
-@@ -2753,7 +3368,7 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
- )
-
- # Ensure that the invited, ban, and knock rooms show up
-- self.assertEqual(
-+ self.assertIncludes(
- room_id_results.keys(),
- {
- join_room_id,
-@@ -2761,6 +3376,7 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
- ban_room_id,
- knock_room_id,
- },
-+ exact=True,
- )
- # It should be pointing to the the respective membership event (latest
- # membership event in the from/to range)
-@@ -2824,7 +3440,7 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
- )
-
- # Only the `newly_left` room should show up
-- self.assertEqual(room_id_results.keys(), {room_id2})
-+ self.assertIncludes(room_id_results.keys(), {room_id2}, exact=True)
- self.assertEqual(
- room_id_results[room_id2].event_id,
- _leave_response2["event_id"],
-@@ -2869,7 +3485,7 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
- )
-
- # The kicked room should show up
-- self.assertEqual(room_id_results.keys(), {kick_room_id})
-+ self.assertIncludes(room_id_results.keys(), {kick_room_id}, exact=True)
- # It should be pointing to the latest membership event in the from/to range
- self.assertEqual(
- room_id_results[kick_room_id].event_id,
-@@ -2893,8 +3509,17 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
- user2_tok = self.login(user2_id, "pass")
-
- # The room where the state reset will happen
-- room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok)
-- join_response1 = self.helper.join(room_id1, user1_id, tok=user1_tok)
-+ room_id1 = self.helper.create_room_as(
-+ user2_id,
-+ is_public=True,
-+ tok=user2_tok,
-+ )
-+ # Create a dummy event for us to point back to for the state reset
-+ dummy_event_response = self.helper.send(room_id1, "test", tok=user2_tok)
-+ dummy_event_id = dummy_event_response["event_id"]
-+
-+ # Join after the dummy event
-+ self.helper.join(room_id1, user1_id, tok=user1_tok)
-
- # Join another room so we don't hit the short-circuit and return early if they
- # have no room membership
-@@ -2903,61 +3528,26 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
-
- before_reset_token = self.event_sources.get_current_token()
-
-- # Send another state event to make a position for the state reset to happen at
-- dummy_state_response = self.helper.send_state(
-- room_id1,
-- event_type="foobarbaz",
-- state_key="",
-- body={"foo": "bar"},
-- tok=user2_tok,
-- )
-- dummy_state_pos = self.get_success(
-- self.store.get_position_for_event(dummy_state_response["event_id"])
-- )
--
-- # Mock a state reset removing the membership for user1 in the current state
-- self.get_success(
-- self.store.db_pool.simple_delete(
-- table="current_state_events",
-- keyvalues={
-- "room_id": room_id1,
-- "type": EventTypes.Member,
-- "state_key": user1_id,
-- },
-- desc="state reset user in current_state_events",
-- )
-- )
-- self.get_success(
-- self.store.db_pool.simple_delete(
-- table="local_current_membership",
-- keyvalues={
-- "room_id": room_id1,
-- "user_id": user1_id,
-- },
-- desc="state reset user in local_current_membership",
-+ # Trigger a state reset
-+ join_rule_event, join_rule_context = self.get_success(
-+ create_event(
-+ self.hs,
-+ prev_event_ids=[dummy_event_id],
-+ type=EventTypes.JoinRules,
-+ state_key="",
-+ content={"join_rule": JoinRules.INVITE},
-+ sender=user2_id,
-+ room_id=room_id1,
-+ room_version=self.get_success(self.store.get_room_version_id(room_id1)),
- )
- )
-- self.get_success(
-- self.store.db_pool.simple_insert(
-- table="current_state_delta_stream",
-- values={
-- "stream_id": dummy_state_pos.stream,
-- "room_id": room_id1,
-- "type": EventTypes.Member,
-- "state_key": user1_id,
-- "event_id": None,
-- "prev_event_id": join_response1["event_id"],
-- "instance_name": dummy_state_pos.instance_name,
-- },
-- desc="state reset user in current_state_delta_stream",
-- )
-+ _, join_rule_event_pos, _ = self.get_success(
-+ self.persistence.persist_event(join_rule_event, join_rule_context)
- )
-
-- # Manually bust the cache since we we're just manually messing with the database
-- # and not causing an actual state reset.
-- self.store._membership_stream_cache.entity_has_changed(
-- user1_id, dummy_state_pos.stream
-- )
-+ # Ensure that the state reset worked and only user2 is in the room now
-+ users_in_room = self.get_success(self.store.get_users_in_room(room_id1))
-+ self.assertIncludes(set(users_in_room), {user2_id}, exact=True)
-
- after_reset_token = self.event_sources.get_current_token()
-
-@@ -2969,7 +3559,7 @@ class FilterRoomsRelevantForSyncTestCase(HomeserverTestCase):
- )
-
- # Room1 should show up because it was `newly_left` via state reset during the from/to range
-- self.assertEqual(room_id_results.keys(), {room_id1, room_id2})
-+ self.assertIncludes(room_id_results.keys(), {room_id1, room_id2}, exact=True)
- # It should be pointing to no event because we were removed from the room
- # without a corresponding leave event
- self.assertEqual(
---
-2.49.0
-
|