Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 831a7a4

Browse files
committed
Add some basic tests about requests getting deduplicated
More to follow when #10825 is ready.
1 parent 7dcdab4 commit 831a7a4

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

mypy.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ files =
8787
tests/handlers/test_sync.py,
8888
tests/rest/client/test_login.py,
8989
tests/rest/client/test_auth.py,
90+
tests/storage/databases/test_state_store.py,
9091
tests/storage/test_state.py,
9192
tests/util/test_itertools.py,
9293
tests/util/test_stream_change_cache.py
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
from typing import Dict, List, Sequence, Tuple
2+
from unittest.mock import patch
3+
4+
from twisted.internet.defer import Deferred, ensureDeferred
5+
6+
from synapse.storage.state import StateFilter
7+
from synapse.types import MutableStateMap, StateMap
8+
9+
from tests.unittest import HomeserverTestCase
10+
11+
12+
class StateGroupInflightCachingTestCase(HomeserverTestCase):
13+
def setUp(self) -> None:
14+
super(StateGroupInflightCachingTestCase, self).setUp()
15+
# Patch out the `_get_state_groups_from_groups`.
16+
# This is useful because it lets us pretend we have a slow database.
17+
gsgfg_patch = patch(
18+
"synapse.storage.databases.state.store.StateGroupDataStore._get_state_groups_from_groups",
19+
self._fake_get_state_groups_from_groups,
20+
)
21+
gsgfg_patch.start()
22+
self.addCleanup(gsgfg_patch.stop)
23+
self.gsgfg_calls: List[
24+
Tuple[Tuple[int, ...], StateFilter, Deferred[Dict[int, StateMap[str]]]]
25+
] = []
26+
27+
def prepare(self, reactor, clock, homeserver) -> None:
28+
super(StateGroupInflightCachingTestCase, self).prepare(
29+
reactor, clock, homeserver
30+
)
31+
self.state_storage = homeserver.get_storage().state
32+
self.state_datastore = homeserver.get_datastores().state
33+
34+
def _fake_get_state_groups_from_groups(
35+
self, groups: Sequence[int], state_filter: StateFilter
36+
) -> "Deferred[Dict[int, StateMap[str]]]":
37+
print("hi", groups, state_filter)
38+
d: Deferred[Dict[int, StateMap[str]]] = Deferred()
39+
self.gsgfg_calls.append((tuple(groups), state_filter, d))
40+
return d
41+
42+
def _complete_request_fake(
43+
self,
44+
groups: Tuple[int, ...],
45+
state_filter: StateFilter,
46+
d: "Deferred[Dict[int, StateMap[str]]]",
47+
) -> None:
48+
"""
49+
Assemble a fake database response and complete the database request.
50+
"""
51+
52+
result: Dict[int, StateMap[str]] = {}
53+
54+
for group in groups:
55+
group_result: MutableStateMap[str] = {}
56+
result[group] = group_result
57+
58+
for state_type, state_keys in state_filter.types.items():
59+
if state_keys is None:
60+
group_result[
61+
(state_type, "wild wombat")
62+
] = f"{group} {state_type} wild wombat"
63+
group_result[
64+
(state_type, "wild spqr")
65+
] = f"{group} {state_type} wild spqr"
66+
else:
67+
for state_key in state_keys:
68+
group_result[
69+
(state_type, state_key)
70+
] = f"{group} {state_type} {state_key}"
71+
72+
if state_filter.include_others:
73+
group_result[("something.else", "wild")] = "card"
74+
75+
d.callback(result)
76+
77+
def test_duplicate_requests_deduplicated(self) -> None:
78+
req1 = ensureDeferred(
79+
self.state_datastore._get_state_for_group_using_inflight_cache(
80+
42, StateFilter.all()
81+
)
82+
)
83+
self.pump(by=0.1)
84+
85+
# This should have gone to the database
86+
self.assertEqual(len(self.gsgfg_calls), 1)
87+
self.assertFalse(req1.called)
88+
89+
req2 = ensureDeferred(
90+
self.state_datastore._get_state_for_group_using_inflight_cache(
91+
42, StateFilter.all()
92+
)
93+
)
94+
self.pump(by=0.1)
95+
96+
# No more calls should have gone to the database
97+
self.assertEqual(len(self.gsgfg_calls), 1)
98+
self.assertFalse(req1.called)
99+
self.assertFalse(req2.called)
100+
101+
groups, sf, d = self.gsgfg_calls[0]
102+
self.assertEqual(groups, (42,))
103+
self.assertEqual(sf, StateFilter.all())
104+
105+
# Now we can complete the request
106+
self._complete_request_fake(groups, sf, d)
107+
108+
self.assertEqual(self.get_success(req1), {("something.else", "wild"): "card"})
109+
self.assertEqual(self.get_success(req2), {("something.else", "wild"): "card"})

0 commit comments

Comments
 (0)