test_state.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from mock import Mock
  16. from twisted.internet import defer
  17. from synapse.api.auth import Auth
  18. from synapse.api.constants import EventTypes, Membership
  19. from synapse.api.room_versions import RoomVersions
  20. from synapse.events import make_event_from_dict
  21. from synapse.events.snapshot import EventContext
  22. from synapse.state import StateHandler, StateResolutionHandler
  23. from tests import unittest
  24. from .utils import MockClock, default_config
  25. _next_event_id = 1000
  26. def create_event(
  27. name=None,
  28. type=None,
  29. state_key=None,
  30. depth=2,
  31. event_id=None,
  32. prev_events=[],
  33. **kwargs
  34. ):
  35. global _next_event_id
  36. if not event_id:
  37. _next_event_id += 1
  38. event_id = "$%s:test" % (_next_event_id,)
  39. if not name:
  40. if state_key is not None:
  41. name = "<%s-%s, %s>" % (type, state_key, event_id)
  42. else:
  43. name = "<%s, %s>" % (type, event_id)
  44. d = {
  45. "event_id": event_id,
  46. "type": type,
  47. "sender": "@user_id:example.com",
  48. "room_id": "!room_id:example.com",
  49. "depth": depth,
  50. "prev_events": prev_events,
  51. }
  52. if state_key is not None:
  53. d["state_key"] = state_key
  54. d.update(kwargs)
  55. event = make_event_from_dict(d)
  56. return event
  57. class StateGroupStore(object):
  58. def __init__(self):
  59. self._event_to_state_group = {}
  60. self._group_to_state = {}
  61. self._event_id_to_event = {}
  62. self._next_group = 1
  63. def get_state_groups_ids(self, room_id, event_ids):
  64. groups = {}
  65. for event_id in event_ids:
  66. group = self._event_to_state_group.get(event_id)
  67. if group:
  68. groups[group] = self._group_to_state[group]
  69. return defer.succeed(groups)
  70. def store_state_group(
  71. self, event_id, room_id, prev_group, delta_ids, current_state_ids
  72. ):
  73. state_group = self._next_group
  74. self._next_group += 1
  75. self._group_to_state[state_group] = dict(current_state_ids)
  76. return defer.succeed(state_group)
  77. def get_events(self, event_ids, **kwargs):
  78. return defer.succeed(
  79. {
  80. e_id: self._event_id_to_event[e_id]
  81. for e_id in event_ids
  82. if e_id in self._event_id_to_event
  83. }
  84. )
  85. def get_state_group_delta(self, name):
  86. return defer.succeed((None, None))
  87. def register_events(self, events):
  88. for e in events:
  89. self._event_id_to_event[e.event_id] = e
  90. def register_event_context(self, event, context):
  91. self._event_to_state_group[event.event_id] = context.state_group
  92. def register_event_id_state_group(self, event_id, state_group):
  93. self._event_to_state_group[event_id] = state_group
  94. def get_room_version_id(self, room_id):
  95. return defer.succeed(RoomVersions.V1.identifier)
  96. class DictObj(dict):
  97. def __init__(self, **kwargs):
  98. super(DictObj, self).__init__(kwargs)
  99. self.__dict__ = self
  100. class Graph(object):
  101. def __init__(self, nodes, edges):
  102. events = {}
  103. clobbered = set(events.keys())
  104. for event_id, fields in nodes.items():
  105. refs = edges.get(event_id)
  106. if refs:
  107. clobbered.difference_update(refs)
  108. prev_events = [(r, {}) for r in refs]
  109. else:
  110. prev_events = []
  111. events[event_id] = create_event(
  112. event_id=event_id, prev_events=prev_events, **fields
  113. )
  114. self._leaves = clobbered
  115. self._events = sorted(events.values(), key=lambda e: e.depth)
  116. def walk(self):
  117. return iter(self._events)
  118. def get_leaves(self):
  119. return (self._events[i] for i in self._leaves)
  120. class StateTestCase(unittest.TestCase):
  121. def setUp(self):
  122. self.store = StateGroupStore()
  123. storage = Mock(main=self.store, state=self.store)
  124. hs = Mock(
  125. spec_set=[
  126. "config",
  127. "get_datastore",
  128. "get_storage",
  129. "get_auth",
  130. "get_state_handler",
  131. "get_clock",
  132. "get_state_resolution_handler",
  133. ]
  134. )
  135. hs.config = default_config("tesths", True)
  136. hs.get_datastore.return_value = self.store
  137. hs.get_state_handler.return_value = None
  138. hs.get_clock.return_value = MockClock()
  139. hs.get_auth.return_value = Auth(hs)
  140. hs.get_state_resolution_handler = lambda: StateResolutionHandler(hs)
  141. hs.get_storage.return_value = storage
  142. self.state = StateHandler(hs)
  143. self.event_id = 0
  144. @defer.inlineCallbacks
  145. def test_branch_no_conflict(self):
  146. graph = Graph(
  147. nodes={
  148. "START": DictObj(
  149. type=EventTypes.Create, state_key="", content={}, depth=1
  150. ),
  151. "A": DictObj(type=EventTypes.Message, depth=2),
  152. "B": DictObj(type=EventTypes.Message, depth=3),
  153. "C": DictObj(type=EventTypes.Name, state_key="", depth=3),
  154. "D": DictObj(type=EventTypes.Message, depth=4),
  155. },
  156. edges={"A": ["START"], "B": ["A"], "C": ["A"], "D": ["B", "C"]},
  157. )
  158. self.store.register_events(graph.walk())
  159. context_store = {} # type: dict[str, EventContext]
  160. for event in graph.walk():
  161. context = yield defer.ensureDeferred(
  162. self.state.compute_event_context(event)
  163. )
  164. self.store.register_event_context(event, context)
  165. context_store[event.event_id] = context
  166. ctx_c = context_store["C"]
  167. ctx_d = context_store["D"]
  168. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  169. self.assertEqual(2, len(prev_state_ids))
  170. self.assertEqual(ctx_c.state_group, ctx_d.state_group_before_event)
  171. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  172. @defer.inlineCallbacks
  173. def test_branch_basic_conflict(self):
  174. graph = Graph(
  175. nodes={
  176. "START": DictObj(
  177. type=EventTypes.Create,
  178. state_key="",
  179. content={"creator": "@user_id:example.com"},
  180. depth=1,
  181. ),
  182. "A": DictObj(
  183. type=EventTypes.Member,
  184. state_key="@user_id:example.com",
  185. content={"membership": Membership.JOIN},
  186. membership=Membership.JOIN,
  187. depth=2,
  188. ),
  189. "B": DictObj(type=EventTypes.Name, state_key="", depth=3),
  190. "C": DictObj(type=EventTypes.Name, state_key="", depth=4),
  191. "D": DictObj(type=EventTypes.Message, depth=5),
  192. },
  193. edges={"A": ["START"], "B": ["A"], "C": ["A"], "D": ["B", "C"]},
  194. )
  195. self.store.register_events(graph.walk())
  196. context_store = {}
  197. for event in graph.walk():
  198. context = yield defer.ensureDeferred(
  199. self.state.compute_event_context(event)
  200. )
  201. self.store.register_event_context(event, context)
  202. context_store[event.event_id] = context
  203. # C ends up winning the resolution between B and C
  204. ctx_c = context_store["C"]
  205. ctx_d = context_store["D"]
  206. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  207. self.assertSetEqual({"START", "A", "C"}, set(prev_state_ids.values()))
  208. self.assertEqual(ctx_c.state_group, ctx_d.state_group_before_event)
  209. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  210. @defer.inlineCallbacks
  211. def test_branch_have_banned_conflict(self):
  212. graph = Graph(
  213. nodes={
  214. "START": DictObj(
  215. type=EventTypes.Create,
  216. state_key="",
  217. content={"creator": "@user_id:example.com"},
  218. depth=1,
  219. ),
  220. "A": DictObj(
  221. type=EventTypes.Member,
  222. state_key="@user_id:example.com",
  223. content={"membership": Membership.JOIN},
  224. membership=Membership.JOIN,
  225. depth=2,
  226. ),
  227. "B": DictObj(type=EventTypes.Name, state_key="", depth=3),
  228. "C": DictObj(
  229. type=EventTypes.Member,
  230. state_key="@user_id_2:example.com",
  231. content={"membership": Membership.BAN},
  232. membership=Membership.BAN,
  233. depth=4,
  234. ),
  235. "D": DictObj(
  236. type=EventTypes.Name,
  237. state_key="",
  238. depth=4,
  239. sender="@user_id_2:example.com",
  240. ),
  241. "E": DictObj(type=EventTypes.Message, depth=5),
  242. },
  243. edges={"A": ["START"], "B": ["A"], "C": ["B"], "D": ["B"], "E": ["C", "D"]},
  244. )
  245. self.store.register_events(graph.walk())
  246. context_store = {}
  247. for event in graph.walk():
  248. context = yield defer.ensureDeferred(
  249. self.state.compute_event_context(event)
  250. )
  251. self.store.register_event_context(event, context)
  252. context_store[event.event_id] = context
  253. # C ends up winning the resolution between C and D because bans win over other
  254. # changes
  255. ctx_c = context_store["C"]
  256. ctx_e = context_store["E"]
  257. prev_state_ids = yield defer.ensureDeferred(ctx_e.get_prev_state_ids())
  258. self.assertSetEqual({"START", "A", "B", "C"}, set(prev_state_ids.values()))
  259. self.assertEqual(ctx_c.state_group, ctx_e.state_group_before_event)
  260. self.assertEqual(ctx_e.state_group_before_event, ctx_e.state_group)
  261. @defer.inlineCallbacks
  262. def test_branch_have_perms_conflict(self):
  263. userid1 = "@user_id:example.com"
  264. userid2 = "@user_id2:example.com"
  265. nodes = {
  266. "A1": DictObj(
  267. type=EventTypes.Create,
  268. state_key="",
  269. content={"creator": userid1},
  270. depth=1,
  271. ),
  272. "A2": DictObj(
  273. type=EventTypes.Member,
  274. state_key=userid1,
  275. content={"membership": Membership.JOIN},
  276. membership=Membership.JOIN,
  277. ),
  278. "A3": DictObj(
  279. type=EventTypes.Member,
  280. state_key=userid2,
  281. content={"membership": Membership.JOIN},
  282. membership=Membership.JOIN,
  283. ),
  284. "A4": DictObj(
  285. type=EventTypes.PowerLevels,
  286. state_key="",
  287. content={
  288. "events": {"m.room.name": 50},
  289. "users": {userid1: 100, userid2: 60},
  290. },
  291. ),
  292. "A5": DictObj(type=EventTypes.Name, state_key=""),
  293. "B": DictObj(
  294. type=EventTypes.PowerLevels,
  295. state_key="",
  296. content={"events": {"m.room.name": 50}, "users": {userid2: 30}},
  297. ),
  298. "C": DictObj(type=EventTypes.Name, state_key="", sender=userid2),
  299. "D": DictObj(type=EventTypes.Message),
  300. }
  301. edges = {
  302. "A2": ["A1"],
  303. "A3": ["A2"],
  304. "A4": ["A3"],
  305. "A5": ["A4"],
  306. "B": ["A5"],
  307. "C": ["A5"],
  308. "D": ["B", "C"],
  309. }
  310. self._add_depths(nodes, edges)
  311. graph = Graph(nodes, edges)
  312. self.store.register_events(graph.walk())
  313. context_store = {}
  314. for event in graph.walk():
  315. context = yield defer.ensureDeferred(
  316. self.state.compute_event_context(event)
  317. )
  318. self.store.register_event_context(event, context)
  319. context_store[event.event_id] = context
  320. # B ends up winning the resolution between B and C because power levels
  321. # win over other changes.
  322. ctx_b = context_store["B"]
  323. ctx_d = context_store["D"]
  324. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  325. self.assertSetEqual({"A1", "A2", "A3", "A5", "B"}, set(prev_state_ids.values()))
  326. self.assertEqual(ctx_b.state_group, ctx_d.state_group_before_event)
  327. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  328. def _add_depths(self, nodes, edges):
  329. def _get_depth(ev):
  330. node = nodes[ev]
  331. if "depth" not in node:
  332. prevs = edges[ev]
  333. depth = max(_get_depth(prev) for prev in prevs) + 1
  334. node["depth"] = depth
  335. return node["depth"]
  336. for n in nodes:
  337. _get_depth(n)
  338. @defer.inlineCallbacks
  339. def test_annotate_with_old_message(self):
  340. event = create_event(type="test_message", name="event")
  341. old_state = [
  342. create_event(type="test1", state_key="1"),
  343. create_event(type="test1", state_key="2"),
  344. create_event(type="test2", state_key=""),
  345. ]
  346. context = yield defer.ensureDeferred(
  347. self.state.compute_event_context(event, old_state=old_state)
  348. )
  349. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  350. self.assertCountEqual((e.event_id for e in old_state), prev_state_ids.values())
  351. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  352. self.assertCountEqual(
  353. (e.event_id for e in old_state), current_state_ids.values()
  354. )
  355. self.assertIsNotNone(context.state_group_before_event)
  356. self.assertEqual(context.state_group_before_event, context.state_group)
  357. @defer.inlineCallbacks
  358. def test_annotate_with_old_state(self):
  359. event = create_event(type="state", state_key="", name="event")
  360. old_state = [
  361. create_event(type="test1", state_key="1"),
  362. create_event(type="test1", state_key="2"),
  363. create_event(type="test2", state_key=""),
  364. ]
  365. context = yield defer.ensureDeferred(
  366. self.state.compute_event_context(event, old_state=old_state)
  367. )
  368. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  369. self.assertCountEqual((e.event_id for e in old_state), prev_state_ids.values())
  370. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  371. self.assertCountEqual(
  372. (e.event_id for e in old_state + [event]), current_state_ids.values()
  373. )
  374. self.assertIsNotNone(context.state_group_before_event)
  375. self.assertNotEqual(context.state_group_before_event, context.state_group)
  376. self.assertEqual(context.state_group_before_event, context.prev_group)
  377. self.assertEqual({("state", ""): event.event_id}, context.delta_ids)
  378. @defer.inlineCallbacks
  379. def test_trivial_annotate_message(self):
  380. prev_event_id = "prev_event_id"
  381. event = create_event(
  382. type="test_message", name="event2", prev_events=[(prev_event_id, {})]
  383. )
  384. old_state = [
  385. create_event(type="test1", state_key="1"),
  386. create_event(type="test1", state_key="2"),
  387. create_event(type="test2", state_key=""),
  388. ]
  389. group_name = yield self.store.store_state_group(
  390. prev_event_id,
  391. event.room_id,
  392. None,
  393. None,
  394. {(e.type, e.state_key): e.event_id for e in old_state},
  395. )
  396. self.store.register_event_id_state_group(prev_event_id, group_name)
  397. context = yield defer.ensureDeferred(self.state.compute_event_context(event))
  398. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  399. self.assertEqual(
  400. {e.event_id for e in old_state}, set(current_state_ids.values())
  401. )
  402. self.assertEqual(group_name, context.state_group)
  403. @defer.inlineCallbacks
  404. def test_trivial_annotate_state(self):
  405. prev_event_id = "prev_event_id"
  406. event = create_event(
  407. type="state", state_key="", name="event2", prev_events=[(prev_event_id, {})]
  408. )
  409. old_state = [
  410. create_event(type="test1", state_key="1"),
  411. create_event(type="test1", state_key="2"),
  412. create_event(type="test2", state_key=""),
  413. ]
  414. group_name = yield self.store.store_state_group(
  415. prev_event_id,
  416. event.room_id,
  417. None,
  418. None,
  419. {(e.type, e.state_key): e.event_id for e in old_state},
  420. )
  421. self.store.register_event_id_state_group(prev_event_id, group_name)
  422. context = yield defer.ensureDeferred(self.state.compute_event_context(event))
  423. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  424. self.assertEqual({e.event_id for e in old_state}, set(prev_state_ids.values()))
  425. self.assertIsNotNone(context.state_group)
  426. @defer.inlineCallbacks
  427. def test_resolve_message_conflict(self):
  428. prev_event_id1 = "event_id1"
  429. prev_event_id2 = "event_id2"
  430. event = create_event(
  431. type="test_message",
  432. name="event3",
  433. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  434. )
  435. creation = create_event(type=EventTypes.Create, state_key="")
  436. old_state_1 = [
  437. creation,
  438. create_event(type="test1", state_key="1"),
  439. create_event(type="test1", state_key="2"),
  440. create_event(type="test2", state_key=""),
  441. ]
  442. old_state_2 = [
  443. creation,
  444. create_event(type="test1", state_key="1"),
  445. create_event(type="test3", state_key="2"),
  446. create_event(type="test4", state_key=""),
  447. ]
  448. self.store.register_events(old_state_1)
  449. self.store.register_events(old_state_2)
  450. context = yield self._get_context(
  451. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  452. )
  453. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  454. self.assertEqual(len(current_state_ids), 6)
  455. self.assertIsNotNone(context.state_group)
  456. @defer.inlineCallbacks
  457. def test_resolve_state_conflict(self):
  458. prev_event_id1 = "event_id1"
  459. prev_event_id2 = "event_id2"
  460. event = create_event(
  461. type="test4",
  462. state_key="",
  463. name="event",
  464. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  465. )
  466. creation = create_event(type=EventTypes.Create, state_key="")
  467. old_state_1 = [
  468. creation,
  469. create_event(type="test1", state_key="1"),
  470. create_event(type="test1", state_key="2"),
  471. create_event(type="test2", state_key=""),
  472. ]
  473. old_state_2 = [
  474. creation,
  475. create_event(type="test1", state_key="1"),
  476. create_event(type="test3", state_key="2"),
  477. create_event(type="test4", state_key=""),
  478. ]
  479. store = StateGroupStore()
  480. store.register_events(old_state_1)
  481. store.register_events(old_state_2)
  482. self.store.get_events = store.get_events
  483. context = yield self._get_context(
  484. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  485. )
  486. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  487. self.assertEqual(len(current_state_ids), 6)
  488. self.assertIsNotNone(context.state_group)
  489. @defer.inlineCallbacks
  490. def test_standard_depth_conflict(self):
  491. prev_event_id1 = "event_id1"
  492. prev_event_id2 = "event_id2"
  493. event = create_event(
  494. type="test4",
  495. name="event",
  496. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  497. )
  498. member_event = create_event(
  499. type=EventTypes.Member,
  500. state_key="@user_id:example.com",
  501. content={"membership": Membership.JOIN},
  502. )
  503. power_levels = create_event(
  504. type=EventTypes.PowerLevels,
  505. state_key="",
  506. content={"users": {"@foo:bar": "100", "@user_id:example.com": "100"}},
  507. )
  508. creation = create_event(
  509. type=EventTypes.Create, state_key="", content={"creator": "@foo:bar"}
  510. )
  511. old_state_1 = [
  512. creation,
  513. power_levels,
  514. member_event,
  515. create_event(type="test1", state_key="1", depth=1),
  516. ]
  517. old_state_2 = [
  518. creation,
  519. power_levels,
  520. member_event,
  521. create_event(type="test1", state_key="1", depth=2),
  522. ]
  523. store = StateGroupStore()
  524. store.register_events(old_state_1)
  525. store.register_events(old_state_2)
  526. self.store.get_events = store.get_events
  527. context = yield self._get_context(
  528. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  529. )
  530. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  531. self.assertEqual(old_state_2[3].event_id, current_state_ids[("test1", "1")])
  532. # Reverse the depth to make sure we are actually using the depths
  533. # during state resolution.
  534. old_state_1 = [
  535. creation,
  536. power_levels,
  537. member_event,
  538. create_event(type="test1", state_key="1", depth=2),
  539. ]
  540. old_state_2 = [
  541. creation,
  542. power_levels,
  543. member_event,
  544. create_event(type="test1", state_key="1", depth=1),
  545. ]
  546. store.register_events(old_state_1)
  547. store.register_events(old_state_2)
  548. context = yield self._get_context(
  549. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  550. )
  551. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  552. self.assertEqual(old_state_1[3].event_id, current_state_ids[("test1", "1")])
  553. @defer.inlineCallbacks
  554. def _get_context(
  555. self, event, prev_event_id_1, old_state_1, prev_event_id_2, old_state_2
  556. ):
  557. sg1 = yield self.store.store_state_group(
  558. prev_event_id_1,
  559. event.room_id,
  560. None,
  561. None,
  562. {(e.type, e.state_key): e.event_id for e in old_state_1},
  563. )
  564. self.store.register_event_id_state_group(prev_event_id_1, sg1)
  565. sg2 = yield self.store.store_state_group(
  566. prev_event_id_2,
  567. event.room_id,
  568. None,
  569. None,
  570. {(e.type, e.state_key): e.event_id for e in old_state_2},
  571. )
  572. self.store.register_event_id_state_group(prev_event_id_2, sg2)
  573. result = yield defer.ensureDeferred(self.state.compute_event_context(event))
  574. return result