# -*- coding: utf-8 -*- # Copyright 2014 matrix.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """This file contains tests of the "presence-like" data that is shared between presence and profiles; namely, the displayname and avatar_url.""" from twisted.trial import unittest from twisted.internet import defer from mock import Mock, call, ANY import logging from ..utils import MockClock from synapse.server import HomeServer from synapse.api.constants import PresenceState from synapse.handlers.presence import PresenceHandler from synapse.handlers.profile import ProfileHandler OFFLINE = PresenceState.OFFLINE UNAVAILABLE = PresenceState.UNAVAILABLE ONLINE = PresenceState.ONLINE logging.getLogger().addHandler(logging.NullHandler()) class MockReplication(object): def __init__(self): self.edu_handlers = {} def register_edu_handler(self, edu_type, handler): self.edu_handlers[edu_type] = handler def register_query_handler(self, query_type, handler): pass def received_edu(self, origin, edu_type, content): self.edu_handlers[edu_type](origin, content) class PresenceAndProfileHandlers(object): def __init__(self, hs): self.presence_handler = PresenceHandler(hs) self.profile_handler = ProfileHandler(hs) class PresenceProfilelikeDataTestCase(unittest.TestCase): def setUp(self): hs = HomeServer("test", clock=MockClock(), db_pool=None, datastore=Mock(spec=[ "set_presence_state", "is_presence_visible", "set_profile_displayname", ]), handlers=None, resource_for_federation=Mock(), http_client=None, replication_layer=MockReplication(), ) hs.handlers = PresenceAndProfileHandlers(hs) self.datastore = hs.get_datastore() self.replication = hs.get_replication_layer() self.replication.send_edu = Mock() def send_edu(*args, **kwargs): # print "send_edu: %s, %s" % (args, kwargs) return defer.succeed((200, "OK")) self.replication.send_edu.side_effect = send_edu def get_profile_displayname(user_localpart): return defer.succeed("Frank") self.datastore.get_profile_displayname = get_profile_displayname def is_presence_visible(*args, **kwargs): return defer.succeed(False) self.datastore.is_presence_visible = is_presence_visible def get_profile_avatar_url(user_localpart): return defer.succeed("http://foo") self.datastore.get_profile_avatar_url = get_profile_avatar_url self.presence_list = [ {"observed_user_id": "@banana:test"}, {"observed_user_id": "@clementine:test"}, ] def get_presence_list(user_localpart, accepted=None): return defer.succeed(self.presence_list) self.datastore.get_presence_list = get_presence_list def user_rooms_intersect(userlist): return defer.succeed(False) self.datastore.user_rooms_intersect = user_rooms_intersect self.handlers = hs.get_handlers() self.mock_update_client = Mock() def update(*args, **kwargs): # print "mock_update_client: %s, %s" %(args, kwargs) return defer.succeed(None) self.mock_update_client.side_effect = update self.handlers.presence_handler.push_update_to_clients = ( self.mock_update_client) hs.handlers.room_member_handler = Mock(spec=[ "get_rooms_for_user", ]) hs.handlers.room_member_handler.get_rooms_for_user = ( lambda u: defer.succeed([])) # Some local users to test with self.u_apple = hs.parse_userid("@apple:test") self.u_banana = hs.parse_userid("@banana:test") self.u_clementine = hs.parse_userid("@clementine:test") # Remote user self.u_potato = hs.parse_userid("@potato:remote") @defer.inlineCallbacks def test_set_my_state(self): self.presence_list = [ {"observed_user_id": "@banana:test"}, {"observed_user_id": "@clementine:test"}, ] mocked_set = self.datastore.set_presence_state mocked_set.return_value = defer.succeed({"presence": OFFLINE}) yield self.handlers.presence_handler.set_state( target_user=self.u_apple, auth_user=self.u_apple, state={"presence": UNAVAILABLE, "status_msg": "Away"}) mocked_set.assert_called_with("apple", {"presence": UNAVAILABLE, "status_msg": "Away"} ) @defer.inlineCallbacks def test_push_local(self): self.presence_list = [ {"observed_user_id": "@banana:test"}, {"observed_user_id": "@clementine:test"}, ] self.datastore.set_presence_state.return_value = defer.succeed( {"presence": ONLINE} ) # TODO(paul): Gut-wrenching from synapse.handlers.presence import UserPresenceCache self.handlers.presence_handler._user_cachemap[self.u_apple] = ( UserPresenceCache() ) self.handlers.presence_handler._user_cachemap[self.u_apple].update( {"presence": OFFLINE}, serial=0 ) apple_set = self.handlers.presence_handler._local_pushmap.setdefault( "apple", set()) apple_set.add(self.u_banana) apple_set.add(self.u_clementine) yield self.handlers.presence_handler.set_state(self.u_apple, self.u_apple, {"presence": ONLINE} ) yield self.handlers.presence_handler.set_state(self.u_banana, self.u_banana, {"presence": ONLINE} ) presence = yield self.handlers.presence_handler.get_presence_list( observer_user=self.u_apple, accepted=True) self.assertEquals([ {"observed_user": self.u_banana, "presence": ONLINE, "last_active_ago": 0, "displayname": "Frank", "avatar_url": "http://foo"}, {"observed_user": self.u_clementine, "presence": OFFLINE} ], presence) self.mock_update_client.assert_has_calls([ call(users_to_push=set([self.u_apple, self.u_banana, self.u_clementine]), room_ids=[], observed_user=self.u_apple, statuscache=ANY), # self-reflection ], any_order=True) statuscache = self.mock_update_client.call_args[1]["statuscache"] self.assertEquals({ "presence": ONLINE, "last_active": 1000000, # MockClock "displayname": "Frank", "avatar_url": "http://foo", }, statuscache.state) self.mock_update_client.reset_mock() self.datastore.set_profile_displayname.return_value = defer.succeed( None) yield self.handlers.profile_handler.set_displayname(self.u_apple, self.u_apple, "I am an Apple") self.mock_update_client.assert_has_calls([ call(users_to_push=set([self.u_apple, self.u_banana, self.u_clementine]), room_ids=[], observed_user=self.u_apple, statuscache=ANY), # self-reflection ], any_order=True) statuscache = self.mock_update_client.call_args[1]["statuscache"] self.assertEquals({ "presence": ONLINE, "last_active": 1000000, # MockClock "displayname": "I am an Apple", "avatar_url": "http://foo", }, statuscache.state) @defer.inlineCallbacks def test_push_remote(self): self.presence_list = [ {"observed_user_id": "@potato:remote"}, ] self.datastore.set_presence_state.return_value = defer.succeed( {"presence": ONLINE} ) # TODO(paul): Gut-wrenching from synapse.handlers.presence import UserPresenceCache self.handlers.presence_handler._user_cachemap[self.u_apple] = ( UserPresenceCache() ) self.handlers.presence_handler._user_cachemap[self.u_apple].update( {"presence": OFFLINE}, serial=0 ) apple_set = self.handlers.presence_handler._remote_sendmap.setdefault( "apple", set()) apple_set.add(self.u_potato.domain) yield self.handlers.presence_handler.set_state(self.u_apple, self.u_apple, {"presence": ONLINE} ) self.replication.send_edu.assert_called_with( destination="remote", edu_type="m.presence", content={ "push": [ {"user_id": "@apple:test", "presence": "online", "last_active_ago": 0, "displayname": "Frank", "avatar_url": "http://foo"}, ], }, ) @defer.inlineCallbacks def test_recv_remote(self): self.presence_list = [ {"observed_user_id": "@banana:test"}, {"observed_user_id": "@clementine:test"}, ] # TODO(paul): Gut-wrenching potato_set = self.handlers.presence_handler._remote_recvmap.setdefault( self.u_potato, set() ) potato_set.add(self.u_apple) yield self.replication.received_edu( "remote", "m.presence", { "push": [ {"user_id": "@potato:remote", "presence": "online", "displayname": "Frank", "avatar_url": "http://foo"}, ], } ) self.mock_update_client.assert_called_with( users_to_push=set([self.u_apple]), room_ids=[], observed_user=self.u_potato, statuscache=ANY) statuscache = self.mock_update_client.call_args[1]["statuscache"] self.assertEquals({"presence": ONLINE, "displayname": "Frank", "avatar_url": "http://foo"}, statuscache.state) state = yield self.handlers.presence_handler.get_state(self.u_potato, self.u_apple) self.assertEquals( {"presence": ONLINE, "displayname": "Frank", "avatar_url": "http://foo"}, state)