test_room.py 12 KB

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