test_http.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. # Copyright 2018 New Vector
  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.defer import Deferred
  16. import synapse.rest.admin
  17. from synapse.logging.context import make_deferred_yieldable
  18. from synapse.push import PusherConfigException
  19. from synapse.rest.client import login, receipts, room
  20. from tests.unittest import HomeserverTestCase, override_config
  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. receipts.register_servlets,
  27. ]
  28. user_id = True
  29. hijack_auth = False
  30. def default_config(self):
  31. config = super().default_config()
  32. config["start_pushers"] = True
  33. return config
  34. def make_homeserver(self, reactor, clock):
  35. self.push_attempts = []
  36. m = Mock()
  37. def post_json_get_json(url, body):
  38. d = Deferred()
  39. self.push_attempts.append((d, url, body))
  40. return make_deferred_yieldable(d)
  41. m.post_json_get_json = post_json_get_json
  42. hs = self.setup_test_homeserver(proxied_blacklisted_http_client=m)
  43. return hs
  44. def test_invalid_configuration(self):
  45. """Invalid push configurations should be rejected."""
  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 pusher
  50. user_tuple = self.get_success(
  51. self.hs.get_datastores().main.get_user_by_access_token(access_token)
  52. )
  53. token_id = user_tuple.token_id
  54. def test_data(data):
  55. self.get_failure(
  56. self.hs.get_pusherpool().add_pusher(
  57. user_id=user_id,
  58. access_token=token_id,
  59. kind="http",
  60. app_id="m.http",
  61. app_display_name="HTTP Push Notifications",
  62. device_display_name="pushy push",
  63. pushkey="a@example.com",
  64. lang=None,
  65. data=data,
  66. ),
  67. PusherConfigException,
  68. )
  69. # Data must be provided with a URL.
  70. test_data(None)
  71. test_data({})
  72. test_data({"url": 1})
  73. # A bare domain name isn't accepted.
  74. test_data({"url": "example.com"})
  75. # A URL without a path isn't accepted.
  76. test_data({"url": "http://example.com"})
  77. # A url with an incorrect path isn't accepted.
  78. test_data({"url": "http://example.com/foo"})
  79. def test_sends_http(self):
  80. """
  81. The HTTP pusher will send pushes for each message to a HTTP endpoint
  82. when configured to do so.
  83. """
  84. # Register the user who gets notified
  85. user_id = self.register_user("user", "pass")
  86. access_token = self.login("user", "pass")
  87. # Register the user who sends the message
  88. other_user_id = self.register_user("otheruser", "pass")
  89. other_access_token = self.login("otheruser", "pass")
  90. # Register the pusher
  91. user_tuple = self.get_success(
  92. self.hs.get_datastores().main.get_user_by_access_token(access_token)
  93. )
  94. token_id = user_tuple.token_id
  95. self.get_success(
  96. self.hs.get_pusherpool().add_pusher(
  97. user_id=user_id,
  98. access_token=token_id,
  99. kind="http",
  100. app_id="m.http",
  101. app_display_name="HTTP Push Notifications",
  102. device_display_name="pushy push",
  103. pushkey="a@example.com",
  104. lang=None,
  105. data={"url": "http://example.com/_matrix/push/v1/notify"},
  106. )
  107. )
  108. # Create a room
  109. room = self.helper.create_room_as(user_id, tok=access_token)
  110. # The other user joins
  111. self.helper.join(room=room, user=other_user_id, tok=other_access_token)
  112. # The other user sends some messages
  113. self.helper.send(room, body="Hi!", tok=other_access_token)
  114. self.helper.send(room, body="There!", tok=other_access_token)
  115. # Get the stream ordering before it gets sent
  116. pushers = self.get_success(
  117. self.hs.get_datastores().main.get_pushers_by({"user_name": user_id})
  118. )
  119. pushers = list(pushers)
  120. self.assertEqual(len(pushers), 1)
  121. last_stream_ordering = pushers[0].last_stream_ordering
  122. # Advance time a bit, so the pusher will register something has happened
  123. self.pump()
  124. # It hasn't succeeded yet, so the stream ordering shouldn't have moved
  125. pushers = self.get_success(
  126. self.hs.get_datastores().main.get_pushers_by({"user_name": user_id})
  127. )
  128. pushers = list(pushers)
  129. self.assertEqual(len(pushers), 1)
  130. self.assertEqual(last_stream_ordering, pushers[0].last_stream_ordering)
  131. # One push was attempted to be sent -- it'll be the first message
  132. self.assertEqual(len(self.push_attempts), 1)
  133. self.assertEqual(
  134. self.push_attempts[0][1], "http://example.com/_matrix/push/v1/notify"
  135. )
  136. self.assertEqual(
  137. self.push_attempts[0][2]["notification"]["content"]["body"], "Hi!"
  138. )
  139. # Make the push succeed
  140. self.push_attempts[0][0].callback({})
  141. self.pump()
  142. # The stream ordering has increased
  143. pushers = self.get_success(
  144. self.hs.get_datastores().main.get_pushers_by({"user_name": user_id})
  145. )
  146. pushers = list(pushers)
  147. self.assertEqual(len(pushers), 1)
  148. self.assertTrue(pushers[0].last_stream_ordering > last_stream_ordering)
  149. last_stream_ordering = pushers[0].last_stream_ordering
  150. # Now it'll try and send the second push message, which will be the second one
  151. self.assertEqual(len(self.push_attempts), 2)
  152. self.assertEqual(
  153. self.push_attempts[1][1], "http://example.com/_matrix/push/v1/notify"
  154. )
  155. self.assertEqual(
  156. self.push_attempts[1][2]["notification"]["content"]["body"], "There!"
  157. )
  158. # Make the second push succeed
  159. self.push_attempts[1][0].callback({})
  160. self.pump()
  161. # The stream ordering has increased, again
  162. pushers = self.get_success(
  163. self.hs.get_datastores().main.get_pushers_by({"user_name": user_id})
  164. )
  165. pushers = list(pushers)
  166. self.assertEqual(len(pushers), 1)
  167. self.assertTrue(pushers[0].last_stream_ordering > last_stream_ordering)
  168. def test_sends_high_priority_for_encrypted(self):
  169. """
  170. The HTTP pusher will send pushes at high priority if they correspond
  171. to an encrypted message.
  172. This will happen both in 1:1 rooms and larger rooms.
  173. """
  174. # Register the user who gets notified
  175. user_id = self.register_user("user", "pass")
  176. access_token = self.login("user", "pass")
  177. # Register the user who sends the message
  178. other_user_id = self.register_user("otheruser", "pass")
  179. other_access_token = self.login("otheruser", "pass")
  180. # Register a third user
  181. yet_another_user_id = self.register_user("yetanotheruser", "pass")
  182. yet_another_access_token = self.login("yetanotheruser", "pass")
  183. # Create a room
  184. room = self.helper.create_room_as(user_id, tok=access_token)
  185. # The other user joins
  186. self.helper.join(room=room, user=other_user_id, tok=other_access_token)
  187. # Register the pusher
  188. user_tuple = self.get_success(
  189. self.hs.get_datastores().main.get_user_by_access_token(access_token)
  190. )
  191. token_id = user_tuple.token_id
  192. self.get_success(
  193. self.hs.get_pusherpool().add_pusher(
  194. user_id=user_id,
  195. access_token=token_id,
  196. kind="http",
  197. app_id="m.http",
  198. app_display_name="HTTP Push Notifications",
  199. device_display_name="pushy push",
  200. pushkey="a@example.com",
  201. lang=None,
  202. data={"url": "http://example.com/_matrix/push/v1/notify"},
  203. )
  204. )
  205. # Send an encrypted event
  206. # I know there'd normally be set-up of an encrypted room first
  207. # but this will do for our purposes
  208. self.helper.send_event(
  209. room,
  210. "m.room.encrypted",
  211. content={
  212. "algorithm": "m.megolm.v1.aes-sha2",
  213. "sender_key": "6lImKbzK51MzWLwHh8tUM3UBBSBrLlgup/OOCGTvumM",
  214. "ciphertext": "AwgAErABoRxwpMipdgiwXgu46rHiWQ0DmRj0qUlPrMraBUDk"
  215. "leTnJRljpuc7IOhsYbLY3uo2WI0ab/ob41sV+3JEIhODJPqH"
  216. "TK7cEZaIL+/up9e+dT9VGF5kRTWinzjkeqO8FU5kfdRjm+3w"
  217. "0sy3o1OCpXXCfO+faPhbV/0HuK4ndx1G+myNfK1Nk/CxfMcT"
  218. "BT+zDS/Df/QePAHVbrr9uuGB7fW8ogW/ulnydgZPRluusFGv"
  219. "J3+cg9LoPpZPAmv5Me3ec7NtdlfN0oDZ0gk3TiNkkhsxDG9Y"
  220. "YcNzl78USI0q8+kOV26Bu5dOBpU4WOuojXZHJlP5lMgdzLLl"
  221. "EQ0",
  222. "session_id": "IigqfNWLL+ez/Is+Duwp2s4HuCZhFG9b9CZKTYHtQ4A",
  223. "device_id": "AHQDUSTAAA",
  224. },
  225. tok=other_access_token,
  226. )
  227. # Advance time a bit, so the pusher will register something has happened
  228. self.pump()
  229. # Make the push succeed
  230. self.push_attempts[0][0].callback({})
  231. self.pump()
  232. # Check our push made it with high priority
  233. self.assertEqual(len(self.push_attempts), 1)
  234. self.assertEqual(
  235. self.push_attempts[0][1], "http://example.com/_matrix/push/v1/notify"
  236. )
  237. self.assertEqual(self.push_attempts[0][2]["notification"]["prio"], "high")
  238. # Add yet another person — we want to make this room not a 1:1
  239. # (as encrypted messages in a 1:1 currently have tweaks applied
  240. # so it doesn't properly exercise the condition of all encrypted
  241. # messages need to be high).
  242. self.helper.join(
  243. room=room, user=yet_another_user_id, tok=yet_another_access_token
  244. )
  245. # Check no push notifications are sent regarding the membership changes
  246. # (that would confuse the test)
  247. self.pump()
  248. self.assertEqual(len(self.push_attempts), 1)
  249. # Send another encrypted event
  250. self.helper.send_event(
  251. room,
  252. "m.room.encrypted",
  253. content={
  254. "ciphertext": "AwgAEoABtEuic/2DF6oIpNH+q/PonzlhXOVho8dTv0tzFr5m"
  255. "9vTo50yabx3nxsRlP2WxSqa8I07YftP+EKWCWJvTkg6o7zXq"
  256. "6CK+GVvLQOVgK50SfvjHqJXN+z1VEqj+5mkZVN/cAgJzoxcH"
  257. "zFHkwDPJC8kQs47IHd8EO9KBUK4v6+NQ1uE/BIak4qAf9aS/"
  258. "kI+f0gjn9IY9K6LXlah82A/iRyrIrxkCkE/n0VfvLhaWFecC"
  259. "sAWTcMLoF6fh1Jpke95mljbmFSpsSd/eEQw",
  260. "device_id": "SRCFTWTHXO",
  261. "session_id": "eMA+bhGczuTz1C5cJR1YbmrnnC6Goni4lbvS5vJ1nG4",
  262. "algorithm": "m.megolm.v1.aes-sha2",
  263. "sender_key": "rC/XSIAiYrVGSuaHMop8/pTZbku4sQKBZwRwukgnN1c",
  264. },
  265. tok=other_access_token,
  266. )
  267. # Advance time a bit, so the pusher will register something has happened
  268. self.pump()
  269. self.assertEqual(len(self.push_attempts), 2)
  270. self.assertEqual(
  271. self.push_attempts[1][1], "http://example.com/_matrix/push/v1/notify"
  272. )
  273. self.assertEqual(self.push_attempts[1][2]["notification"]["prio"], "high")
  274. def test_sends_high_priority_for_one_to_one_only(self):
  275. """
  276. The HTTP pusher will send pushes at high priority if they correspond
  277. to a message in a one-to-one room.
  278. """
  279. # Register the user who gets notified
  280. user_id = self.register_user("user", "pass")
  281. access_token = self.login("user", "pass")
  282. # Register the user who sends the message
  283. other_user_id = self.register_user("otheruser", "pass")
  284. other_access_token = self.login("otheruser", "pass")
  285. # Register a third user
  286. yet_another_user_id = self.register_user("yetanotheruser", "pass")
  287. yet_another_access_token = self.login("yetanotheruser", "pass")
  288. # Create a room
  289. room = self.helper.create_room_as(user_id, tok=access_token)
  290. # The other user joins
  291. self.helper.join(room=room, user=other_user_id, tok=other_access_token)
  292. # Register the pusher
  293. user_tuple = self.get_success(
  294. self.hs.get_datastores().main.get_user_by_access_token(access_token)
  295. )
  296. token_id = user_tuple.token_id
  297. self.get_success(
  298. self.hs.get_pusherpool().add_pusher(
  299. user_id=user_id,
  300. access_token=token_id,
  301. kind="http",
  302. app_id="m.http",
  303. app_display_name="HTTP Push Notifications",
  304. device_display_name="pushy push",
  305. pushkey="a@example.com",
  306. lang=None,
  307. data={"url": "http://example.com/_matrix/push/v1/notify"},
  308. )
  309. )
  310. # Send a message
  311. self.helper.send(room, body="Hi!", tok=other_access_token)
  312. # Advance time a bit, so the pusher will register something has happened
  313. self.pump()
  314. # Make the push succeed
  315. self.push_attempts[0][0].callback({})
  316. self.pump()
  317. # Check our push made it with high priority — this is a one-to-one room
  318. self.assertEqual(len(self.push_attempts), 1)
  319. self.assertEqual(
  320. self.push_attempts[0][1], "http://example.com/_matrix/push/v1/notify"
  321. )
  322. self.assertEqual(self.push_attempts[0][2]["notification"]["prio"], "high")
  323. # Yet another user joins
  324. self.helper.join(
  325. room=room, user=yet_another_user_id, tok=yet_another_access_token
  326. )
  327. # Check no push notifications are sent regarding the membership changes
  328. # (that would confuse the test)
  329. self.pump()
  330. self.assertEqual(len(self.push_attempts), 1)
  331. # Send another event
  332. self.helper.send(room, body="Welcome!", tok=other_access_token)
  333. # Advance time a bit, so the pusher will register something has happened
  334. self.pump()
  335. self.assertEqual(len(self.push_attempts), 2)
  336. self.assertEqual(
  337. self.push_attempts[1][1], "http://example.com/_matrix/push/v1/notify"
  338. )
  339. # check that this is low-priority
  340. self.assertEqual(self.push_attempts[1][2]["notification"]["prio"], "low")
  341. def test_sends_high_priority_for_mention(self):
  342. """
  343. The HTTP pusher will send pushes at high priority if they correspond
  344. to a message containing the user's display name.
  345. """
  346. # Register the user who gets notified
  347. user_id = self.register_user("user", "pass")
  348. access_token = self.login("user", "pass")
  349. # Register the user who sends the message
  350. other_user_id = self.register_user("otheruser", "pass")
  351. other_access_token = self.login("otheruser", "pass")
  352. # Register a third user
  353. yet_another_user_id = self.register_user("yetanotheruser", "pass")
  354. yet_another_access_token = self.login("yetanotheruser", "pass")
  355. # Create a room
  356. room = self.helper.create_room_as(user_id, tok=access_token)
  357. # The other users join
  358. self.helper.join(room=room, user=other_user_id, tok=other_access_token)
  359. self.helper.join(
  360. room=room, user=yet_another_user_id, tok=yet_another_access_token
  361. )
  362. # Register the pusher
  363. user_tuple = self.get_success(
  364. self.hs.get_datastores().main.get_user_by_access_token(access_token)
  365. )
  366. token_id = user_tuple.token_id
  367. self.get_success(
  368. self.hs.get_pusherpool().add_pusher(
  369. user_id=user_id,
  370. access_token=token_id,
  371. kind="http",
  372. app_id="m.http",
  373. app_display_name="HTTP Push Notifications",
  374. device_display_name="pushy push",
  375. pushkey="a@example.com",
  376. lang=None,
  377. data={"url": "http://example.com/_matrix/push/v1/notify"},
  378. )
  379. )
  380. # Send a message
  381. self.helper.send(room, body="Oh, user, hello!", tok=other_access_token)
  382. # Advance time a bit, so the pusher will register something has happened
  383. self.pump()
  384. # Make the push succeed
  385. self.push_attempts[0][0].callback({})
  386. self.pump()
  387. # Check our push made it with high priority
  388. self.assertEqual(len(self.push_attempts), 1)
  389. self.assertEqual(
  390. self.push_attempts[0][1], "http://example.com/_matrix/push/v1/notify"
  391. )
  392. self.assertEqual(self.push_attempts[0][2]["notification"]["prio"], "high")
  393. # Send another event, this time with no mention
  394. self.helper.send(room, body="Are you there?", tok=other_access_token)
  395. # Advance time a bit, so the pusher will register something has happened
  396. self.pump()
  397. self.assertEqual(len(self.push_attempts), 2)
  398. self.assertEqual(
  399. self.push_attempts[1][1], "http://example.com/_matrix/push/v1/notify"
  400. )
  401. # check that this is low-priority
  402. self.assertEqual(self.push_attempts[1][2]["notification"]["prio"], "low")
  403. def test_sends_high_priority_for_atroom(self):
  404. """
  405. The HTTP pusher will send pushes at high priority if they correspond
  406. to a message that contains @room.
  407. """
  408. # Register the user who gets notified
  409. user_id = self.register_user("user", "pass")
  410. access_token = self.login("user", "pass")
  411. # Register the user who sends the message
  412. other_user_id = self.register_user("otheruser", "pass")
  413. other_access_token = self.login("otheruser", "pass")
  414. # Register a third user
  415. yet_another_user_id = self.register_user("yetanotheruser", "pass")
  416. yet_another_access_token = self.login("yetanotheruser", "pass")
  417. # Create a room (as other_user so the power levels are compatible with
  418. # other_user sending @room).
  419. room = self.helper.create_room_as(other_user_id, tok=other_access_token)
  420. # The other users join
  421. self.helper.join(room=room, user=user_id, tok=access_token)
  422. self.helper.join(
  423. room=room, user=yet_another_user_id, tok=yet_another_access_token
  424. )
  425. # Register the pusher
  426. user_tuple = self.get_success(
  427. self.hs.get_datastores().main.get_user_by_access_token(access_token)
  428. )
  429. token_id = user_tuple.token_id
  430. self.get_success(
  431. self.hs.get_pusherpool().add_pusher(
  432. user_id=user_id,
  433. access_token=token_id,
  434. kind="http",
  435. app_id="m.http",
  436. app_display_name="HTTP Push Notifications",
  437. device_display_name="pushy push",
  438. pushkey="a@example.com",
  439. lang=None,
  440. data={"url": "http://example.com/_matrix/push/v1/notify"},
  441. )
  442. )
  443. # Send a message
  444. self.helper.send(
  445. room,
  446. body="@room eeek! There's a spider on the table!",
  447. tok=other_access_token,
  448. )
  449. # Advance time a bit, so the pusher will register something has happened
  450. self.pump()
  451. # Make the push succeed
  452. self.push_attempts[0][0].callback({})
  453. self.pump()
  454. # Check our push made it with high priority
  455. self.assertEqual(len(self.push_attempts), 1)
  456. self.assertEqual(
  457. self.push_attempts[0][1], "http://example.com/_matrix/push/v1/notify"
  458. )
  459. self.assertEqual(self.push_attempts[0][2]["notification"]["prio"], "high")
  460. # Send another event, this time as someone without the power of @room
  461. self.helper.send(
  462. room, body="@room the spider is gone", tok=yet_another_access_token
  463. )
  464. # Advance time a bit, so the pusher will register something has happened
  465. self.pump()
  466. self.assertEqual(len(self.push_attempts), 2)
  467. self.assertEqual(
  468. self.push_attempts[1][1], "http://example.com/_matrix/push/v1/notify"
  469. )
  470. # check that this is low-priority
  471. self.assertEqual(self.push_attempts[1][2]["notification"]["prio"], "low")
  472. def test_push_unread_count_group_by_room(self):
  473. """
  474. The HTTP pusher will group unread count by number of unread rooms.
  475. """
  476. # Carry out common push count tests and setup
  477. self._test_push_unread_count()
  478. # Carry out our option-value specific test
  479. #
  480. # This push should still only contain an unread count of 1 (for 1 unread room)
  481. self._check_push_attempt(6, 1)
  482. @override_config({"push": {"group_unread_count_by_room": False}})
  483. def test_push_unread_count_message_count(self):
  484. """
  485. The HTTP pusher will send the total unread message count.
  486. """
  487. # Carry out common push count tests and setup
  488. self._test_push_unread_count()
  489. # Carry out our option-value specific test
  490. #
  491. # We're counting every unread message, so there should now be 3 since the
  492. # last read receipt
  493. self._check_push_attempt(6, 3)
  494. def _test_push_unread_count(self):
  495. """
  496. Tests that the correct unread count appears in sent push notifications
  497. Note that:
  498. * Sending messages will cause push notifications to go out to relevant users
  499. * Sending a read receipt will cause the HTTP pusher to check whether the unread
  500. count has changed since the last push notification. If so, a "badge update"
  501. notification goes out to the user that sent the receipt
  502. """
  503. # Register the user who gets notified
  504. user_id = self.register_user("user", "pass")
  505. access_token = self.login("user", "pass")
  506. # Register the user who sends the message
  507. other_user_id = self.register_user("other_user", "pass")
  508. other_access_token = self.login("other_user", "pass")
  509. # Create a room (as other_user)
  510. room_id = self.helper.create_room_as(other_user_id, tok=other_access_token)
  511. # The user to get notified joins
  512. self.helper.join(room=room_id, user=user_id, tok=access_token)
  513. # Register the pusher
  514. user_tuple = self.get_success(
  515. self.hs.get_datastores().main.get_user_by_access_token(access_token)
  516. )
  517. token_id = user_tuple.token_id
  518. self.get_success(
  519. self.hs.get_pusherpool().add_pusher(
  520. user_id=user_id,
  521. access_token=token_id,
  522. kind="http",
  523. app_id="m.http",
  524. app_display_name="HTTP Push Notifications",
  525. device_display_name="pushy push",
  526. pushkey="a@example.com",
  527. lang=None,
  528. data={"url": "http://example.com/_matrix/push/v1/notify"},
  529. )
  530. )
  531. # Send a message
  532. response = self.helper.send(
  533. room_id, body="Hello there!", tok=other_access_token
  534. )
  535. # To get an unread count, the user who is getting notified has to have a read
  536. # position in the room. We'll set the read position to this event in a moment
  537. first_message_event_id = response["event_id"]
  538. expected_push_attempts = 1
  539. self._check_push_attempt(expected_push_attempts, 0)
  540. self._send_read_request(access_token, first_message_event_id, room_id)
  541. # Unread count has not changed. Therefore, ensure that read request does not
  542. # trigger a push notification.
  543. self.assertEqual(len(self.push_attempts), 1)
  544. # Send another message
  545. response2 = self.helper.send(
  546. room_id, body="How's the weather today?", tok=other_access_token
  547. )
  548. second_message_event_id = response2["event_id"]
  549. expected_push_attempts += 1
  550. self._check_push_attempt(expected_push_attempts, 1)
  551. self._send_read_request(access_token, second_message_event_id, room_id)
  552. expected_push_attempts += 1
  553. self._check_push_attempt(expected_push_attempts, 0)
  554. # If we're grouping by room, sending more messages shouldn't increase the
  555. # unread count, as they're all being sent in the same room. Otherwise, it
  556. # should. Therefore, the last call to _check_push_attempt is done in the
  557. # caller method.
  558. self.helper.send(room_id, body="Hello?", tok=other_access_token)
  559. expected_push_attempts += 1
  560. self._advance_time_and_make_push_succeed(expected_push_attempts)
  561. self.helper.send(room_id, body="Hello??", tok=other_access_token)
  562. expected_push_attempts += 1
  563. self._advance_time_and_make_push_succeed(expected_push_attempts)
  564. self.helper.send(room_id, body="HELLO???", tok=other_access_token)
  565. def _advance_time_and_make_push_succeed(self, expected_push_attempts):
  566. self.pump()
  567. self.push_attempts[expected_push_attempts - 1][0].callback({})
  568. def _check_push_attempt(
  569. self, expected_push_attempts: int, expected_unread_count_last_push: int
  570. ) -> None:
  571. """
  572. Makes sure that the last expected push attempt succeeds and checks whether
  573. it contains the expected unread count.
  574. """
  575. self._advance_time_and_make_push_succeed(expected_push_attempts)
  576. # Check our push made it
  577. self.assertEqual(len(self.push_attempts), expected_push_attempts)
  578. _, push_url, push_body = self.push_attempts[expected_push_attempts - 1]
  579. self.assertEqual(
  580. push_url,
  581. "http://example.com/_matrix/push/v1/notify",
  582. )
  583. # Check that the unread count for the room is 0
  584. #
  585. # The unread count is zero as the user has no read receipt in the room yet
  586. self.assertEqual(
  587. push_body["notification"]["counts"]["unread"],
  588. expected_unread_count_last_push,
  589. )
  590. def _send_read_request(self, access_token, message_event_id, room_id):
  591. # Now set the user's read receipt position to the first event
  592. #
  593. # This will actually trigger a new notification to be sent out so that
  594. # even if the user does not receive another message, their unread
  595. # count goes down
  596. channel = self.make_request(
  597. "POST",
  598. "/rooms/%s/receipt/m.read/%s" % (room_id, message_event_id),
  599. {},
  600. access_token=access_token,
  601. )
  602. self.assertEqual(channel.code, 200, channel.json_body)