test_appservice.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. # Copyright 2015, 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 unittest.mock import Mock
  15. from twisted.internet import defer
  16. from synapse.handlers.appservice import ApplicationServicesHandler
  17. from synapse.types import RoomStreamToken
  18. from tests.test_utils import make_awaitable
  19. from tests.utils import MockClock
  20. from .. import unittest
  21. class AppServiceHandlerTestCase(unittest.TestCase):
  22. """Tests the ApplicationServicesHandler."""
  23. def setUp(self):
  24. self.mock_store = Mock()
  25. self.mock_as_api = Mock()
  26. self.mock_scheduler = Mock()
  27. hs = Mock()
  28. hs.get_datastore.return_value = self.mock_store
  29. self.mock_store.get_received_ts.return_value = make_awaitable(0)
  30. self.mock_store.set_appservice_last_pos.return_value = make_awaitable(None)
  31. hs.get_application_service_api.return_value = self.mock_as_api
  32. hs.get_application_service_scheduler.return_value = self.mock_scheduler
  33. hs.get_clock.return_value = MockClock()
  34. self.handler = ApplicationServicesHandler(hs)
  35. self.event_source = hs.get_event_sources()
  36. def test_notify_interested_services(self):
  37. interested_service = self._mkservice(is_interested=True)
  38. services = [
  39. self._mkservice(is_interested=False),
  40. interested_service,
  41. self._mkservice(is_interested=False),
  42. ]
  43. self.mock_as_api.query_user.return_value = make_awaitable(True)
  44. self.mock_store.get_app_services.return_value = services
  45. self.mock_store.get_user_by_id.return_value = make_awaitable([])
  46. event = Mock(
  47. sender="@someone:anywhere", type="m.room.message", room_id="!foo:bar"
  48. )
  49. self.mock_store.get_new_events_for_appservice.side_effect = [
  50. make_awaitable((0, [])),
  51. make_awaitable((1, [event])),
  52. ]
  53. self.handler.notify_interested_services(RoomStreamToken(None, 1))
  54. self.mock_scheduler.submit_event_for_as.assert_called_once_with(
  55. interested_service, event
  56. )
  57. def test_query_user_exists_unknown_user(self):
  58. user_id = "@someone:anywhere"
  59. services = [self._mkservice(is_interested=True)]
  60. services[0].is_interested_in_user.return_value = True
  61. self.mock_store.get_app_services.return_value = services
  62. self.mock_store.get_user_by_id.return_value = make_awaitable(None)
  63. event = Mock(sender=user_id, type="m.room.message", room_id="!foo:bar")
  64. self.mock_as_api.query_user.return_value = make_awaitable(True)
  65. self.mock_store.get_new_events_for_appservice.side_effect = [
  66. make_awaitable((0, [event])),
  67. ]
  68. self.handler.notify_interested_services(RoomStreamToken(None, 0))
  69. self.mock_as_api.query_user.assert_called_once_with(services[0], user_id)
  70. def test_query_user_exists_known_user(self):
  71. user_id = "@someone:anywhere"
  72. services = [self._mkservice(is_interested=True)]
  73. services[0].is_interested_in_user.return_value = True
  74. self.mock_store.get_app_services.return_value = services
  75. self.mock_store.get_user_by_id.return_value = make_awaitable({"name": user_id})
  76. event = Mock(sender=user_id, type="m.room.message", room_id="!foo:bar")
  77. self.mock_as_api.query_user.return_value = make_awaitable(True)
  78. self.mock_store.get_new_events_for_appservice.side_effect = [
  79. make_awaitable((0, [event])),
  80. ]
  81. self.handler.notify_interested_services(RoomStreamToken(None, 0))
  82. self.assertFalse(
  83. self.mock_as_api.query_user.called,
  84. "query_user called when it shouldn't have been.",
  85. )
  86. def test_query_room_alias_exists(self):
  87. room_alias_str = "#foo:bar"
  88. room_alias = Mock()
  89. room_alias.to_string.return_value = room_alias_str
  90. room_id = "!alpha:bet"
  91. servers = ["aperture"]
  92. interested_service = self._mkservice_alias(is_interested_in_alias=True)
  93. services = [
  94. self._mkservice_alias(is_interested_in_alias=False),
  95. interested_service,
  96. self._mkservice_alias(is_interested_in_alias=False),
  97. ]
  98. self.mock_as_api.query_alias.return_value = make_awaitable(True)
  99. self.mock_store.get_app_services.return_value = services
  100. self.mock_store.get_association_from_room_alias.return_value = make_awaitable(
  101. Mock(room_id=room_id, servers=servers)
  102. )
  103. result = self.successResultOf(
  104. defer.ensureDeferred(self.handler.query_room_alias_exists(room_alias))
  105. )
  106. self.mock_as_api.query_alias.assert_called_once_with(
  107. interested_service, room_alias_str
  108. )
  109. self.assertEquals(result.room_id, room_id)
  110. self.assertEquals(result.servers, servers)
  111. def test_get_3pe_protocols_no_appservices(self):
  112. self.mock_store.get_app_services.return_value = []
  113. response = self.successResultOf(
  114. defer.ensureDeferred(self.handler.get_3pe_protocols("my-protocol"))
  115. )
  116. self.mock_as_api.get_3pe_protocol.assert_not_called()
  117. self.assertEquals(response, {})
  118. def test_get_3pe_protocols_no_protocols(self):
  119. service = self._mkservice(False, [])
  120. self.mock_store.get_app_services.return_value = [service]
  121. response = self.successResultOf(
  122. defer.ensureDeferred(self.handler.get_3pe_protocols())
  123. )
  124. self.mock_as_api.get_3pe_protocol.assert_not_called()
  125. self.assertEquals(response, {})
  126. def test_get_3pe_protocols_protocol_no_response(self):
  127. service = self._mkservice(False, ["my-protocol"])
  128. self.mock_store.get_app_services.return_value = [service]
  129. self.mock_as_api.get_3pe_protocol.return_value = make_awaitable(None)
  130. response = self.successResultOf(
  131. defer.ensureDeferred(self.handler.get_3pe_protocols())
  132. )
  133. self.mock_as_api.get_3pe_protocol.assert_called_once_with(
  134. service, "my-protocol"
  135. )
  136. self.assertEquals(response, {})
  137. def test_get_3pe_protocols_select_one_protocol(self):
  138. service = self._mkservice(False, ["my-protocol"])
  139. self.mock_store.get_app_services.return_value = [service]
  140. self.mock_as_api.get_3pe_protocol.return_value = make_awaitable(
  141. {"x-protocol-data": 42, "instances": []}
  142. )
  143. response = self.successResultOf(
  144. defer.ensureDeferred(self.handler.get_3pe_protocols("my-protocol"))
  145. )
  146. self.mock_as_api.get_3pe_protocol.assert_called_once_with(
  147. service, "my-protocol"
  148. )
  149. self.assertEquals(
  150. response, {"my-protocol": {"x-protocol-data": 42, "instances": []}}
  151. )
  152. def test_get_3pe_protocols_one_protocol(self):
  153. service = self._mkservice(False, ["my-protocol"])
  154. self.mock_store.get_app_services.return_value = [service]
  155. self.mock_as_api.get_3pe_protocol.return_value = make_awaitable(
  156. {"x-protocol-data": 42, "instances": []}
  157. )
  158. response = self.successResultOf(
  159. defer.ensureDeferred(self.handler.get_3pe_protocols())
  160. )
  161. self.mock_as_api.get_3pe_protocol.assert_called_once_with(
  162. service, "my-protocol"
  163. )
  164. self.assertEquals(
  165. response, {"my-protocol": {"x-protocol-data": 42, "instances": []}}
  166. )
  167. def test_get_3pe_protocols_multiple_protocol(self):
  168. service_one = self._mkservice(False, ["my-protocol"])
  169. service_two = self._mkservice(False, ["other-protocol"])
  170. self.mock_store.get_app_services.return_value = [service_one, service_two]
  171. self.mock_as_api.get_3pe_protocol.return_value = make_awaitable(
  172. {"x-protocol-data": 42, "instances": []}
  173. )
  174. response = self.successResultOf(
  175. defer.ensureDeferred(self.handler.get_3pe_protocols())
  176. )
  177. self.mock_as_api.get_3pe_protocol.assert_called()
  178. self.assertEquals(
  179. response,
  180. {
  181. "my-protocol": {"x-protocol-data": 42, "instances": []},
  182. "other-protocol": {"x-protocol-data": 42, "instances": []},
  183. },
  184. )
  185. def test_get_3pe_protocols_multiple_info(self):
  186. service_one = self._mkservice(False, ["my-protocol"])
  187. service_two = self._mkservice(False, ["my-protocol"])
  188. async def get_3pe_protocol(service, unusedProtocol):
  189. if service == service_one:
  190. return {
  191. "x-protocol-data": 42,
  192. "instances": [{"desc": "Alice's service"}],
  193. }
  194. if service == service_two:
  195. return {
  196. "x-protocol-data": 36,
  197. "x-not-used": 45,
  198. "instances": [{"desc": "Bob's service"}],
  199. }
  200. raise Exception("Unexpected service")
  201. self.mock_store.get_app_services.return_value = [service_one, service_two]
  202. self.mock_as_api.get_3pe_protocol = get_3pe_protocol
  203. response = self.successResultOf(
  204. defer.ensureDeferred(self.handler.get_3pe_protocols())
  205. )
  206. # It's expected that the second service's data doesn't appear in the response
  207. self.assertEquals(
  208. response,
  209. {
  210. "my-protocol": {
  211. "x-protocol-data": 42,
  212. "instances": [
  213. {
  214. "desc": "Alice's service",
  215. },
  216. {"desc": "Bob's service"},
  217. ],
  218. },
  219. },
  220. )
  221. def test_notify_interested_services_ephemeral(self):
  222. """
  223. Test sending ephemeral events to the appservice handler are scheduled
  224. to be pushed out to interested appservices, and that the stream ID is
  225. updated accordingly.
  226. """
  227. interested_service = self._mkservice(is_interested=True)
  228. services = [interested_service]
  229. self.mock_store.get_app_services.return_value = services
  230. self.mock_store.get_type_stream_id_for_appservice.return_value = make_awaitable(
  231. 579
  232. )
  233. event = Mock(event_id="event_1")
  234. self.event_source.sources.receipt.get_new_events_as.return_value = (
  235. make_awaitable(([event], None))
  236. )
  237. self.handler.notify_interested_services_ephemeral(
  238. "receipt_key", 580, ["@fakerecipient:example.com"]
  239. )
  240. self.mock_scheduler.submit_ephemeral_events_for_as.assert_called_once_with(
  241. interested_service, [event]
  242. )
  243. self.mock_store.set_type_stream_id_for_appservice.assert_called_once_with(
  244. interested_service,
  245. "read_receipt",
  246. 580,
  247. )
  248. def test_notify_interested_services_ephemeral_out_of_order(self):
  249. """
  250. Test sending out of order ephemeral events to the appservice handler
  251. are ignored.
  252. """
  253. interested_service = self._mkservice(is_interested=True)
  254. services = [interested_service]
  255. self.mock_store.get_app_services.return_value = services
  256. self.mock_store.get_type_stream_id_for_appservice.return_value = make_awaitable(
  257. 580
  258. )
  259. event = Mock(event_id="event_1")
  260. self.event_source.sources.receipt.get_new_events_as.return_value = (
  261. make_awaitable(([event], None))
  262. )
  263. self.handler.notify_interested_services_ephemeral(
  264. "receipt_key", 580, ["@fakerecipient:example.com"]
  265. )
  266. self.mock_scheduler.submit_ephemeral_events_for_as.assert_not_called()
  267. def _mkservice(self, is_interested, protocols=None):
  268. service = Mock()
  269. service.is_interested.return_value = make_awaitable(is_interested)
  270. service.token = "mock_service_token"
  271. service.url = "mock_service_url"
  272. service.protocols = protocols
  273. return service
  274. def _mkservice_alias(self, is_interested_in_alias):
  275. service = Mock()
  276. service.is_interested_in_alias.return_value = is_interested_in_alias
  277. service.token = "mock_service_token"
  278. service.url = "mock_service_url"
  279. return service