You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

267 lines
9.9 KiB

  1. # Copyright 2014-2016 OpenMarket Ltd
  2. # Copyright 2019 The Matrix.org Foundation C.I.C.
  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 typing import List, Optional, Tuple, cast
  16. from twisted.test.proto_helpers import MemoryReactor
  17. from synapse.api.constants import Membership
  18. from synapse.rest.admin import register_servlets_for_client_rest_resource
  19. from synapse.rest.client import login, room
  20. from synapse.server import HomeServer
  21. from synapse.types import UserID, create_requester
  22. from synapse.util import Clock
  23. from tests import unittest
  24. from tests.server import TestHomeServer
  25. from tests.test_utils import event_injection
  26. class RoomMemberStoreTestCase(unittest.HomeserverTestCase):
  27. servlets = [
  28. login.register_servlets,
  29. register_servlets_for_client_rest_resource,
  30. room.register_servlets,
  31. ]
  32. def prepare(self, reactor: MemoryReactor, clock: Clock, hs: TestHomeServer) -> None: # type: ignore[override]
  33. # We can't test the RoomMemberStore on its own without the other event
  34. # storage logic
  35. self.store = hs.get_datastores().main
  36. self.u_alice = self.register_user("alice", "pass")
  37. self.t_alice = self.login("alice", "pass")
  38. self.u_bob = self.register_user("bob", "pass")
  39. # User elsewhere on another host
  40. self.u_charlie = UserID.from_string("@charlie:elsewhere")
  41. def test_one_member(self) -> None:
  42. # Alice creates the room, and is automatically joined
  43. self.room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
  44. rooms_for_user = self.get_success(
  45. self.store.get_rooms_for_local_user_where_membership_is(
  46. self.u_alice, [Membership.JOIN]
  47. )
  48. )
  49. self.assertEqual([self.room], [m.room_id for m in rooms_for_user])
  50. def test_count_known_servers(self) -> None:
  51. """
  52. _count_known_servers will calculate how many servers are in a room.
  53. """
  54. self.room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
  55. self.inject_room_member(self.room, self.u_bob, Membership.JOIN)
  56. self.inject_room_member(self.room, self.u_charlie.to_string(), Membership.JOIN)
  57. servers = self.get_success(self.store._count_known_servers())
  58. self.assertEqual(servers, 2)
  59. def test_count_known_servers_stat_counter_disabled(self) -> None:
  60. """
  61. If enabled, the metrics for how many servers are known will be counted.
  62. """
  63. self.assertTrue("_known_servers_count" not in self.store.__dict__.keys())
  64. self.room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
  65. self.inject_room_member(self.room, self.u_bob, Membership.JOIN)
  66. self.inject_room_member(self.room, self.u_charlie.to_string(), Membership.JOIN)
  67. self.pump()
  68. self.assertTrue("_known_servers_count" not in self.store.__dict__.keys())
  69. @unittest.override_config(
  70. {"enable_metrics": True, "metrics_flags": {"known_servers": True}}
  71. )
  72. def test_count_known_servers_stat_counter_enabled(self) -> None:
  73. """
  74. If enabled, the metrics for how many servers are known will be counted.
  75. """
  76. # Initialises to 1 -- itself
  77. self.assertEqual(self.store._known_servers_count, 1)
  78. self.pump()
  79. # No rooms have been joined, so technically the SQL returns 0, but it
  80. # will still say it knows about itself.
  81. self.assertEqual(self.store._known_servers_count, 1)
  82. self.room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
  83. self.inject_room_member(self.room, self.u_bob, Membership.JOIN)
  84. self.inject_room_member(self.room, self.u_charlie.to_string(), Membership.JOIN)
  85. self.pump(1)
  86. # It now knows about Charlie's server.
  87. self.assertEqual(self.store._known_servers_count, 2)
  88. def test__null_byte_in_display_name_properly_handled(self) -> None:
  89. room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
  90. res = cast(
  91. List[Tuple[Optional[str], str]],
  92. self.get_success(
  93. self.store.db_pool.simple_select_list(
  94. "room_memberships",
  95. {"user_id": "@alice:test"},
  96. ["display_name", "event_id"],
  97. )
  98. ),
  99. )
  100. # Check that we only got one result back
  101. self.assertEqual(len(res), 1)
  102. # Check that alice's display name is "alice"
  103. self.assertEqual(res[0][0], "alice")
  104. # Grab the event_id to use later
  105. event_id = res[0][1]
  106. # Create a profile with the offending null byte in the display name
  107. new_profile = {"displayname": "ali\u0000ce"}
  108. # Ensure that the change goes smoothly and does not fail due to the null byte
  109. self.helper.change_membership(
  110. room,
  111. self.u_alice,
  112. self.u_alice,
  113. "join",
  114. extra_data=new_profile,
  115. tok=self.t_alice,
  116. )
  117. res2 = cast(
  118. List[Tuple[Optional[str], str]],
  119. self.get_success(
  120. self.store.db_pool.simple_select_list(
  121. "room_memberships",
  122. {"user_id": "@alice:test"},
  123. ["display_name", "event_id"],
  124. )
  125. ),
  126. )
  127. # Check that we only have two results
  128. self.assertEqual(len(res2), 2)
  129. # Filter out the previous event using the event_id we grabbed above
  130. row = [row for row in res2 if row[1] != event_id]
  131. # Check that alice's display name is now None
  132. self.assertIsNone(row[0][0])
  133. def test_room_is_locally_forgotten(self) -> None:
  134. """Test that when the last local user has forgotten a room it is known as forgotten."""
  135. # join two local and one remote user
  136. self.room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
  137. self.get_success(
  138. event_injection.inject_member_event(self.hs, self.room, self.u_bob, "join")
  139. )
  140. self.get_success(
  141. event_injection.inject_member_event(
  142. self.hs, self.room, self.u_charlie.to_string(), "join"
  143. )
  144. )
  145. self.assertFalse(
  146. self.get_success(self.store.is_locally_forgotten_room(self.room))
  147. )
  148. # local users leave the room and the room is not forgotten
  149. self.get_success(
  150. event_injection.inject_member_event(
  151. self.hs, self.room, self.u_alice, "leave"
  152. )
  153. )
  154. self.get_success(
  155. event_injection.inject_member_event(self.hs, self.room, self.u_bob, "leave")
  156. )
  157. self.assertFalse(
  158. self.get_success(self.store.is_locally_forgotten_room(self.room))
  159. )
  160. # first user forgets the room, room is not forgotten
  161. self.get_success(self.store.forget(self.u_alice, self.room))
  162. self.assertFalse(
  163. self.get_success(self.store.is_locally_forgotten_room(self.room))
  164. )
  165. # second (last local) user forgets the room and the room is forgotten
  166. self.get_success(self.store.forget(self.u_bob, self.room))
  167. self.assertTrue(
  168. self.get_success(self.store.is_locally_forgotten_room(self.room))
  169. )
  170. def test_join_locally_forgotten_room(self) -> None:
  171. """Tests if a user joins a forgotten room the room is not forgotten anymore."""
  172. self.room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
  173. self.assertFalse(
  174. self.get_success(self.store.is_locally_forgotten_room(self.room))
  175. )
  176. # after leaving and forget the room, it is forgotten
  177. self.get_success(
  178. event_injection.inject_member_event(
  179. self.hs, self.room, self.u_alice, "leave"
  180. )
  181. )
  182. self.get_success(self.store.forget(self.u_alice, self.room))
  183. self.assertTrue(
  184. self.get_success(self.store.is_locally_forgotten_room(self.room))
  185. )
  186. # after rejoin the room is not forgotten anymore
  187. self.get_success(
  188. event_injection.inject_member_event(
  189. self.hs, self.room, self.u_alice, "join"
  190. )
  191. )
  192. self.assertFalse(
  193. self.get_success(self.store.is_locally_forgotten_room(self.room))
  194. )
  195. class CurrentStateMembershipUpdateTestCase(unittest.HomeserverTestCase):
  196. def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
  197. self.store = hs.get_datastores().main
  198. self.room_creator = hs.get_room_creation_handler()
  199. def test_can_rerun_update(self) -> None:
  200. # First make sure we have completed all updates.
  201. self.wait_for_background_updates()
  202. # Now let's create a room, which will insert a membership
  203. user = UserID("alice", "test")
  204. requester = create_requester(user)
  205. self.get_success(self.room_creator.create_room(requester, {}))
  206. # Register the background update to run again.
  207. self.get_success(
  208. self.store.db_pool.simple_insert(
  209. table="background_updates",
  210. values={
  211. "update_name": "current_state_events_membership",
  212. "progress_json": "{}",
  213. "depends_on": None,
  214. },
  215. )
  216. )
  217. # ... and tell the DataStore that it hasn't finished all updates yet
  218. self.store.db_pool.updates._all_done = False
  219. # Now let's actually drive the updates to completion
  220. self.wait_for_background_updates()