Add tests

This commit is contained in:
Erik Johnston 2024-10-03 16:10:41 +01:00
parent af9c72db9d
commit 2fd3a5abae

View file

@ -18,7 +18,7 @@
# #
# #
import logging import logging
from typing import AbstractSet, Dict, Optional, Tuple from typing import AbstractSet, Dict, Optional, Set, Tuple
from unittest.mock import patch from unittest.mock import patch
from parameterized import parameterized from parameterized import parameterized
@ -35,6 +35,7 @@ from synapse.handlers.sliding_sync import (
RoomsForUserType, RoomsForUserType,
RoomSyncConfig, RoomSyncConfig,
StateValues, StateValues,
_required_state_changes,
) )
from synapse.rest import admin from synapse.rest import admin
from synapse.rest.client import knock, login, room from synapse.rest.client import knock, login, room
@ -42,8 +43,10 @@ from synapse.server import HomeServer
from synapse.storage.util.id_generators import MultiWriterIdGenerator from synapse.storage.util.id_generators import MultiWriterIdGenerator
from synapse.types import JsonDict, StreamToken, UserID from synapse.types import JsonDict, StreamToken, UserID
from synapse.types.handlers.sliding_sync import SlidingSyncConfig from synapse.types.handlers.sliding_sync import SlidingSyncConfig
from synapse.types.state import StateFilter
from synapse.util import Clock from synapse.util import Clock
from tests import unittest
from tests.replication._base import BaseMultiWorkerStreamTestCase from tests.replication._base import BaseMultiWorkerStreamTestCase
from tests.unittest import HomeserverTestCase, TestCase from tests.unittest import HomeserverTestCase, TestCase
@ -3213,3 +3216,402 @@ class SortRoomsTestCase(HomeserverTestCase):
# We only care about the *latest* event in the room. # We only care about the *latest* event in the room.
[room_id1, room_id2], [room_id1, room_id2],
) )
class RequiredStateChangesTestCase(unittest.TestCase):
"""Test cases for `_required_state_changes`"""
def test_simple_no_change(self) -> None:
"""Test no change to required state"""
previous_required_state_map = {"type1": {"state_key"}}
request_required_state_map = previous_required_state_map
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# No changes
self.assertIsNone(to_persist)
self.assertEqual(added, StateFilter.none())
def test_simple_add_type(self) -> None:
"""Test adding a type to the config"""
previous_required_state_map = {"type1": {"state_key"}}
request_required_state_map = {"type1": {"state_key"}, "type2": {"state_key"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've added a type so we should persist the changed required state
# config.
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
# We should see the new type added
self.assertEqual(added, StateFilter.from_types([("type2", "state_key")]))
def test_simple_add_state_key(self) -> None:
"""Test adding a state key to the config"""
previous_required_state_map = {"type": {"state_key1"}}
request_required_state_map = {"type": {"state_key1", "state_key2"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've added a type so we should persist the changed required state
# config.
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.from_types([("type", "state_key2")]))
def test_simple_add_state_key_with_change(self) -> None:
"""Test adding a state key to the config, and see some changed state"""
previous_required_state_map = {"type": {"state_key1"}}
request_required_state_map = {"type": {"state_key1", "state_key2"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={("type", "state_key"): "$event_id"},
)
# We've added a type so we should persist the changed required state
# config.
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.from_types([("type", "state_key2")]))
def test_simple_remove_type_no_change(self) -> None:
"""Test removing a type from the config when there are no matching state
deltas not cause the persisted required state config to change"""
previous_required_state_map = {"type1": {"state_key"}, "type2": {"state_key"}}
request_required_state_map = {"type1": {"state_key"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've removed a type without a change, so nothing should change.
self.assertIsNone(to_persist)
self.assertEqual(added, StateFilter.none())
def test_simple_remove_type_change(self) -> None:
"""Test removing a type from the config when there are is a matching
state delta does cause the persisted required state config to change"""
previous_required_state_map = {"type1": {"state_key"}, "type2": {"state_key"}}
request_required_state_map = {"type1": {"state_key"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={("type2", "state_key"): "$event_id"},
)
# We've removed a type and there's been a change to that state, so we
# persist the change to required state.
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.none())
def test_type_wildcards_add(self) -> None:
"""Test that changing the wildcard type"""
previous_required_state_map = {"type1": {"state_key"}}
request_required_state_map = {"type1": {"state_key"}, "*": {"state_key"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've added a wildcard, so we persist the change and request everything
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.all())
def test_type_wildcards_remove(self) -> None:
"""Test that changing the wildcard type"""
previous_required_state_map = {"type1": {"state_key"}, "*": {"state_key"}}
request_required_state_map = {"type1": {"state_key"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've added a wildcard, so we persist the change but don't request anything
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.none())
def test_state_key_wildcards_add(self) -> None:
"""Test that adding a wildcard to a type works"""
previous_required_state_map = {"type1": {"state_key"}}
request_required_state_map = {"type1": {"state_key"}, "type2": {"*"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've added a wildcard, so we persist the change and request the state
# for that type
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.from_types([("type2", None)]))
def test_state_key_wildcards_remove(self) -> None:
"""Test that removing a wildcard to a type works"""
previous_required_state_map = {"type1": {"state_key"}, "type2": {"*"}}
request_required_state_map = {"type1": {"state_key"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={("type2", "state_key"): "$event_id"},
)
# We've removed a wildcard, so we persist the change and request nothing
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.none())
def test_state_key_wildcards_remove_no_change(self) -> None:
"""Test that removing a wildcard to a type works"""
previous_required_state_map = {"type1": {"state_key"}, "type2": {"*"}}
request_required_state_map = {"type1": {"state_key"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've removed a wildcard but there have been no matching state
# changes, so we don't persist anything.
self.assertIsNone(to_persist)
self.assertEqual(added, StateFilter.none())
def test_state_key_remove_change_some(self) -> None:
"""Test that removing state keys work when only some of the state keys
have changed"""
previous_required_state_map = {
"type1": {"state_key1", "state_key2", "state_key3"}
}
request_required_state_map = {"type1": {"state_key1"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={("type1", "state_key3"): "$event_id"},
)
# We've removed some state keys from the type, but only state_key3 was
# changed so only that one should be removed.
assert to_persist is not None
self.assertDictEqual(to_persist, {"type1": {"state_key1", "state_key2"}})
self.assertEqual(added, StateFilter.none())
def test_state_key_added_me(self) -> None:
"""Test that adding state keys work when using "$ME"""
previous_required_state_map: Dict[str, Set[str]] = {}
request_required_state_map = {"type1": {"$ME"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've added the $ME state key, so we should see a persist for that
# change.
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.from_types([("type1", "@user:test")]))
def test_state_key_remove_me(self) -> None:
"""Test that removing state keys work when using "$ME"""
previous_required_state_map = {"type1": {"$ME"}}
request_required_state_map: Dict[str, Set[str]] = {}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={("type1", "@user:test"): "$event_id"},
)
# We've removed the $ME state key and seen a state change for the user,
# so we should see a persist for that change.
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.none())
def test_state_key_added_lazy(self) -> None:
"""Test that adding state keys work when using "$LAZY"""
previous_required_state_map: Dict[str, Set[str]] = {}
request_required_state_map = {"type1": {"$LAZY"}}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={},
)
# We've added the $LAZY state key, but that gets handled separately so
# it should not appear in `added`
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.none())
def test_state_key_remove_lazy(self) -> None:
"""Test that removing state keys work when using "$LAZY"""
previous_required_state_map = {"type1": {"$LAZY"}}
request_required_state_map: Dict[str, Set[str]] = {}
to_persist, added = _required_state_changes(
user_id="@user:test",
previous_room_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=previous_required_state_map,
),
room_sync_config=RoomSyncConfig(
timeline_limit=0,
required_state_map=request_required_state_map,
),
state_deltas={("type1", "@user:test"): "$event_id"},
)
# We've removed the $LAZY state key so we persist it when there has been
# any state delta for the type.
assert to_persist is not None
self.assertDictEqual(to_persist, request_required_state_map)
self.assertEqual(added, StateFilter.none())