test_presentable_names.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. # Copyright 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 typing import Iterable, Optional, Tuple
  15. from synapse.api.constants import EventTypes, Membership
  16. from synapse.api.room_versions import RoomVersions
  17. from synapse.events import FrozenEvent
  18. from synapse.push.presentable_names import calculate_room_name
  19. from synapse.types import StateKey, StateMap
  20. from tests import unittest
  21. class MockDataStore:
  22. """
  23. A fake data store which stores a mapping of state key to event content.
  24. (I.e. the state key is used as the event ID.)
  25. """
  26. def __init__(self, events: Iterable[Tuple[StateKey, dict]]):
  27. """
  28. Args:
  29. events: A state map to event contents.
  30. """
  31. self._events = {}
  32. for i, (event_id, content) in enumerate(events):
  33. self._events[event_id] = FrozenEvent(
  34. {
  35. "event_id": "$event_id",
  36. "type": event_id[0],
  37. "sender": "@user:test",
  38. "state_key": event_id[1],
  39. "room_id": "#room:test",
  40. "content": content,
  41. "origin_server_ts": i,
  42. },
  43. RoomVersions.V1,
  44. )
  45. async def get_event(
  46. self, event_id: StateKey, allow_none: bool = False
  47. ) -> Optional[FrozenEvent]:
  48. assert allow_none, "Mock not configured for allow_none = False"
  49. return self._events.get(event_id)
  50. async def get_events(self, event_ids: Iterable[StateKey]):
  51. # This is cheating since it just returns all events.
  52. return self._events
  53. class PresentableNamesTestCase(unittest.HomeserverTestCase):
  54. USER_ID = "@test:test"
  55. OTHER_USER_ID = "@user:test"
  56. def _calculate_room_name(
  57. self,
  58. events: StateMap[dict],
  59. user_id: str = "",
  60. fallback_to_members: bool = True,
  61. fallback_to_single_member: bool = True,
  62. ):
  63. # This isn't 100% accurate, but works with MockDataStore.
  64. room_state_ids = {k[0]: k[0] for k in events}
  65. return self.get_success(
  66. calculate_room_name(
  67. MockDataStore(events),
  68. room_state_ids,
  69. user_id or self.USER_ID,
  70. fallback_to_members,
  71. fallback_to_single_member,
  72. )
  73. )
  74. def test_name(self):
  75. """A room name event should be used."""
  76. events = [
  77. ((EventTypes.Name, ""), {"name": "test-name"}),
  78. ]
  79. self.assertEqual("test-name", self._calculate_room_name(events))
  80. # Check if the event content has garbage.
  81. events = [((EventTypes.Name, ""), {"foo": 1})]
  82. self.assertEqual("Empty Room", self._calculate_room_name(events))
  83. events = [((EventTypes.Name, ""), {"name": 1})]
  84. self.assertEqual(1, self._calculate_room_name(events))
  85. def test_canonical_alias(self):
  86. """An canonical alias should be used."""
  87. events = [
  88. ((EventTypes.CanonicalAlias, ""), {"alias": "#test-name:test"}),
  89. ]
  90. self.assertEqual("#test-name:test", self._calculate_room_name(events))
  91. # Check if the event content has garbage.
  92. events = [((EventTypes.CanonicalAlias, ""), {"foo": 1})]
  93. self.assertEqual("Empty Room", self._calculate_room_name(events))
  94. events = [((EventTypes.CanonicalAlias, ""), {"alias": "test-name"})]
  95. self.assertEqual("Empty Room", self._calculate_room_name(events))
  96. def test_invite(self):
  97. """An invite has special behaviour."""
  98. events = [
  99. ((EventTypes.Member, self.USER_ID), {"membership": Membership.INVITE}),
  100. ((EventTypes.Member, self.OTHER_USER_ID), {"displayname": "Other User"}),
  101. ]
  102. self.assertEqual("Invite from Other User", self._calculate_room_name(events))
  103. self.assertIsNone(
  104. self._calculate_room_name(events, fallback_to_single_member=False)
  105. )
  106. # Ensure this logic is skipped if we don't fallback to members.
  107. self.assertIsNone(self._calculate_room_name(events, fallback_to_members=False))
  108. # Check if the event content has garbage.
  109. events = [
  110. ((EventTypes.Member, self.USER_ID), {"membership": Membership.INVITE}),
  111. ((EventTypes.Member, self.OTHER_USER_ID), {"foo": 1}),
  112. ]
  113. self.assertEqual("Invite from @user:test", self._calculate_room_name(events))
  114. # No member event for sender.
  115. events = [
  116. ((EventTypes.Member, self.USER_ID), {"membership": Membership.INVITE}),
  117. ]
  118. self.assertEqual("Room Invite", self._calculate_room_name(events))
  119. def test_no_members(self):
  120. """Behaviour of an empty room."""
  121. events = []
  122. self.assertEqual("Empty Room", self._calculate_room_name(events))
  123. # Note that events with invalid (or missing) membership are ignored.
  124. events = [
  125. ((EventTypes.Member, self.OTHER_USER_ID), {"foo": 1}),
  126. ((EventTypes.Member, "@foo:test"), {"membership": "foo"}),
  127. ]
  128. self.assertEqual("Empty Room", self._calculate_room_name(events))
  129. def test_no_other_members(self):
  130. """Behaviour of a room with no other members in it."""
  131. events = [
  132. (
  133. (EventTypes.Member, self.USER_ID),
  134. {"membership": Membership.JOIN, "displayname": "Me"},
  135. ),
  136. ]
  137. self.assertEqual("Me", self._calculate_room_name(events))
  138. # Check if the event content has no displayname.
  139. events = [
  140. ((EventTypes.Member, self.USER_ID), {"membership": Membership.JOIN}),
  141. ]
  142. self.assertEqual("@test:test", self._calculate_room_name(events))
  143. # 3pid invite, use the other user (who is set as the sender).
  144. events = [
  145. ((EventTypes.Member, self.OTHER_USER_ID), {"membership": Membership.JOIN}),
  146. ]
  147. self.assertEqual(
  148. "nobody", self._calculate_room_name(events, user_id=self.OTHER_USER_ID)
  149. )
  150. events = [
  151. ((EventTypes.Member, self.OTHER_USER_ID), {"membership": Membership.JOIN}),
  152. ((EventTypes.ThirdPartyInvite, self.OTHER_USER_ID), {}),
  153. ]
  154. self.assertEqual(
  155. "Inviting email address",
  156. self._calculate_room_name(events, user_id=self.OTHER_USER_ID),
  157. )
  158. def test_one_other_member(self):
  159. """Behaviour of a room with a single other member."""
  160. events = [
  161. ((EventTypes.Member, self.USER_ID), {"membership": Membership.JOIN}),
  162. (
  163. (EventTypes.Member, self.OTHER_USER_ID),
  164. {"membership": Membership.JOIN, "displayname": "Other User"},
  165. ),
  166. ]
  167. self.assertEqual("Other User", self._calculate_room_name(events))
  168. self.assertIsNone(
  169. self._calculate_room_name(events, fallback_to_single_member=False)
  170. )
  171. # Check if the event content has no displayname and is an invite.
  172. events = [
  173. ((EventTypes.Member, self.USER_ID), {"membership": Membership.JOIN}),
  174. (
  175. (EventTypes.Member, self.OTHER_USER_ID),
  176. {"membership": Membership.INVITE},
  177. ),
  178. ]
  179. self.assertEqual("@user:test", self._calculate_room_name(events))
  180. def test_other_members(self):
  181. """Behaviour of a room with multiple other members."""
  182. # Two other members.
  183. events = [
  184. ((EventTypes.Member, self.USER_ID), {"membership": Membership.JOIN}),
  185. (
  186. (EventTypes.Member, self.OTHER_USER_ID),
  187. {"membership": Membership.JOIN, "displayname": "Other User"},
  188. ),
  189. ((EventTypes.Member, "@foo:test"), {"membership": Membership.JOIN}),
  190. ]
  191. self.assertEqual("Other User and @foo:test", self._calculate_room_name(events))
  192. # Three or more other members.
  193. events.append(
  194. ((EventTypes.Member, "@fourth:test"), {"membership": Membership.INVITE})
  195. )
  196. self.assertEqual("Other User and 2 others", self._calculate_room_name(events))