test_state.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. # Copyright 2014-2016 OpenMarket Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from typing import (
  15. Any,
  16. Collection,
  17. Dict,
  18. Generator,
  19. Iterable,
  20. Iterator,
  21. List,
  22. Optional,
  23. Set,
  24. Tuple,
  25. cast,
  26. )
  27. from unittest.mock import Mock
  28. from twisted.internet import defer
  29. from synapse.api.auth import Auth
  30. from synapse.api.constants import EventTypes, Membership
  31. from synapse.api.room_versions import RoomVersions
  32. from synapse.events import EventBase, make_event_from_dict
  33. from synapse.events.snapshot import EventContext
  34. from synapse.state import StateHandler, StateResolutionHandler, _make_state_cache_entry
  35. from synapse.types import MutableStateMap, StateMap
  36. from synapse.types.state import StateFilter
  37. from synapse.util import Clock
  38. from synapse.util.macaroons import MacaroonGenerator
  39. from tests import unittest
  40. from .utils import MockClock, default_config
  41. _next_event_id = 1000
  42. def create_event(
  43. name: Optional[str] = None,
  44. type: Optional[str] = None,
  45. state_key: Optional[str] = None,
  46. depth: int = 2,
  47. event_id: Optional[str] = None,
  48. prev_events: Optional[List[Tuple[str, dict]]] = None,
  49. **kwargs: Any,
  50. ) -> EventBase:
  51. global _next_event_id
  52. if not event_id:
  53. _next_event_id += 1
  54. event_id = "$%s:test" % (_next_event_id,)
  55. if not name:
  56. if state_key is not None:
  57. name = "<%s-%s, %s>" % (type, state_key, event_id)
  58. else:
  59. name = "<%s, %s>" % (type, event_id)
  60. d = {
  61. "event_id": event_id,
  62. "type": type,
  63. "sender": "@user_id:example.com",
  64. "room_id": "!room_id:example.com",
  65. "depth": depth,
  66. "prev_events": prev_events or [],
  67. }
  68. if state_key is not None:
  69. d["state_key"] = state_key
  70. d.update(kwargs)
  71. return make_event_from_dict(d)
  72. class _DummyStore:
  73. def __init__(self) -> None:
  74. self._event_to_state_group: Dict[str, int] = {}
  75. self._group_to_state: Dict[int, MutableStateMap[str]] = {}
  76. self._event_id_to_event: Dict[str, EventBase] = {}
  77. self._next_group = 1
  78. async def get_state_groups_ids(
  79. self, room_id: str, event_ids: Collection[str]
  80. ) -> Dict[int, MutableStateMap[str]]:
  81. groups = {}
  82. for event_id in event_ids:
  83. group = self._event_to_state_group.get(event_id)
  84. if group:
  85. groups[group] = self._group_to_state[group]
  86. return groups
  87. async def get_state_ids_for_group(
  88. self, state_group: int, state_filter: Optional[StateFilter] = None
  89. ) -> MutableStateMap[str]:
  90. return self._group_to_state[state_group]
  91. async def store_state_group(
  92. self,
  93. event_id: str,
  94. room_id: str,
  95. prev_group: Optional[int],
  96. delta_ids: Optional[StateMap[str]],
  97. current_state_ids: Optional[StateMap[str]],
  98. ) -> int:
  99. state_group = self._next_group
  100. self._next_group += 1
  101. if current_state_ids is None:
  102. assert prev_group is not None
  103. assert delta_ids is not None
  104. current_state_ids = dict(self._group_to_state[prev_group])
  105. current_state_ids.update(delta_ids)
  106. self._group_to_state[state_group] = dict(current_state_ids)
  107. return state_group
  108. async def get_events(
  109. self, event_ids: Collection[str], **kwargs: Any
  110. ) -> Dict[str, EventBase]:
  111. return {
  112. e_id: self._event_id_to_event[e_id]
  113. for e_id in event_ids
  114. if e_id in self._event_id_to_event
  115. }
  116. async def get_partial_state_events(
  117. self, event_ids: Collection[str]
  118. ) -> Dict[str, bool]:
  119. return {e: False for e in event_ids}
  120. async def get_state_group_delta(
  121. self, name: str
  122. ) -> Tuple[Optional[int], Optional[StateMap[str]]]:
  123. return None, None
  124. def register_events(self, events: Iterable[EventBase]) -> None:
  125. for e in events:
  126. self._event_id_to_event[e.event_id] = e
  127. def register_event_context(self, event: EventBase, context: EventContext) -> None:
  128. assert context.state_group is not None
  129. self._event_to_state_group[event.event_id] = context.state_group
  130. def register_event_id_state_group(self, event_id: str, state_group: int) -> None:
  131. self._event_to_state_group[event_id] = state_group
  132. async def get_room_version_id(self, room_id: str) -> str:
  133. return RoomVersions.V1.identifier
  134. async def get_state_group_for_events(
  135. self, event_ids: Collection[str], await_full_state: bool = True
  136. ) -> Dict[str, int]:
  137. res = {}
  138. for event in event_ids:
  139. res[event] = self._event_to_state_group[event]
  140. return res
  141. async def get_state_for_groups(
  142. self, groups: Collection[int]
  143. ) -> Dict[int, MutableStateMap[str]]:
  144. res = {}
  145. for group in groups:
  146. state = self._group_to_state[group]
  147. res[group] = state
  148. return res
  149. class DictObj(dict):
  150. def __init__(self, **kwargs: Any) -> None:
  151. super().__init__(kwargs)
  152. self.__dict__ = self
  153. class Graph:
  154. def __init__(self, nodes: Dict[str, DictObj], edges: Dict[str, List[str]]):
  155. events: Dict[str, EventBase] = {}
  156. clobbered: Set[str] = set()
  157. for event_id, fields in nodes.items():
  158. refs = edges.get(event_id)
  159. if refs:
  160. clobbered.difference_update(refs)
  161. prev_events: List[Tuple[str, dict]] = [(r, {}) for r in refs]
  162. else:
  163. prev_events = []
  164. events[event_id] = create_event(
  165. event_id=event_id, prev_events=prev_events, **fields
  166. )
  167. self._leaves = clobbered
  168. self._events = sorted(events.values(), key=lambda e: e.depth)
  169. def walk(self) -> Iterator[EventBase]:
  170. return iter(self._events)
  171. class StateTestCase(unittest.TestCase):
  172. def setUp(self) -> None:
  173. self.dummy_store = _DummyStore()
  174. storage_controllers = Mock(main=self.dummy_store, state=self.dummy_store)
  175. hs = Mock(
  176. spec_set=[
  177. "config",
  178. "get_datastores",
  179. "get_storage_controllers",
  180. "get_auth",
  181. "get_state_handler",
  182. "get_clock",
  183. "get_state_resolution_handler",
  184. "get_account_validity_handler",
  185. "get_macaroon_generator",
  186. "get_instance_name",
  187. "get_simple_http_client",
  188. "hostname",
  189. ]
  190. )
  191. clock = cast(Clock, MockClock())
  192. hs.config = default_config("tesths", True)
  193. hs.get_datastores.return_value = Mock(main=self.dummy_store)
  194. hs.get_state_handler.return_value = None
  195. hs.get_clock.return_value = clock
  196. hs.get_macaroon_generator.return_value = MacaroonGenerator(
  197. clock, "tesths", b"verysecret"
  198. )
  199. hs.get_auth.return_value = Auth(hs)
  200. hs.get_state_resolution_handler = lambda: StateResolutionHandler(hs)
  201. hs.get_storage_controllers.return_value = storage_controllers
  202. self.state = StateHandler(hs)
  203. self.event_id = 0
  204. @defer.inlineCallbacks
  205. def test_branch_no_conflict(self) -> Generator[defer.Deferred, Any, None]:
  206. graph = Graph(
  207. nodes={
  208. "START": DictObj(
  209. type=EventTypes.Create, state_key="", content={}, depth=1
  210. ),
  211. "A": DictObj(type=EventTypes.Message, depth=2),
  212. "B": DictObj(type=EventTypes.Message, depth=3),
  213. "C": DictObj(type=EventTypes.Name, state_key="", depth=3),
  214. "D": DictObj(type=EventTypes.Message, depth=4),
  215. },
  216. edges={"A": ["START"], "B": ["A"], "C": ["A"], "D": ["B", "C"]},
  217. )
  218. self.dummy_store.register_events(graph.walk())
  219. context_store: dict[str, EventContext] = {}
  220. for event in graph.walk():
  221. context = yield defer.ensureDeferred(
  222. self.state.compute_event_context(event)
  223. )
  224. self.dummy_store.register_event_context(event, context)
  225. context_store[event.event_id] = context
  226. ctx_c = context_store["C"]
  227. ctx_d = context_store["D"]
  228. prev_state_ids: StateMap[str]
  229. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  230. self.assertEqual(2, len(prev_state_ids))
  231. self.assertEqual(ctx_c.state_group, ctx_d.state_group_before_event)
  232. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  233. @defer.inlineCallbacks
  234. def test_branch_basic_conflict(
  235. self,
  236. ) -> Generator["defer.Deferred[object]", Any, None]:
  237. graph = Graph(
  238. nodes={
  239. "START": DictObj(
  240. type=EventTypes.Create,
  241. state_key="",
  242. content={"creator": "@user_id:example.com"},
  243. depth=1,
  244. ),
  245. "A": DictObj(
  246. type=EventTypes.Member,
  247. state_key="@user_id:example.com",
  248. content={"membership": Membership.JOIN},
  249. membership=Membership.JOIN,
  250. depth=2,
  251. ),
  252. "B": DictObj(type=EventTypes.Name, state_key="", depth=3),
  253. "C": DictObj(type=EventTypes.Name, state_key="", depth=4),
  254. "D": DictObj(type=EventTypes.Message, depth=5),
  255. },
  256. edges={"A": ["START"], "B": ["A"], "C": ["A"], "D": ["B", "C"]},
  257. )
  258. self.dummy_store.register_events(graph.walk())
  259. context_store: Dict[str, EventContext] = {}
  260. for event in graph.walk():
  261. context = yield defer.ensureDeferred(
  262. self.state.compute_event_context(event)
  263. )
  264. self.dummy_store.register_event_context(event, context)
  265. context_store[event.event_id] = context
  266. # C ends up winning the resolution between B and C
  267. ctx_c = context_store["C"]
  268. ctx_d = context_store["D"]
  269. prev_state_ids: StateMap[str]
  270. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  271. self.assertSetEqual({"START", "A", "C"}, set(prev_state_ids.values()))
  272. self.assertEqual(ctx_c.state_group, ctx_d.state_group_before_event)
  273. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  274. @defer.inlineCallbacks
  275. def test_branch_have_banned_conflict(
  276. self,
  277. ) -> Generator["defer.Deferred[object]", Any, None]:
  278. graph = Graph(
  279. nodes={
  280. "START": DictObj(
  281. type=EventTypes.Create,
  282. state_key="",
  283. content={"creator": "@user_id:example.com"},
  284. depth=1,
  285. ),
  286. "A": DictObj(
  287. type=EventTypes.Member,
  288. state_key="@user_id:example.com",
  289. content={"membership": Membership.JOIN},
  290. membership=Membership.JOIN,
  291. depth=2,
  292. ),
  293. "B": DictObj(type=EventTypes.Name, state_key="", depth=3),
  294. "C": DictObj(
  295. type=EventTypes.Member,
  296. state_key="@user_id_2:example.com",
  297. content={"membership": Membership.BAN},
  298. membership=Membership.BAN,
  299. depth=4,
  300. ),
  301. "D": DictObj(
  302. type=EventTypes.Name,
  303. state_key="",
  304. depth=4,
  305. sender="@user_id_2:example.com",
  306. ),
  307. "E": DictObj(type=EventTypes.Message, depth=5),
  308. },
  309. edges={"A": ["START"], "B": ["A"], "C": ["B"], "D": ["B"], "E": ["C", "D"]},
  310. )
  311. self.dummy_store.register_events(graph.walk())
  312. context_store: Dict[str, EventContext] = {}
  313. for event in graph.walk():
  314. context = yield defer.ensureDeferred(
  315. self.state.compute_event_context(event)
  316. )
  317. self.dummy_store.register_event_context(event, context)
  318. context_store[event.event_id] = context
  319. # C ends up winning the resolution between C and D because bans win over other
  320. # changes
  321. ctx_c = context_store["C"]
  322. ctx_e = context_store["E"]
  323. prev_state_ids: StateMap[str]
  324. prev_state_ids = yield defer.ensureDeferred(ctx_e.get_prev_state_ids())
  325. self.assertSetEqual({"START", "A", "B", "C"}, set(prev_state_ids.values()))
  326. self.assertEqual(ctx_c.state_group, ctx_e.state_group_before_event)
  327. self.assertEqual(ctx_e.state_group_before_event, ctx_e.state_group)
  328. @defer.inlineCallbacks
  329. def test_branch_have_perms_conflict(
  330. self,
  331. ) -> Generator["defer.Deferred[object]", Any, None]:
  332. userid1 = "@user_id:example.com"
  333. userid2 = "@user_id2:example.com"
  334. nodes = {
  335. "A1": DictObj(
  336. type=EventTypes.Create,
  337. state_key="",
  338. content={"creator": userid1},
  339. depth=1,
  340. ),
  341. "A2": DictObj(
  342. type=EventTypes.Member,
  343. state_key=userid1,
  344. content={"membership": Membership.JOIN},
  345. membership=Membership.JOIN,
  346. ),
  347. "A3": DictObj(
  348. type=EventTypes.Member,
  349. state_key=userid2,
  350. content={"membership": Membership.JOIN},
  351. membership=Membership.JOIN,
  352. ),
  353. "A4": DictObj(
  354. type=EventTypes.PowerLevels,
  355. state_key="",
  356. content={
  357. "events": {"m.room.name": 50},
  358. "users": {userid1: 100, userid2: 60},
  359. },
  360. ),
  361. "A5": DictObj(type=EventTypes.Name, state_key=""),
  362. "B": DictObj(
  363. type=EventTypes.PowerLevels,
  364. state_key="",
  365. content={"events": {"m.room.name": 50}, "users": {userid2: 30}},
  366. ),
  367. "C": DictObj(type=EventTypes.Name, state_key="", sender=userid2),
  368. "D": DictObj(type=EventTypes.Message),
  369. }
  370. edges = {
  371. "A2": ["A1"],
  372. "A3": ["A2"],
  373. "A4": ["A3"],
  374. "A5": ["A4"],
  375. "B": ["A5"],
  376. "C": ["A5"],
  377. "D": ["B", "C"],
  378. }
  379. self._add_depths(nodes, edges)
  380. graph = Graph(nodes, edges)
  381. self.dummy_store.register_events(graph.walk())
  382. context_store: Dict[str, EventContext] = {}
  383. for event in graph.walk():
  384. context = yield defer.ensureDeferred(
  385. self.state.compute_event_context(event)
  386. )
  387. self.dummy_store.register_event_context(event, context)
  388. context_store[event.event_id] = context
  389. # B ends up winning the resolution between B and C because power levels
  390. # win over other changes.
  391. ctx_b = context_store["B"]
  392. ctx_d = context_store["D"]
  393. prev_state_ids: StateMap[str]
  394. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  395. self.assertSetEqual({"A1", "A2", "A3", "A5", "B"}, set(prev_state_ids.values()))
  396. self.assertEqual(ctx_b.state_group, ctx_d.state_group_before_event)
  397. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  398. def _add_depths(
  399. self, nodes: Dict[str, DictObj], edges: Dict[str, List[str]]
  400. ) -> None:
  401. def _get_depth(ev: str) -> int:
  402. node = nodes[ev]
  403. if "depth" not in node:
  404. prevs = edges[ev]
  405. depth = max(_get_depth(prev) for prev in prevs) + 1
  406. node["depth"] = depth
  407. return node["depth"]
  408. for n in nodes:
  409. _get_depth(n)
  410. @defer.inlineCallbacks
  411. def test_annotate_with_old_message(
  412. self,
  413. ) -> Generator["defer.Deferred[object]", Any, None]:
  414. event = create_event(type="test_message", name="event")
  415. old_state = [
  416. create_event(type="test1", state_key="1"),
  417. create_event(type="test1", state_key="2"),
  418. create_event(type="test2", state_key=""),
  419. ]
  420. context: EventContext
  421. context = yield defer.ensureDeferred(
  422. self.state.compute_event_context(
  423. event,
  424. state_ids_before_event={
  425. (e.type, e.state_key): e.event_id for e in old_state
  426. },
  427. partial_state=False,
  428. )
  429. )
  430. prev_state_ids: StateMap[str]
  431. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  432. self.assertCountEqual((e.event_id for e in old_state), prev_state_ids.values())
  433. current_state_ids: StateMap[str]
  434. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  435. self.assertCountEqual(
  436. (e.event_id for e in old_state), current_state_ids.values()
  437. )
  438. self.assertIsNotNone(context.state_group_before_event)
  439. self.assertEqual(context.state_group_before_event, context.state_group)
  440. @defer.inlineCallbacks
  441. def test_annotate_with_old_state(
  442. self,
  443. ) -> Generator["defer.Deferred[object]", Any, None]:
  444. event = create_event(type="state", state_key="", name="event")
  445. old_state = [
  446. create_event(type="test1", state_key="1"),
  447. create_event(type="test1", state_key="2"),
  448. create_event(type="test2", state_key=""),
  449. ]
  450. context: EventContext
  451. context = yield defer.ensureDeferred(
  452. self.state.compute_event_context(
  453. event,
  454. state_ids_before_event={
  455. (e.type, e.state_key): e.event_id for e in old_state
  456. },
  457. partial_state=False,
  458. )
  459. )
  460. prev_state_ids: StateMap[str]
  461. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  462. self.assertCountEqual((e.event_id for e in old_state), prev_state_ids.values())
  463. current_state_ids: StateMap[str]
  464. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  465. self.assertCountEqual(
  466. (e.event_id for e in old_state + [event]), current_state_ids.values()
  467. )
  468. self.assertIsNotNone(context.state_group_before_event)
  469. self.assertNotEqual(context.state_group_before_event, context.state_group)
  470. self.assertEqual(context.state_group_before_event, context.prev_group)
  471. self.assertEqual({("state", ""): event.event_id}, context.delta_ids)
  472. @defer.inlineCallbacks
  473. def test_trivial_annotate_message(
  474. self,
  475. ) -> Generator["defer.Deferred[object]", Any, None]:
  476. prev_event_id = "prev_event_id"
  477. event = create_event(
  478. type="test_message", name="event2", prev_events=[(prev_event_id, {})]
  479. )
  480. old_state = [
  481. create_event(type="test1", state_key="1"),
  482. create_event(type="test1", state_key="2"),
  483. create_event(type="test2", state_key=""),
  484. ]
  485. group_name = yield defer.ensureDeferred(
  486. self.dummy_store.store_state_group(
  487. prev_event_id,
  488. event.room_id,
  489. None,
  490. None,
  491. {(e.type, e.state_key): e.event_id for e in old_state},
  492. )
  493. )
  494. self.dummy_store.register_event_id_state_group(prev_event_id, group_name)
  495. context: EventContext
  496. context = yield defer.ensureDeferred(self.state.compute_event_context(event))
  497. current_state_ids: StateMap[str]
  498. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  499. self.assertEqual(
  500. {e.event_id for e in old_state}, set(current_state_ids.values())
  501. )
  502. self.assertEqual(group_name, context.state_group)
  503. @defer.inlineCallbacks
  504. def test_trivial_annotate_state(
  505. self,
  506. ) -> Generator["defer.Deferred[object]", Any, None]:
  507. prev_event_id = "prev_event_id"
  508. event = create_event(
  509. type="state", state_key="", name="event2", prev_events=[(prev_event_id, {})]
  510. )
  511. old_state = [
  512. create_event(type="test1", state_key="1"),
  513. create_event(type="test1", state_key="2"),
  514. create_event(type="test2", state_key=""),
  515. ]
  516. group_name = yield defer.ensureDeferred(
  517. self.dummy_store.store_state_group(
  518. prev_event_id,
  519. event.room_id,
  520. None,
  521. None,
  522. {(e.type, e.state_key): e.event_id for e in old_state},
  523. )
  524. )
  525. self.dummy_store.register_event_id_state_group(prev_event_id, group_name)
  526. context: EventContext
  527. context = yield defer.ensureDeferred(self.state.compute_event_context(event))
  528. prev_state_ids: StateMap[str]
  529. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  530. self.assertEqual({e.event_id for e in old_state}, set(prev_state_ids.values()))
  531. self.assertIsNotNone(context.state_group)
  532. @defer.inlineCallbacks
  533. def test_resolve_message_conflict(
  534. self,
  535. ) -> Generator["defer.Deferred[Any]", Any, None]:
  536. prev_event_id1 = "event_id1"
  537. prev_event_id2 = "event_id2"
  538. event = create_event(
  539. type="test_message",
  540. name="event3",
  541. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  542. )
  543. creation = create_event(type=EventTypes.Create, state_key="")
  544. old_state_1 = [
  545. creation,
  546. create_event(type="test1", state_key="1"),
  547. create_event(type="test1", state_key="2"),
  548. create_event(type="test2", state_key=""),
  549. ]
  550. old_state_2 = [
  551. creation,
  552. create_event(type="test1", state_key="1"),
  553. create_event(type="test3", state_key="2"),
  554. create_event(type="test4", state_key=""),
  555. ]
  556. self.dummy_store.register_events(old_state_1)
  557. self.dummy_store.register_events(old_state_2)
  558. context: EventContext
  559. context = yield self._get_context(
  560. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  561. )
  562. current_state_ids: StateMap[str]
  563. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  564. self.assertEqual(len(current_state_ids), 6)
  565. self.assertIsNotNone(context.state_group)
  566. @defer.inlineCallbacks
  567. def test_resolve_state_conflict(
  568. self,
  569. ) -> Generator["defer.Deferred[Any]", Any, None]:
  570. prev_event_id1 = "event_id1"
  571. prev_event_id2 = "event_id2"
  572. event = create_event(
  573. type="test4",
  574. state_key="",
  575. name="event",
  576. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  577. )
  578. creation = create_event(type=EventTypes.Create, state_key="")
  579. old_state_1 = [
  580. creation,
  581. create_event(type="test1", state_key="1"),
  582. create_event(type="test1", state_key="2"),
  583. create_event(type="test2", state_key=""),
  584. ]
  585. old_state_2 = [
  586. creation,
  587. create_event(type="test1", state_key="1"),
  588. create_event(type="test3", state_key="2"),
  589. create_event(type="test4", state_key=""),
  590. ]
  591. store = _DummyStore()
  592. store.register_events(old_state_1)
  593. store.register_events(old_state_2)
  594. self.dummy_store.get_events = store.get_events # type: ignore[assignment]
  595. context: EventContext
  596. context = yield self._get_context(
  597. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  598. )
  599. current_state_ids: StateMap[str]
  600. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  601. self.assertEqual(len(current_state_ids), 6)
  602. self.assertIsNotNone(context.state_group)
  603. @defer.inlineCallbacks
  604. def test_standard_depth_conflict(
  605. self,
  606. ) -> Generator["defer.Deferred[Any]", Any, None]:
  607. prev_event_id1 = "event_id1"
  608. prev_event_id2 = "event_id2"
  609. event = create_event(
  610. type="test4",
  611. name="event",
  612. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  613. )
  614. member_event = create_event(
  615. type=EventTypes.Member,
  616. state_key="@user_id:example.com",
  617. content={"membership": Membership.JOIN},
  618. )
  619. power_levels = create_event(
  620. type=EventTypes.PowerLevels,
  621. state_key="",
  622. content={"users": {"@foo:bar": "100", "@user_id:example.com": "100"}},
  623. )
  624. creation = create_event(
  625. type=EventTypes.Create, state_key="", content={"creator": "@foo:bar"}
  626. )
  627. old_state_1 = [
  628. creation,
  629. power_levels,
  630. member_event,
  631. create_event(type="test1", state_key="1", depth=1),
  632. ]
  633. old_state_2 = [
  634. creation,
  635. power_levels,
  636. member_event,
  637. create_event(type="test1", state_key="1", depth=2),
  638. ]
  639. store = _DummyStore()
  640. store.register_events(old_state_1)
  641. store.register_events(old_state_2)
  642. self.dummy_store.get_events = store.get_events # type: ignore[assignment]
  643. context: EventContext
  644. context = yield self._get_context(
  645. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  646. )
  647. current_state_ids: StateMap[str]
  648. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  649. self.assertEqual(old_state_2[3].event_id, current_state_ids[("test1", "1")])
  650. # Reverse the depth to make sure we are actually using the depths
  651. # during state resolution.
  652. old_state_1 = [
  653. creation,
  654. power_levels,
  655. member_event,
  656. create_event(type="test1", state_key="1", depth=2),
  657. ]
  658. old_state_2 = [
  659. creation,
  660. power_levels,
  661. member_event,
  662. create_event(type="test1", state_key="1", depth=1),
  663. ]
  664. store.register_events(old_state_1)
  665. store.register_events(old_state_2)
  666. context = yield self._get_context(
  667. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  668. )
  669. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  670. self.assertEqual(old_state_1[3].event_id, current_state_ids[("test1", "1")])
  671. @defer.inlineCallbacks
  672. def _get_context(
  673. self,
  674. event: EventBase,
  675. prev_event_id_1: str,
  676. old_state_1: Collection[EventBase],
  677. prev_event_id_2: str,
  678. old_state_2: Collection[EventBase],
  679. ) -> Generator["defer.Deferred[object]", Any, EventContext]:
  680. sg1: int
  681. sg1 = yield defer.ensureDeferred(
  682. self.dummy_store.store_state_group(
  683. prev_event_id_1,
  684. event.room_id,
  685. None,
  686. None,
  687. {(e.type, e.state_key): e.event_id for e in old_state_1},
  688. )
  689. )
  690. self.dummy_store.register_event_id_state_group(prev_event_id_1, sg1)
  691. sg2: int
  692. sg2 = yield defer.ensureDeferred(
  693. self.dummy_store.store_state_group(
  694. prev_event_id_2,
  695. event.room_id,
  696. None,
  697. None,
  698. {(e.type, e.state_key): e.event_id for e in old_state_2},
  699. )
  700. )
  701. self.dummy_store.register_event_id_state_group(prev_event_id_2, sg2)
  702. result = yield defer.ensureDeferred(self.state.compute_event_context(event))
  703. return result
  704. def test_make_state_cache_entry(self) -> None:
  705. "Test that calculating a prev_group and delta is correct"
  706. new_state = {
  707. ("a", ""): "E",
  708. ("b", ""): "E",
  709. ("c", ""): "E",
  710. ("d", ""): "E",
  711. }
  712. # old_state_1 has fewer differences to new_state than old_state_2, but
  713. # the delta involves deleting a key, which isn't allowed in the deltas,
  714. # so we should pick old_state_2 as the prev_group.
  715. # `old_state_1` has two differences: `a` and `e`
  716. old_state_1 = {
  717. ("a", ""): "F",
  718. ("b", ""): "E",
  719. ("c", ""): "E",
  720. ("d", ""): "E",
  721. ("e", ""): "E",
  722. }
  723. # `old_state_2` has three differences: `a`, `c` and `d`
  724. old_state_2 = {
  725. ("a", ""): "F",
  726. ("b", ""): "E",
  727. ("c", ""): "F",
  728. ("d", ""): "F",
  729. }
  730. entry = _make_state_cache_entry(new_state, {1: old_state_1, 2: old_state_2})
  731. self.assertEqual(entry.prev_group, 2)
  732. # There are three changes from `old_state_2` to `new_state`
  733. self.assertEqual(
  734. entry.delta_ids, {("a", ""): "E", ("c", ""): "E", ("d", ""): "E"}
  735. )