test_http.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2018 New Vector
  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.defer import Deferred
  17. import synapse.rest.admin
  18. from synapse.logging.context import make_deferred_yieldable
  19. from synapse.rest.client.v1 import login, room
  20. from tests.unittest import HomeserverTestCase
  21. class HTTPPusherTests(HomeserverTestCase):
  22. servlets = [
  23. synapse.rest.admin.register_servlets_for_client_rest_resource,
  24. room.register_servlets,
  25. login.register_servlets,
  26. ]
  27. user_id = True
  28. hijack_auth = False
  29. def make_homeserver(self, reactor, clock):
  30. self.push_attempts = []
  31. m = Mock()
  32. def post_json_get_json(url, body):
  33. d = Deferred()
  34. self.push_attempts.append((d, url, body))
  35. return make_deferred_yieldable(d)
  36. m.post_json_get_json = post_json_get_json
  37. config = self.default_config()
  38. config["start_pushers"] = True
  39. hs = self.setup_test_homeserver(config=config, proxied_http_client=m)
  40. return hs
  41. def test_sends_http(self):
  42. """
  43. The HTTP pusher will send pushes for each message to a HTTP endpoint
  44. when configured to do so.
  45. """
  46. # Register the user who gets notified
  47. user_id = self.register_user("user", "pass")
  48. access_token = self.login("user", "pass")
  49. # Register the user who sends the message
  50. other_user_id = self.register_user("otheruser", "pass")
  51. other_access_token = self.login("otheruser", "pass")
  52. # Register the pusher
  53. user_tuple = self.get_success(
  54. self.hs.get_datastore().get_user_by_access_token(access_token)
  55. )
  56. token_id = user_tuple.token_id
  57. self.get_success(
  58. self.hs.get_pusherpool().add_pusher(
  59. user_id=user_id,
  60. access_token=token_id,
  61. kind="http",
  62. app_id="m.http",
  63. app_display_name="HTTP Push Notifications",
  64. device_display_name="pushy push",
  65. pushkey="a@example.com",
  66. lang=None,
  67. data={"url": "example.com"},
  68. )
  69. )
  70. # Create a room
  71. room = self.helper.create_room_as(user_id, tok=access_token)
  72. # The other user joins
  73. self.helper.join(room=room, user=other_user_id, tok=other_access_token)
  74. # The other user sends some messages
  75. self.helper.send(room, body="Hi!", tok=other_access_token)
  76. self.helper.send(room, body="There!", tok=other_access_token)
  77. # Get the stream ordering before it gets sent
  78. pushers = self.get_success(
  79. self.hs.get_datastore().get_pushers_by({"user_name": user_id})
  80. )
  81. pushers = list(pushers)
  82. self.assertEqual(len(pushers), 1)
  83. last_stream_ordering = pushers[0]["last_stream_ordering"]
  84. # Advance time a bit, so the pusher will register something has happened
  85. self.pump()
  86. # It hasn't succeeded yet, so the stream ordering shouldn't have moved
  87. pushers = self.get_success(
  88. self.hs.get_datastore().get_pushers_by({"user_name": user_id})
  89. )
  90. pushers = list(pushers)
  91. self.assertEqual(len(pushers), 1)
  92. self.assertEqual(last_stream_ordering, pushers[0]["last_stream_ordering"])
  93. # One push was attempted to be sent -- it'll be the first message
  94. self.assertEqual(len(self.push_attempts), 1)
  95. self.assertEqual(self.push_attempts[0][1], "example.com")
  96. self.assertEqual(
  97. self.push_attempts[0][2]["notification"]["content"]["body"], "Hi!"
  98. )
  99. # Make the push succeed
  100. self.push_attempts[0][0].callback({})
  101. self.pump()
  102. # The stream ordering has increased
  103. pushers = self.get_success(
  104. self.hs.get_datastore().get_pushers_by({"user_name": user_id})
  105. )
  106. pushers = list(pushers)
  107. self.assertEqual(len(pushers), 1)
  108. self.assertTrue(pushers[0]["last_stream_ordering"] > last_stream_ordering)
  109. last_stream_ordering = pushers[0]["last_stream_ordering"]
  110. # Now it'll try and send the second push message, which will be the second one
  111. self.assertEqual(len(self.push_attempts), 2)
  112. self.assertEqual(self.push_attempts[1][1], "example.com")
  113. self.assertEqual(
  114. self.push_attempts[1][2]["notification"]["content"]["body"], "There!"
  115. )
  116. # Make the second push succeed
  117. self.push_attempts[1][0].callback({})
  118. self.pump()
  119. # The stream ordering has increased, again
  120. pushers = self.get_success(
  121. self.hs.get_datastore().get_pushers_by({"user_name": user_id})
  122. )
  123. pushers = list(pushers)
  124. self.assertEqual(len(pushers), 1)
  125. self.assertTrue(pushers[0]["last_stream_ordering"] > last_stream_ordering)
  126. def test_sends_high_priority_for_encrypted(self):
  127. """
  128. The HTTP pusher will send pushes at high priority if they correspond
  129. to an encrypted message.
  130. This will happen both in 1:1 rooms and larger rooms.
  131. """
  132. # Register the user who gets notified
  133. user_id = self.register_user("user", "pass")
  134. access_token = self.login("user", "pass")
  135. # Register the user who sends the message
  136. other_user_id = self.register_user("otheruser", "pass")
  137. other_access_token = self.login("otheruser", "pass")
  138. # Register a third user
  139. yet_another_user_id = self.register_user("yetanotheruser", "pass")
  140. yet_another_access_token = self.login("yetanotheruser", "pass")
  141. # Create a room
  142. room = self.helper.create_room_as(user_id, tok=access_token)
  143. # The other user joins
  144. self.helper.join(room=room, user=other_user_id, tok=other_access_token)
  145. # Register the pusher
  146. user_tuple = self.get_success(
  147. self.hs.get_datastore().get_user_by_access_token(access_token)
  148. )
  149. token_id = user_tuple.token_id
  150. self.get_success(
  151. self.hs.get_pusherpool().add_pusher(
  152. user_id=user_id,
  153. access_token=token_id,
  154. kind="http",
  155. app_id="m.http",
  156. app_display_name="HTTP Push Notifications",
  157. device_display_name="pushy push",
  158. pushkey="a@example.com",
  159. lang=None,
  160. data={"url": "example.com"},
  161. )
  162. )
  163. # Send an encrypted event
  164. # I know there'd normally be set-up of an encrypted room first
  165. # but this will do for our purposes
  166. self.helper.send_event(
  167. room,
  168. "m.room.encrypted",
  169. content={
  170. "algorithm": "m.megolm.v1.aes-sha2",
  171. "sender_key": "6lImKbzK51MzWLwHh8tUM3UBBSBrLlgup/OOCGTvumM",
  172. "ciphertext": "AwgAErABoRxwpMipdgiwXgu46rHiWQ0DmRj0qUlPrMraBUDk"
  173. "leTnJRljpuc7IOhsYbLY3uo2WI0ab/ob41sV+3JEIhODJPqH"
  174. "TK7cEZaIL+/up9e+dT9VGF5kRTWinzjkeqO8FU5kfdRjm+3w"
  175. "0sy3o1OCpXXCfO+faPhbV/0HuK4ndx1G+myNfK1Nk/CxfMcT"
  176. "BT+zDS/Df/QePAHVbrr9uuGB7fW8ogW/ulnydgZPRluusFGv"
  177. "J3+cg9LoPpZPAmv5Me3ec7NtdlfN0oDZ0gk3TiNkkhsxDG9Y"
  178. "YcNzl78USI0q8+kOV26Bu5dOBpU4WOuojXZHJlP5lMgdzLLl"
  179. "EQ0",
  180. "session_id": "IigqfNWLL+ez/Is+Duwp2s4HuCZhFG9b9CZKTYHtQ4A",
  181. "device_id": "AHQDUSTAAA",
  182. },
  183. tok=other_access_token,
  184. )
  185. # Advance time a bit, so the pusher will register something has happened
  186. self.pump()
  187. # Make the push succeed
  188. self.push_attempts[0][0].callback({})
  189. self.pump()
  190. # Check our push made it with high priority
  191. self.assertEqual(len(self.push_attempts), 1)
  192. self.assertEqual(self.push_attempts[0][1], "example.com")
  193. self.assertEqual(self.push_attempts[0][2]["notification"]["prio"], "high")
  194. # Add yet another person — we want to make this room not a 1:1
  195. # (as encrypted messages in a 1:1 currently have tweaks applied
  196. # so it doesn't properly exercise the condition of all encrypted
  197. # messages need to be high).
  198. self.helper.join(
  199. room=room, user=yet_another_user_id, tok=yet_another_access_token
  200. )
  201. # Check no push notifications are sent regarding the membership changes
  202. # (that would confuse the test)
  203. self.pump()
  204. self.assertEqual(len(self.push_attempts), 1)
  205. # Send another encrypted event
  206. self.helper.send_event(
  207. room,
  208. "m.room.encrypted",
  209. content={
  210. "ciphertext": "AwgAEoABtEuic/2DF6oIpNH+q/PonzlhXOVho8dTv0tzFr5m"
  211. "9vTo50yabx3nxsRlP2WxSqa8I07YftP+EKWCWJvTkg6o7zXq"
  212. "6CK+GVvLQOVgK50SfvjHqJXN+z1VEqj+5mkZVN/cAgJzoxcH"
  213. "zFHkwDPJC8kQs47IHd8EO9KBUK4v6+NQ1uE/BIak4qAf9aS/"
  214. "kI+f0gjn9IY9K6LXlah82A/iRyrIrxkCkE/n0VfvLhaWFecC"
  215. "sAWTcMLoF6fh1Jpke95mljbmFSpsSd/eEQw",
  216. "device_id": "SRCFTWTHXO",
  217. "session_id": "eMA+bhGczuTz1C5cJR1YbmrnnC6Goni4lbvS5vJ1nG4",
  218. "algorithm": "m.megolm.v1.aes-sha2",
  219. "sender_key": "rC/XSIAiYrVGSuaHMop8/pTZbku4sQKBZwRwukgnN1c",
  220. },
  221. tok=other_access_token,
  222. )
  223. # Advance time a bit, so the pusher will register something has happened
  224. self.pump()
  225. self.assertEqual(len(self.push_attempts), 2)
  226. self.assertEqual(self.push_attempts[1][1], "example.com")
  227. self.assertEqual(self.push_attempts[1][2]["notification"]["prio"], "high")
  228. def test_sends_high_priority_for_one_to_one_only(self):
  229. """
  230. The HTTP pusher will send pushes at high priority if they correspond
  231. to a message in a one-to-one room.
  232. """
  233. # Register the user who gets notified
  234. user_id = self.register_user("user", "pass")
  235. access_token = self.login("user", "pass")
  236. # Register the user who sends the message
  237. other_user_id = self.register_user("otheruser", "pass")
  238. other_access_token = self.login("otheruser", "pass")
  239. # Register a third user
  240. yet_another_user_id = self.register_user("yetanotheruser", "pass")
  241. yet_another_access_token = self.login("yetanotheruser", "pass")
  242. # Create a room
  243. room = self.helper.create_room_as(user_id, tok=access_token)
  244. # The other user joins
  245. self.helper.join(room=room, user=other_user_id, tok=other_access_token)
  246. # Register the pusher
  247. user_tuple = self.get_success(
  248. self.hs.get_datastore().get_user_by_access_token(access_token)
  249. )
  250. token_id = user_tuple.token_id
  251. self.get_success(
  252. self.hs.get_pusherpool().add_pusher(
  253. user_id=user_id,
  254. access_token=token_id,
  255. kind="http",
  256. app_id="m.http",
  257. app_display_name="HTTP Push Notifications",
  258. device_display_name="pushy push",
  259. pushkey="a@example.com",
  260. lang=None,
  261. data={"url": "example.com"},
  262. )
  263. )
  264. # Send a message
  265. self.helper.send(room, body="Hi!", tok=other_access_token)
  266. # Advance time a bit, so the pusher will register something has happened
  267. self.pump()
  268. # Make the push succeed
  269. self.push_attempts[0][0].callback({})
  270. self.pump()
  271. # Check our push made it with high priority — this is a one-to-one room
  272. self.assertEqual(len(self.push_attempts), 1)
  273. self.assertEqual(self.push_attempts[0][1], "example.com")
  274. self.assertEqual(self.push_attempts[0][2]["notification"]["prio"], "high")
  275. # Yet another user joins
  276. self.helper.join(
  277. room=room, user=yet_another_user_id, tok=yet_another_access_token
  278. )
  279. # Check no push notifications are sent regarding the membership changes
  280. # (that would confuse the test)
  281. self.pump()
  282. self.assertEqual(len(self.push_attempts), 1)
  283. # Send another event
  284. self.helper.send(room, body="Welcome!", tok=other_access_token)
  285. # Advance time a bit, so the pusher will register something has happened
  286. self.pump()
  287. self.assertEqual(len(self.push_attempts), 2)
  288. self.assertEqual(self.push_attempts[1][1], "example.com")
  289. # check that this is low-priority
  290. self.assertEqual(self.push_attempts[1][2]["notification"]["prio"], "low")
  291. def test_sends_high_priority_for_mention(self):
  292. """
  293. The HTTP pusher will send pushes at high priority if they correspond
  294. to a message containing the user's display name.
  295. """
  296. # Register the user who gets notified
  297. user_id = self.register_user("user", "pass")
  298. access_token = self.login("user", "pass")
  299. # Register the user who sends the message
  300. other_user_id = self.register_user("otheruser", "pass")
  301. other_access_token = self.login("otheruser", "pass")
  302. # Register a third user
  303. yet_another_user_id = self.register_user("yetanotheruser", "pass")
  304. yet_another_access_token = self.login("yetanotheruser", "pass")
  305. # Create a room
  306. room = self.helper.create_room_as(user_id, tok=access_token)
  307. # The other users join
  308. self.helper.join(room=room, user=other_user_id, tok=other_access_token)
  309. self.helper.join(
  310. room=room, user=yet_another_user_id, tok=yet_another_access_token
  311. )
  312. # Register the pusher
  313. user_tuple = self.get_success(
  314. self.hs.get_datastore().get_user_by_access_token(access_token)
  315. )
  316. token_id = user_tuple.token_id
  317. self.get_success(
  318. self.hs.get_pusherpool().add_pusher(
  319. user_id=user_id,
  320. access_token=token_id,
  321. kind="http",
  322. app_id="m.http",
  323. app_display_name="HTTP Push Notifications",
  324. device_display_name="pushy push",
  325. pushkey="a@example.com",
  326. lang=None,
  327. data={"url": "example.com"},
  328. )
  329. )
  330. # Send a message
  331. self.helper.send(room, body="Oh, user, hello!", tok=other_access_token)
  332. # Advance time a bit, so the pusher will register something has happened
  333. self.pump()
  334. # Make the push succeed
  335. self.push_attempts[0][0].callback({})
  336. self.pump()
  337. # Check our push made it with high priority
  338. self.assertEqual(len(self.push_attempts), 1)
  339. self.assertEqual(self.push_attempts[0][1], "example.com")
  340. self.assertEqual(self.push_attempts[0][2]["notification"]["prio"], "high")
  341. # Send another event, this time with no mention
  342. self.helper.send(room, body="Are you there?", tok=other_access_token)
  343. # Advance time a bit, so the pusher will register something has happened
  344. self.pump()
  345. self.assertEqual(len(self.push_attempts), 2)
  346. self.assertEqual(self.push_attempts[1][1], "example.com")
  347. # check that this is low-priority
  348. self.assertEqual(self.push_attempts[1][2]["notification"]["prio"], "low")
  349. def test_sends_high_priority_for_atroom(self):
  350. """
  351. The HTTP pusher will send pushes at high priority if they correspond
  352. to a message that contains @room.
  353. """
  354. # Register the user who gets notified
  355. user_id = self.register_user("user", "pass")
  356. access_token = self.login("user", "pass")
  357. # Register the user who sends the message
  358. other_user_id = self.register_user("otheruser", "pass")
  359. other_access_token = self.login("otheruser", "pass")
  360. # Register a third user
  361. yet_another_user_id = self.register_user("yetanotheruser", "pass")
  362. yet_another_access_token = self.login("yetanotheruser", "pass")
  363. # Create a room (as other_user so the power levels are compatible with
  364. # other_user sending @room).
  365. room = self.helper.create_room_as(other_user_id, tok=other_access_token)
  366. # The other users join
  367. self.helper.join(room=room, user=user_id, tok=access_token)
  368. self.helper.join(
  369. room=room, user=yet_another_user_id, tok=yet_another_access_token
  370. )
  371. # Register the pusher
  372. user_tuple = self.get_success(
  373. self.hs.get_datastore().get_user_by_access_token(access_token)
  374. )
  375. token_id = user_tuple.token_id
  376. self.get_success(
  377. self.hs.get_pusherpool().add_pusher(
  378. user_id=user_id,
  379. access_token=token_id,
  380. kind="http",
  381. app_id="m.http",
  382. app_display_name="HTTP Push Notifications",
  383. device_display_name="pushy push",
  384. pushkey="a@example.com",
  385. lang=None,
  386. data={"url": "example.com"},
  387. )
  388. )
  389. # Send a message
  390. self.helper.send(
  391. room,
  392. body="@room eeek! There's a spider on the table!",
  393. tok=other_access_token,
  394. )
  395. # Advance time a bit, so the pusher will register something has happened
  396. self.pump()
  397. # Make the push succeed
  398. self.push_attempts[0][0].callback({})
  399. self.pump()
  400. # Check our push made it with high priority
  401. self.assertEqual(len(self.push_attempts), 1)
  402. self.assertEqual(self.push_attempts[0][1], "example.com")
  403. self.assertEqual(self.push_attempts[0][2]["notification"]["prio"], "high")
  404. # Send another event, this time as someone without the power of @room
  405. self.helper.send(
  406. room, body="@room the spider is gone", tok=yet_another_access_token
  407. )
  408. # Advance time a bit, so the pusher will register something has happened
  409. self.pump()
  410. self.assertEqual(len(self.push_attempts), 2)
  411. self.assertEqual(self.push_attempts[1][1], "example.com")
  412. # check that this is low-priority
  413. self.assertEqual(self.push_attempts[1][2]["notification"]["prio"], "low")