test_event_push_actions.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. # Copyright 2016-2021 The Matrix.org Foundation C.I.C.
  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 twisted.test.proto_helpers import MemoryReactor
  15. from synapse.rest import admin
  16. from synapse.rest.client import login, room
  17. from synapse.server import HomeServer
  18. from synapse.storage.databases.main.event_push_actions import NotifCounts
  19. from synapse.util import Clock
  20. from tests.unittest import HomeserverTestCase
  21. USER_ID = "@user:example.com"
  22. class EventPushActionsStoreTestCase(HomeserverTestCase):
  23. servlets = [
  24. admin.register_servlets,
  25. room.register_servlets,
  26. login.register_servlets,
  27. ]
  28. def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
  29. self.store = hs.get_datastores().main
  30. persist_events_store = hs.get_datastores().persist_events
  31. assert persist_events_store is not None
  32. self.persist_events_store = persist_events_store
  33. def test_get_unread_push_actions_for_user_in_range_for_http(self) -> None:
  34. self.get_success(
  35. self.store.get_unread_push_actions_for_user_in_range_for_http(
  36. USER_ID, 0, 1000, 20
  37. )
  38. )
  39. def test_get_unread_push_actions_for_user_in_range_for_email(self) -> None:
  40. self.get_success(
  41. self.store.get_unread_push_actions_for_user_in_range_for_email(
  42. USER_ID, 0, 1000, 20
  43. )
  44. )
  45. def test_count_aggregation(self) -> None:
  46. # Create a user to receive notifications and send receipts.
  47. user_id = self.register_user("user1235", "pass")
  48. token = self.login("user1235", "pass")
  49. # And another users to send events.
  50. other_id = self.register_user("other", "pass")
  51. other_token = self.login("other", "pass")
  52. # Create a room and put both users in it.
  53. room_id = self.helper.create_room_as(user_id, tok=token)
  54. self.helper.join(room_id, other_id, tok=other_token)
  55. last_event_id: str
  56. def _assert_counts(
  57. noitf_count: int, unread_count: int, highlight_count: int
  58. ) -> None:
  59. counts = self.get_success(
  60. self.store.db_pool.runInteraction(
  61. "get-unread-counts",
  62. self.store._get_unread_counts_by_receipt_txn,
  63. room_id,
  64. user_id,
  65. )
  66. )
  67. self.assertEqual(
  68. counts,
  69. NotifCounts(
  70. notify_count=noitf_count,
  71. unread_count=unread_count,
  72. highlight_count=highlight_count,
  73. ),
  74. )
  75. def _create_event(highlight: bool = False) -> str:
  76. result = self.helper.send_event(
  77. room_id,
  78. type="m.room.message",
  79. content={"msgtype": "m.text", "body": user_id if highlight else "msg"},
  80. tok=other_token,
  81. )
  82. nonlocal last_event_id
  83. last_event_id = result["event_id"]
  84. return last_event_id
  85. def _rotate() -> None:
  86. self.get_success(self.store._rotate_notifs())
  87. def _mark_read(event_id: str) -> None:
  88. self.get_success(
  89. self.store.insert_receipt(
  90. room_id,
  91. "m.read",
  92. user_id=user_id,
  93. event_ids=[event_id],
  94. data={},
  95. )
  96. )
  97. _assert_counts(0, 0, 0)
  98. _create_event()
  99. _assert_counts(1, 1, 0)
  100. _rotate()
  101. _assert_counts(1, 1, 0)
  102. event_id = _create_event()
  103. _assert_counts(2, 2, 0)
  104. _rotate()
  105. _assert_counts(2, 2, 0)
  106. _create_event()
  107. _mark_read(event_id)
  108. _assert_counts(1, 1, 0)
  109. _mark_read(last_event_id)
  110. _assert_counts(0, 0, 0)
  111. _create_event()
  112. _rotate()
  113. _assert_counts(1, 1, 0)
  114. # Delete old event push actions, this should not affect the (summarised) count.
  115. #
  116. # All event push actions are kept for 24 hours, so need to move forward
  117. # in time.
  118. self.pump(60 * 60 * 24)
  119. self.get_success(self.store._remove_old_push_actions_that_have_rotated())
  120. # Double check that the event push actions have been cleared (i.e. that
  121. # any results *must* come from the summary).
  122. result = self.get_success(
  123. self.store.db_pool.simple_select_list(
  124. table="event_push_actions",
  125. keyvalues={"1": 1},
  126. retcols=("event_id",),
  127. desc="",
  128. )
  129. )
  130. self.assertEqual(result, [])
  131. _assert_counts(1, 1, 0)
  132. _mark_read(last_event_id)
  133. _assert_counts(0, 0, 0)
  134. event_id = _create_event(True)
  135. _assert_counts(1, 1, 1)
  136. _rotate()
  137. _assert_counts(1, 1, 1)
  138. # Check that adding another notification and rotating after highlight
  139. # works.
  140. _create_event()
  141. _rotate()
  142. _assert_counts(2, 2, 1)
  143. # Check that sending read receipts at different points results in the
  144. # right counts.
  145. _mark_read(event_id)
  146. _assert_counts(1, 1, 0)
  147. _mark_read(last_event_id)
  148. _assert_counts(0, 0, 0)
  149. _create_event(True)
  150. _assert_counts(1, 1, 1)
  151. _mark_read(last_event_id)
  152. _assert_counts(0, 0, 0)
  153. _rotate()
  154. _assert_counts(0, 0, 0)
  155. def test_find_first_stream_ordering_after_ts(self) -> None:
  156. def add_event(so: int, ts: int) -> None:
  157. self.get_success(
  158. self.store.db_pool.simple_insert(
  159. "events",
  160. {
  161. "stream_ordering": so,
  162. "received_ts": ts,
  163. "event_id": "event%i" % so,
  164. "type": "",
  165. "room_id": "",
  166. "content": "",
  167. "processed": True,
  168. "outlier": False,
  169. "topological_ordering": 0,
  170. "depth": 0,
  171. },
  172. )
  173. )
  174. # start with the base case where there are no events in the table
  175. r = self.get_success(self.store.find_first_stream_ordering_after_ts(11))
  176. self.assertEqual(r, 0)
  177. # now with one event
  178. add_event(2, 10)
  179. r = self.get_success(self.store.find_first_stream_ordering_after_ts(9))
  180. self.assertEqual(r, 2)
  181. r = self.get_success(self.store.find_first_stream_ordering_after_ts(10))
  182. self.assertEqual(r, 2)
  183. r = self.get_success(self.store.find_first_stream_ordering_after_ts(11))
  184. self.assertEqual(r, 3)
  185. # add a bunch of dummy events to the events table
  186. for (stream_ordering, ts) in (
  187. (3, 110),
  188. (4, 120),
  189. (5, 120),
  190. (10, 130),
  191. (20, 140),
  192. ):
  193. add_event(stream_ordering, ts)
  194. r = self.get_success(self.store.find_first_stream_ordering_after_ts(110))
  195. self.assertEqual(r, 3, "First event after 110ms should be 3, was %i" % r)
  196. # 4 and 5 are both after 120: we want 4 rather than 5
  197. r = self.get_success(self.store.find_first_stream_ordering_after_ts(120))
  198. self.assertEqual(r, 4, "First event after 120ms should be 4, was %i" % r)
  199. r = self.get_success(self.store.find_first_stream_ordering_after_ts(129))
  200. self.assertEqual(r, 10, "First event after 129ms should be 10, was %i" % r)
  201. # check we can get the last event
  202. r = self.get_success(self.store.find_first_stream_ordering_after_ts(140))
  203. self.assertEqual(r, 20, "First event after 14ms should be 20, was %i" % r)
  204. # off the end
  205. r = self.get_success(self.store.find_first_stream_ordering_after_ts(160))
  206. self.assertEqual(r, 21)
  207. # check we can find an event at ordering zero
  208. add_event(0, 5)
  209. r = self.get_success(self.store.find_first_stream_ordering_after_ts(1))
  210. self.assertEqual(r, 0)