|
33 | 33 | )
|
34 | 34 | from synapse.api.room_versions import RoomVersions
|
35 | 35 | from synapse.handlers.sliding_sync import (
|
| 36 | + MAX_NUMBER_STATE_KEYS_TO_REMEMBER, |
36 | 37 | RoomsForUserType,
|
37 | 38 | RoomSyncConfig,
|
38 | 39 | StateValues,
|
@@ -3319,6 +3320,32 @@ class RequiredStateChangesTestCase(unittest.TestCase):
|
3319 | 3320 | ),
|
3320 | 3321 | ),
|
3321 | 3322 | ),
|
| 3323 | + ( |
| 3324 | + "simple_retain_previous_state_keys", |
| 3325 | + """Test adding a state key to the config and retaining a previously sent state_key""", |
| 3326 | + RequiredStateChangesTestParameters( |
| 3327 | + previous_required_state_map={"type": {"state_key1"}}, |
| 3328 | + request_required_state_map={"type": {"state_key2", "state_key3"}}, |
| 3329 | + state_deltas={("type", "state_key2"): "$event_id"}, |
| 3330 | + expected_with_state_deltas=( |
| 3331 | + # We've added a key so we should persist the changed required state |
| 3332 | + # config. |
| 3333 | + # |
| 3334 | + # Retain `state_key1` from the `previous_required_state_map` |
| 3335 | + {"type": {"state_key1", "state_key2", "state_key3"}}, |
| 3336 | + # We should see the new state_keys added |
| 3337 | + StateFilter.from_types( |
| 3338 | + [("type", "state_key2"), ("type", "state_key3")] |
| 3339 | + ), |
| 3340 | + ), |
| 3341 | + expected_without_state_deltas=( |
| 3342 | + {"type": {"state_key1", "state_key2", "state_key3"}}, |
| 3343 | + StateFilter.from_types( |
| 3344 | + [("type", "state_key2"), ("type", "state_key3")] |
| 3345 | + ), |
| 3346 | + ), |
| 3347 | + ), |
| 3348 | + ), |
3322 | 3349 | (
|
3323 | 3350 | "simple_remove_type",
|
3324 | 3351 | """
|
@@ -3894,6 +3921,14 @@ class RequiredStateChangesTestCase(unittest.TestCase):
|
3894 | 3921 | # sent it before and send the new state. (if we were tracking
|
3895 | 3922 | # that we sent any other state, we should still keep track
|
3896 | 3923 | # that).
|
| 3924 | + # |
| 3925 | + # This acts the same as the `simple_remove_type` test. It's |
| 3926 | + # possible that we could remember the specific `state_keys` that |
| 3927 | + # we have sent down before but this currently just acts the same |
| 3928 | + # as if a whole `type` was removed. Perhaps it's good that we |
| 3929 | + # "garbage collect" and forget what we've sent before for a |
| 3930 | + # given `type` when the client stops caring about a certain |
| 3931 | + # `type`. |
3897 | 3932 | {},
|
3898 | 3933 | # We don't need to request anything more if they are requesting
|
3899 | 3934 | # less state now
|
@@ -4133,3 +4168,79 @@ def test_xxx(
|
4133 | 4168 | test_parameters.expected_with_state_deltas[1],
|
4134 | 4169 | "added_state_filter does not match (with state_deltas)",
|
4135 | 4170 | )
|
| 4171 | + |
| 4172 | + @parameterized.expand( |
| 4173 | + [ |
| 4174 | + # Test with a normal arbitrary type (no special meaning) |
| 4175 | + ("arbitrary_type", "type", set()), |
| 4176 | + # Test with membership |
| 4177 | + ("membership", EventTypes.Member, set()), |
| 4178 | + # Test with lazy-loading room members |
| 4179 | + ("lazy_loading_membership", EventTypes.Member, {StateValues.LAZY}), |
| 4180 | + ] |
| 4181 | + ) |
| 4182 | + def test_limit_retained_previous_state_keys( |
| 4183 | + self, |
| 4184 | + _test_label: str, |
| 4185 | + event_type: str, |
| 4186 | + extra_state_keys: Set[str], |
| 4187 | + ) -> None: |
| 4188 | + """ |
| 4189 | + Test that we limit the number of state_keys that we remember but always include |
| 4190 | + the state_keys that we've just requested. |
| 4191 | + """ |
| 4192 | + previous_required_state_map = { |
| 4193 | + event_type: { |
| 4194 | + # Prefix the state_keys we've "prev_"iously sent so they are easier to |
| 4195 | + # identify in our assertions. |
| 4196 | + f"prev_state_key{i}" |
| 4197 | + for i in range(MAX_NUMBER_STATE_KEYS_TO_REMEMBER - 30) |
| 4198 | + } |
| 4199 | + | extra_state_keys |
| 4200 | + } |
| 4201 | + request_required_state_map = { |
| 4202 | + event_type: {f"state_key{i}" for i in range(50)} | extra_state_keys |
| 4203 | + } |
| 4204 | + |
| 4205 | + # (function under test) |
| 4206 | + changed_required_state_map, added_state_filter = _required_state_changes( |
| 4207 | + user_id="@user:test", |
| 4208 | + prev_required_state_map=previous_required_state_map, |
| 4209 | + request_required_state_map=request_required_state_map, |
| 4210 | + state_deltas={}, |
| 4211 | + ) |
| 4212 | + assert changed_required_state_map is not None |
| 4213 | + |
| 4214 | + # We should only remember up to the maximum number of state keys |
| 4215 | + self.assertGreaterEqual( |
| 4216 | + len(changed_required_state_map[event_type]), |
| 4217 | + # Most of the time this will be `MAX_NUMBER_STATE_KEYS_TO_REMEMBER` but |
| 4218 | + # because we are just naively selecting enough previous state_keys to fill |
| 4219 | + # the limit, there might be some overlap in what's added back which means we |
| 4220 | + # might have slightly less than the limit. |
| 4221 | + # |
| 4222 | + # `extra_state_keys` overlaps in the previous and requested |
| 4223 | + # `required_state_map` so we might see this this scenario. |
| 4224 | + MAX_NUMBER_STATE_KEYS_TO_REMEMBER - len(extra_state_keys), |
| 4225 | + ) |
| 4226 | + |
| 4227 | + # Should include all of the requested state |
| 4228 | + self.assertIncludes( |
| 4229 | + changed_required_state_map[event_type], |
| 4230 | + request_required_state_map[event_type], |
| 4231 | + ) |
| 4232 | + # And the rest is filled with the previous state keys |
| 4233 | + # |
| 4234 | + # We can't assert the exact state_keys since we don't know the order so we just |
| 4235 | + # check that they all start with "prev_" and that we have the correct amount. |
| 4236 | + remaining_state_keys = ( |
| 4237 | + changed_required_state_map[event_type] |
| 4238 | + - request_required_state_map[event_type] |
| 4239 | + ) |
| 4240 | + self.assertGreater( |
| 4241 | + len(remaining_state_keys), |
| 4242 | + 0, |
| 4243 | + ) |
| 4244 | + assert all( |
| 4245 | + state_key.startswith("prev_") for state_key in remaining_state_keys |
| 4246 | + ), "Remaining state_keys should be the previous state_keys" |
0 commit comments