test_presencelike.py 11 KB

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