test_presencelike.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014 OpenMarket Ltd
  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. """This file contains tests of the "presence-like" data that is shared between
  16. presence and profiles; namely, the displayname and avatar_url."""
  17. from tests import unittest
  18. from twisted.internet import defer
  19. from mock import Mock, call, ANY, NonCallableMock
  20. from ..utils import MockClock, setup_test_homeserver
  21. from synapse.api.constants import PresenceState
  22. from synapse.handlers.presence import PresenceHandler
  23. from synapse.handlers.profile import ProfileHandler
  24. from synapse.types import UserID
  25. OFFLINE = PresenceState.OFFLINE
  26. UNAVAILABLE = PresenceState.UNAVAILABLE
  27. ONLINE = PresenceState.ONLINE
  28. class MockReplication(object):
  29. def __init__(self):
  30. self.edu_handlers = {}
  31. def register_edu_handler(self, edu_type, handler):
  32. self.edu_handlers[edu_type] = handler
  33. def register_query_handler(self, query_type, handler):
  34. pass
  35. def received_edu(self, origin, edu_type, content):
  36. self.edu_handlers[edu_type](origin, content)
  37. class PresenceAndProfileHandlers(object):
  38. def __init__(self, hs):
  39. self.presence_handler = PresenceHandler(hs)
  40. self.profile_handler = ProfileHandler(hs)
  41. class PresenceProfilelikeDataTestCase(unittest.TestCase):
  42. @defer.inlineCallbacks
  43. def setUp(self):
  44. hs = yield setup_test_homeserver(
  45. clock=MockClock(),
  46. datastore=Mock(spec=[
  47. "set_presence_state",
  48. "is_presence_visible",
  49. "set_profile_displayname",
  50. "get_rooms_for_user",
  51. ]),
  52. handlers=None,
  53. resource_for_federation=Mock(),
  54. http_client=None,
  55. replication_layer=MockReplication(),
  56. ratelimiter=NonCallableMock(spec_set=[
  57. "send_message",
  58. ]),
  59. )
  60. self.ratelimiter = hs.get_ratelimiter()
  61. self.ratelimiter.send_message.return_value = (True, 0)
  62. hs.handlers = PresenceAndProfileHandlers(hs)
  63. self.datastore = hs.get_datastore()
  64. self.replication = hs.get_replication_layer()
  65. self.replication.send_edu = Mock()
  66. def send_edu(*args, **kwargs):
  67. # print "send_edu: %s, %s" % (args, kwargs)
  68. return defer.succeed((200, "OK"))
  69. self.replication.send_edu.side_effect = send_edu
  70. def get_profile_displayname(user_localpart):
  71. return defer.succeed("Frank")
  72. self.datastore.get_profile_displayname = get_profile_displayname
  73. def is_presence_visible(*args, **kwargs):
  74. return defer.succeed(False)
  75. self.datastore.is_presence_visible = is_presence_visible
  76. def get_profile_avatar_url(user_localpart):
  77. return defer.succeed("http://foo")
  78. self.datastore.get_profile_avatar_url = get_profile_avatar_url
  79. self.presence_list = [
  80. {"observed_user_id": "@banana:test", "accepted": True},
  81. {"observed_user_id": "@clementine:test", "accepted": True},
  82. ]
  83. def get_presence_list(user_localpart, accepted=None):
  84. return defer.succeed(self.presence_list)
  85. self.datastore.get_presence_list = get_presence_list
  86. def user_rooms_intersect(userlist):
  87. return defer.succeed(False)
  88. self.datastore.user_rooms_intersect = user_rooms_intersect
  89. self.handlers = hs.get_handlers()
  90. self.mock_update_client = Mock()
  91. def update(*args, **kwargs):
  92. # print "mock_update_client: %s, %s" %(args, kwargs)
  93. return defer.succeed(None)
  94. self.mock_update_client.side_effect = update
  95. self.handlers.presence_handler.push_update_to_clients = (
  96. self.mock_update_client)
  97. hs.handlers.room_member_handler = Mock(spec=[
  98. "get_joined_rooms_for_user",
  99. ])
  100. hs.handlers.room_member_handler.get_joined_rooms_for_user = (
  101. lambda u: defer.succeed([]))
  102. # Some local users to test with
  103. self.u_apple = UserID.from_string("@apple:test")
  104. self.u_banana = UserID.from_string("@banana:test")
  105. self.u_clementine = UserID.from_string("@clementine:test")
  106. # Remote user
  107. self.u_potato = UserID.from_string("@potato:remote")
  108. self.mock_get_joined = (
  109. self.datastore.get_rooms_for_user
  110. )
  111. @defer.inlineCallbacks
  112. def test_set_my_state(self):
  113. self.presence_list = [
  114. {"observed_user_id": "@banana:test", "accepted": True},
  115. {"observed_user_id": "@clementine:test", "accepted": True},
  116. ]
  117. mocked_set = self.datastore.set_presence_state
  118. mocked_set.return_value = defer.succeed({"state": OFFLINE})
  119. yield self.handlers.presence_handler.set_state(
  120. target_user=self.u_apple, auth_user=self.u_apple,
  121. state={"presence": UNAVAILABLE, "status_msg": "Away"})
  122. mocked_set.assert_called_with("apple",
  123. {"state": UNAVAILABLE, "status_msg": "Away"}
  124. )
  125. @defer.inlineCallbacks
  126. def test_push_local(self):
  127. def get_joined(*args):
  128. return defer.succeed([])
  129. self.mock_get_joined.side_effect = get_joined
  130. self.presence_list = [
  131. {"observed_user_id": "@banana:test", "accepted": True},
  132. {"observed_user_id": "@clementine:test", "accepted": True},
  133. ]
  134. self.datastore.set_presence_state.return_value = defer.succeed(
  135. {"state": ONLINE}
  136. )
  137. # TODO(paul): Gut-wrenching
  138. from synapse.handlers.presence import UserPresenceCache
  139. self.handlers.presence_handler._user_cachemap[self.u_apple] = (
  140. UserPresenceCache()
  141. )
  142. self.handlers.presence_handler._user_cachemap[self.u_apple].update(
  143. {"presence": OFFLINE}, serial=0
  144. )
  145. apple_set = self.handlers.presence_handler._local_pushmap.setdefault(
  146. "apple", set())
  147. apple_set.add(self.u_banana)
  148. apple_set.add(self.u_clementine)
  149. yield self.handlers.presence_handler.set_state(self.u_apple,
  150. self.u_apple, {"presence": ONLINE}
  151. )
  152. yield self.handlers.presence_handler.set_state(self.u_banana,
  153. self.u_banana, {"presence": ONLINE}
  154. )
  155. presence = yield self.handlers.presence_handler.get_presence_list(
  156. observer_user=self.u_apple, accepted=True)
  157. self.assertEquals([
  158. {"observed_user": self.u_banana,
  159. "presence": ONLINE,
  160. "last_active_ago": 0,
  161. "displayname": "Frank",
  162. "avatar_url": "http://foo",
  163. "accepted": True},
  164. {"observed_user": self.u_clementine,
  165. "presence": OFFLINE,
  166. "accepted": True}
  167. ], presence)
  168. self.mock_update_client.assert_has_calls([
  169. call(
  170. users_to_push={self.u_apple, self.u_banana, self.u_clementine},
  171. room_ids=[]
  172. ),
  173. ], any_order=True)
  174. self.mock_update_client.reset_mock()
  175. self.datastore.set_profile_displayname.return_value = defer.succeed(
  176. None)
  177. yield self.handlers.profile_handler.set_displayname(self.u_apple,
  178. self.u_apple, "I am an Apple")
  179. self.mock_update_client.assert_has_calls([
  180. call(
  181. users_to_push={self.u_apple, self.u_banana, self.u_clementine},
  182. room_ids=[],
  183. ),
  184. ], any_order=True)
  185. @defer.inlineCallbacks
  186. def test_push_remote(self):
  187. self.presence_list = [
  188. {"observed_user_id": "@potato:remote", "accepted": True},
  189. ]
  190. self.datastore.set_presence_state.return_value = defer.succeed(
  191. {"state": ONLINE}
  192. )
  193. # TODO(paul): Gut-wrenching
  194. from synapse.handlers.presence import UserPresenceCache
  195. self.handlers.presence_handler._user_cachemap[self.u_apple] = (
  196. UserPresenceCache()
  197. )
  198. self.handlers.presence_handler._user_cachemap[self.u_apple].update(
  199. {"presence": OFFLINE}, serial=0
  200. )
  201. apple_set = self.handlers.presence_handler._remote_sendmap.setdefault(
  202. "apple", set())
  203. apple_set.add(self.u_potato.domain)
  204. yield self.handlers.presence_handler.set_state(self.u_apple,
  205. self.u_apple, {"presence": ONLINE}
  206. )
  207. self.replication.send_edu.assert_called_with(
  208. destination="remote",
  209. edu_type="m.presence",
  210. content={
  211. "push": [
  212. {"user_id": "@apple:test",
  213. "presence": "online",
  214. "last_active_ago": 0,
  215. "displayname": "Frank",
  216. "avatar_url": "http://foo"},
  217. ],
  218. },
  219. )
  220. @defer.inlineCallbacks
  221. def test_recv_remote(self):
  222. self.presence_list = [
  223. {"observed_user_id": "@banana:test"},
  224. {"observed_user_id": "@clementine:test"},
  225. ]
  226. # TODO(paul): Gut-wrenching
  227. potato_set = self.handlers.presence_handler._remote_recvmap.setdefault(
  228. self.u_potato, set()
  229. )
  230. potato_set.add(self.u_apple)
  231. yield self.replication.received_edu(
  232. "remote", "m.presence", {
  233. "push": [
  234. {"user_id": "@potato:remote",
  235. "presence": "online",
  236. "displayname": "Frank",
  237. "avatar_url": "http://foo"},
  238. ],
  239. }
  240. )
  241. self.mock_update_client.assert_called_with(
  242. users_to_push=set([self.u_apple]),
  243. room_ids=[],
  244. )
  245. state = yield self.handlers.presence_handler.get_state(self.u_potato,
  246. self.u_apple)
  247. self.assertEquals(
  248. {"presence": ONLINE,
  249. "displayname": "Frank",
  250. "avatar_url": "http://foo"},
  251. state)