test_room.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014 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 twisted.internet import defer
  16. from .. import unittest
  17. from synapse.api.constants import EventTypes, Membership
  18. from synapse.handlers.room import RoomMemberHandler, RoomCreationHandler
  19. from synapse.handlers.profile import ProfileHandler
  20. from synapse.types import UserID
  21. from ..utils import setup_test_homeserver
  22. from mock import Mock, NonCallableMock
  23. class RoomMemberHandlerTestCase(unittest.TestCase):
  24. @defer.inlineCallbacks
  25. def setUp(self):
  26. self.hostname = "red"
  27. hs = yield setup_test_homeserver(
  28. self.hostname,
  29. ratelimiter=NonCallableMock(spec_set=[
  30. "send_message",
  31. ]),
  32. datastore=NonCallableMock(spec_set=[
  33. "persist_event",
  34. "get_room_member",
  35. "get_room",
  36. "store_room",
  37. "get_latest_events_in_room",
  38. ]),
  39. resource_for_federation=NonCallableMock(),
  40. http_client=NonCallableMock(spec_set=[]),
  41. notifier=NonCallableMock(spec_set=["on_new_room_event"]),
  42. handlers=NonCallableMock(spec_set=[
  43. "room_member_handler",
  44. "profile_handler",
  45. "federation_handler",
  46. ]),
  47. auth=NonCallableMock(spec_set=[
  48. "check",
  49. "add_auth_events",
  50. "check_host_in_room",
  51. ]),
  52. state_handler=NonCallableMock(spec_set=[
  53. "compute_event_context",
  54. "get_current_state",
  55. ]),
  56. )
  57. self.federation = NonCallableMock(spec_set=[
  58. "handle_new_event",
  59. "send_invite",
  60. "get_state_for_room",
  61. ])
  62. self.datastore = hs.get_datastore()
  63. self.handlers = hs.get_handlers()
  64. self.notifier = hs.get_notifier()
  65. self.state_handler = hs.get_state_handler()
  66. self.distributor = hs.get_distributor()
  67. self.auth = hs.get_auth()
  68. self.hs = hs
  69. self.handlers.federation_handler = self.federation
  70. self.distributor.declare("collect_presencelike_data")
  71. self.handlers.room_member_handler = RoomMemberHandler(self.hs)
  72. self.handlers.profile_handler = ProfileHandler(self.hs)
  73. self.room_member_handler = self.handlers.room_member_handler
  74. self.ratelimiter = hs.get_ratelimiter()
  75. self.ratelimiter.send_message.return_value = (True, 0)
  76. @defer.inlineCallbacks
  77. def test_invite(self):
  78. room_id = "!foo:red"
  79. user_id = "@bob:red"
  80. target_user_id = "@red:blue"
  81. content = {"membership": Membership.INVITE}
  82. builder = self.hs.get_event_builder_factory().new({
  83. "type": EventTypes.Member,
  84. "sender": user_id,
  85. "state_key": target_user_id,
  86. "room_id": room_id,
  87. "content": content,
  88. })
  89. self.datastore.get_latest_events_in_room.return_value = (
  90. defer.succeed([])
  91. )
  92. def annotate(_):
  93. ctx = Mock()
  94. ctx.current_state = {
  95. (EventTypes.Member, "@alice:green"): self._create_member(
  96. user_id="@alice:green",
  97. room_id=room_id,
  98. ),
  99. (EventTypes.Member, "@bob:red"): self._create_member(
  100. user_id="@bob:red",
  101. room_id=room_id,
  102. ),
  103. }
  104. ctx.prev_state_events = []
  105. return defer.succeed(ctx)
  106. self.state_handler.compute_event_context.side_effect = annotate
  107. def add_auth(_, ctx):
  108. ctx.auth_events = ctx.current_state[
  109. (EventTypes.Member, "@bob:red")
  110. ]
  111. return defer.succeed(True)
  112. self.auth.add_auth_events.side_effect = add_auth
  113. def send_invite(domain, event):
  114. return defer.succeed(event)
  115. self.federation.send_invite.side_effect = send_invite
  116. room_handler = self.room_member_handler
  117. event, context = yield room_handler._create_new_client_event(
  118. builder
  119. )
  120. yield room_handler.change_membership(event, context)
  121. self.state_handler.compute_event_context.assert_called_once_with(
  122. builder
  123. )
  124. self.auth.add_auth_events.assert_called_once_with(
  125. builder, context
  126. )
  127. self.federation.send_invite.assert_called_once_with(
  128. "blue", event,
  129. )
  130. self.datastore.persist_event.assert_called_once_with(
  131. event, context=context,
  132. )
  133. self.notifier.on_new_room_event.assert_called_once_with(
  134. event, extra_users=[UserID.from_string(target_user_id)]
  135. )
  136. self.assertFalse(self.datastore.get_room.called)
  137. self.assertFalse(self.datastore.store_room.called)
  138. self.assertFalse(self.federation.get_state_for_room.called)
  139. @defer.inlineCallbacks
  140. def test_simple_join(self):
  141. room_id = "!foo:red"
  142. user_id = "@bob:red"
  143. user = UserID.from_string(user_id)
  144. join_signal_observer = Mock()
  145. self.distributor.observe("user_joined_room", join_signal_observer)
  146. builder = self.hs.get_event_builder_factory().new({
  147. "type": EventTypes.Member,
  148. "sender": user_id,
  149. "state_key": user_id,
  150. "room_id": room_id,
  151. "content": {"membership": Membership.JOIN},
  152. })
  153. self.datastore.get_latest_events_in_room.return_value = (
  154. defer.succeed([])
  155. )
  156. def annotate(_):
  157. ctx = Mock()
  158. ctx.current_state = {
  159. (EventTypes.Member, "@bob:red"): self._create_member(
  160. user_id="@bob:red",
  161. room_id=room_id,
  162. membership=Membership.INVITE
  163. ),
  164. }
  165. ctx.prev_state_events = []
  166. return defer.succeed(ctx)
  167. self.state_handler.compute_event_context.side_effect = annotate
  168. def add_auth(_, ctx):
  169. ctx.auth_events = ctx.current_state[
  170. (EventTypes.Member, "@bob:red")
  171. ]
  172. return defer.succeed(True)
  173. self.auth.add_auth_events.side_effect = add_auth
  174. room_handler = self.room_member_handler
  175. event, context = yield room_handler._create_new_client_event(
  176. builder
  177. )
  178. # Actual invocation
  179. yield room_handler.change_membership(event, context)
  180. self.federation.handle_new_event.assert_called_once_with(
  181. event, destinations=set()
  182. )
  183. self.datastore.persist_event.assert_called_once_with(
  184. event, context=context
  185. )
  186. self.notifier.on_new_room_event.assert_called_once_with(
  187. event, extra_users=[user]
  188. )
  189. join_signal_observer.assert_called_with(
  190. user=user, room_id=room_id
  191. )
  192. def _create_member(self, user_id, room_id, membership=Membership.JOIN):
  193. builder = self.hs.get_event_builder_factory().new({
  194. "type": EventTypes.Member,
  195. "sender": user_id,
  196. "state_key": user_id,
  197. "room_id": room_id,
  198. "content": {"membership": membership},
  199. })
  200. return builder.build()
  201. @defer.inlineCallbacks
  202. def test_simple_leave(self):
  203. room_id = "!foo:red"
  204. user_id = "@bob:red"
  205. user = UserID.from_string(user_id)
  206. builder = self.hs.get_event_builder_factory().new({
  207. "type": EventTypes.Member,
  208. "sender": user_id,
  209. "state_key": user_id,
  210. "room_id": room_id,
  211. "content": {"membership": Membership.LEAVE},
  212. })
  213. self.datastore.get_latest_events_in_room.return_value = (
  214. defer.succeed([])
  215. )
  216. def annotate(_):
  217. ctx = Mock()
  218. ctx.current_state = {
  219. (EventTypes.Member, "@bob:red"): self._create_member(
  220. user_id="@bob:red",
  221. room_id=room_id,
  222. membership=Membership.JOIN
  223. ),
  224. }
  225. ctx.prev_state_events = []
  226. return defer.succeed(ctx)
  227. self.state_handler.compute_event_context.side_effect = annotate
  228. def add_auth(_, ctx):
  229. ctx.auth_events = ctx.current_state[
  230. (EventTypes.Member, "@bob:red")
  231. ]
  232. return defer.succeed(True)
  233. self.auth.add_auth_events.side_effect = add_auth
  234. room_handler = self.room_member_handler
  235. event, context = yield room_handler._create_new_client_event(
  236. builder
  237. )
  238. leave_signal_observer = Mock()
  239. self.distributor.observe("user_left_room", leave_signal_observer)
  240. # Actual invocation
  241. yield room_handler.change_membership(event, context)
  242. self.federation.handle_new_event.assert_called_once_with(
  243. event, destinations=set(['red'])
  244. )
  245. self.datastore.persist_event.assert_called_once_with(
  246. event, context=context
  247. )
  248. self.notifier.on_new_room_event.assert_called_once_with(
  249. event, extra_users=[user]
  250. )
  251. leave_signal_observer.assert_called_with(
  252. user=user, room_id=room_id
  253. )
  254. class RoomCreationTest(unittest.TestCase):
  255. @defer.inlineCallbacks
  256. def setUp(self):
  257. self.hostname = "red"
  258. hs = yield setup_test_homeserver(
  259. self.hostname,
  260. datastore=NonCallableMock(spec_set=[
  261. "store_room",
  262. "snapshot_room",
  263. "persist_event",
  264. "get_joined_hosts_for_room",
  265. ]),
  266. http_client=NonCallableMock(spec_set=[]),
  267. notifier=NonCallableMock(spec_set=["on_new_room_event"]),
  268. handlers=NonCallableMock(spec_set=[
  269. "room_creation_handler",
  270. "message_handler",
  271. ]),
  272. auth=NonCallableMock(spec_set=["check", "add_auth_events"]),
  273. ratelimiter=NonCallableMock(spec_set=[
  274. "send_message",
  275. ]),
  276. )
  277. self.federation = NonCallableMock(spec_set=[
  278. "handle_new_event",
  279. ])
  280. self.handlers = hs.get_handlers()
  281. self.handlers.room_creation_handler = RoomCreationHandler(hs)
  282. self.room_creation_handler = self.handlers.room_creation_handler
  283. self.message_handler = self.handlers.message_handler
  284. self.ratelimiter = hs.get_ratelimiter()
  285. self.ratelimiter.send_message.return_value = (True, 0)
  286. @defer.inlineCallbacks
  287. def test_room_creation(self):
  288. user_id = "@foo:red"
  289. room_id = "!bobs_room:red"
  290. config = {"visibility": "private"}
  291. yield self.room_creation_handler.create_room(
  292. user_id=user_id,
  293. room_id=room_id,
  294. config=config,
  295. )
  296. self.assertTrue(self.message_handler.create_and_send_event.called)
  297. event_dicts = [
  298. e[0][0]
  299. for e in self.message_handler.create_and_send_event.call_args_list
  300. ]
  301. self.assertTrue(len(event_dicts) > 3)
  302. self.assertDictContainsSubset(
  303. {
  304. "type": EventTypes.Create,
  305. "sender": user_id,
  306. "room_id": room_id,
  307. },
  308. event_dicts[0]
  309. )
  310. self.assertEqual(user_id, event_dicts[0]["content"]["creator"])
  311. self.assertDictContainsSubset(
  312. {
  313. "type": EventTypes.Member,
  314. "sender": user_id,
  315. "room_id": room_id,
  316. "state_key": user_id,
  317. },
  318. event_dicts[1]
  319. )
  320. self.assertEqual(
  321. Membership.JOIN,
  322. event_dicts[1]["content"]["membership"]
  323. )