From 4f475c7697722e946e39e42f38f3dd03a95d8765 Mon Sep 17 00:00:00 2001 From: "matrix.org" Date: Tue, 12 Aug 2014 15:10:52 +0100 Subject: Reference Matrix Home Server --- tests/handlers/__init__.py | 0 tests/handlers/test_federation.py | 107 +++++ tests/handlers/test_presence.py | 884 ++++++++++++++++++++++++++++++++++++ tests/handlers/test_presencelike.py | 250 ++++++++++ tests/handlers/test_profile.py | 112 +++++ tests/handlers/test_room.py | 363 +++++++++++++++ 6 files changed, 1716 insertions(+) create mode 100644 tests/handlers/__init__.py create mode 100644 tests/handlers/test_federation.py create mode 100644 tests/handlers/test_presence.py create mode 100644 tests/handlers/test_presencelike.py create mode 100644 tests/handlers/test_profile.py create mode 100644 tests/handlers/test_room.py (limited to 'tests/handlers') diff --git a/tests/handlers/__init__.py b/tests/handlers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/handlers/test_federation.py b/tests/handlers/test_federation.py new file mode 100644 index 0000000000..880cfb47b8 --- /dev/null +++ b/tests/handlers/test_federation.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- + +from twisted.internet import defer +from twisted.trial import unittest + +from synapse.api.events.room import ( + InviteJoinEvent, MessageEvent, RoomMemberEvent +) +from synapse.api.constants import Membership +from synapse.handlers.federation import FederationHandler +from synapse.server import HomeServer + +from mock import NonCallableMock + +import logging + +logging.getLogger().addHandler(logging.NullHandler()) + + +class FederationTestCase(unittest.TestCase): + + def setUp(self): + self.hostname = "test" + hs = HomeServer( + self.hostname, + db_pool=None, + datastore=NonCallableMock(spec_set=[ + "persist_event", + "store_room", + ]), + http_server=NonCallableMock(), + http_client=NonCallableMock(spec_set=[]), + notifier=NonCallableMock(spec_set=["on_new_room_event"]), + handlers=NonCallableMock(spec_set=[ + "room_member_handler", + "federation_handler", + ]), + ) + + self.datastore = hs.get_datastore() + self.handlers = hs.get_handlers() + self.notifier = hs.get_notifier() + self.hs = hs + + self.handlers.federation_handler = FederationHandler(self.hs) + + @defer.inlineCallbacks + def test_msg(self): + event = self.hs.get_event_factory().create_event( + etype=MessageEvent.TYPE, + msg_id="bob", + room_id="foo", + content={"msgtype": u"fooo"}, + ) + + store_id = "ASD" + self.datastore.persist_event.return_value = defer.succeed(store_id) + + yield self.handlers.federation_handler.on_receive(event, False) + + self.datastore.persist_event.assert_called_once_with(event) + self.notifier.on_new_room_event.assert_called_once_with( + event, store_id) + + @defer.inlineCallbacks + def test_invite_join_target_this(self): + room_id = "foo" + user_id = "@bob:red" + + event = self.hs.get_event_factory().create_event( + etype=InviteJoinEvent.TYPE, + user_id=user_id, + target_host=self.hostname, + room_id=room_id, + content={}, + ) + + yield self.handlers.federation_handler.on_receive(event, False) + + mem_handler = self.handlers.room_member_handler + self.assertEquals(1, mem_handler.change_membership.call_count) + self.assertEquals(True, mem_handler.change_membership.call_args[0][1]) + + new_event = mem_handler.change_membership.call_args[0][0] + self.assertEquals(RoomMemberEvent.TYPE, new_event.type) + self.assertEquals(room_id, new_event.room_id) + self.assertEquals(user_id, new_event.target_user_id) + self.assertEquals(user_id, new_event.state_key) + self.assertEquals(Membership.JOIN, new_event.membership) + + @defer.inlineCallbacks + def test_invite_join_target_other(self): + room_id = "foo" + user_id = "@bob:red" + + event = self.hs.get_event_factory().create_event( + etype=InviteJoinEvent.TYPE, + user_id=user_id, + target_user_id="@red:not%s" % self.hostname, + room_id=room_id, + content={}, + ) + + yield self.handlers.federation_handler.on_receive(event, False) + + mem_handler = self.handlers.room_member_handler + self.assertEquals(0, mem_handler.change_membership.call_count) diff --git a/tests/handlers/test_presence.py b/tests/handlers/test_presence.py new file mode 100644 index 0000000000..e814357520 --- /dev/null +++ b/tests/handlers/test_presence.py @@ -0,0 +1,884 @@ +# -*- coding: utf-8 -*- + +from twisted.trial import unittest +from twisted.internet import defer + +from mock import Mock, call, ANY +import logging + +from synapse.server import HomeServer +from synapse.api.constants import PresenceState +from synapse.api.errors import SynapseError +from synapse.handlers.presence import PresenceHandler, UserPresenceCache + + +OFFLINE = PresenceState.OFFLINE +BUSY = PresenceState.BUSY +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 received_edu(self, origin, edu_type, content): + self.edu_handlers[edu_type](origin, content) + + +class JustPresenceHandlers(object): + def __init__(self, hs): + self.presence_handler = PresenceHandler(hs) + + +class PresenceStateTestCase(unittest.TestCase): + """ Tests presence management. """ + + def setUp(self): + hs = HomeServer("test", + db_pool=None, + datastore=Mock(spec=[ + "get_presence_state", + "set_presence_state", + "add_presence_list_pending", + "set_presence_list_accepted", + ]), + handlers=None, + http_server=Mock(), + http_client=None, + ) + hs.handlers = JustPresenceHandlers(hs) + + self.datastore = hs.get_datastore() + + def is_presence_visible(observed_localpart, observer_userid): + allow = (observed_localpart == "apple" and + observer_userid == "@banana:test" + ) + return defer.succeed(allow) + self.datastore.is_presence_visible = is_presence_visible + + # 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") + + self.handler = hs.get_handlers().presence_handler + + hs.handlers.room_member_handler = Mock(spec=[ + "get_rooms_for_user", + ]) + hs.handlers.room_member_handler.get_rooms_for_user = ( + lambda u: defer.succeed([])) + + self.mock_start = Mock() + self.mock_stop = Mock() + + self.handler.start_polling_presence = self.mock_start + self.handler.stop_polling_presence = self.mock_stop + + @defer.inlineCallbacks + def test_get_my_state(self): + mocked_get = self.datastore.get_presence_state + mocked_get.return_value = defer.succeed( + {"state": ONLINE, "status_msg": "Online"} + ) + + state = yield self.handler.get_state( + target_user=self.u_apple, auth_user=self.u_apple + ) + + self.assertEquals({"state": ONLINE, "status_msg": "Online"}, + state + ) + mocked_get.assert_called_with("apple") + + @defer.inlineCallbacks + def test_get_allowed_state(self): + mocked_get = self.datastore.get_presence_state + mocked_get.return_value = defer.succeed( + {"state": ONLINE, "status_msg": "Online"} + ) + + state = yield self.handler.get_state( + target_user=self.u_apple, auth_user=self.u_banana + ) + + self.assertEquals({"state": ONLINE, "status_msg": "Online"}, + state + ) + mocked_get.assert_called_with("apple") + + @defer.inlineCallbacks + def test_get_disallowed_state(self): + mocked_get = self.datastore.get_presence_state + mocked_get.return_value = defer.succeed( + {"state": ONLINE, "status_msg": "Online"} + ) + + yield self.assertFailure( + self.handler.get_state( + target_user=self.u_apple, auth_user=self.u_clementine + ), + SynapseError + ) + + @defer.inlineCallbacks + def test_set_my_state(self): + mocked_set = self.datastore.set_presence_state + mocked_set.return_value = defer.succeed({"state": OFFLINE}) + + yield self.handler.set_state( + target_user=self.u_apple, auth_user=self.u_apple, + state={"state": BUSY, "status_msg": "Away"}) + + mocked_set.assert_called_with("apple", + {"state": 1, "status_msg": "Away"}) + self.mock_start.assert_called_with(self.u_apple, + state={"state": 1, "status_msg": "Away"}) + + yield self.handler.set_state( + target_user=self.u_apple, auth_user=self.u_apple, + state={"state": OFFLINE}) + + self.mock_stop.assert_called_with(self.u_apple) + + +class PresenceInvitesTestCase(unittest.TestCase): + """ Tests presence management. """ + + def setUp(self): + self.replication = MockReplication() + self.replication.send_edu = Mock() + + hs = HomeServer("test", + db_pool=None, + datastore=Mock(spec=[ + "has_presence_state", + "allow_presence_visible", + "add_presence_list_pending", + "set_presence_list_accepted", + "get_presence_list", + "del_presence_list", + ]), + handlers=None, + http_server=Mock(), + http_client=None, + replication_layer=self.replication + ) + hs.handlers = JustPresenceHandlers(hs) + + self.datastore = hs.get_datastore() + + def has_presence_state(user_localpart): + return defer.succeed( + user_localpart in ("apple", "banana")) + self.datastore.has_presence_state = has_presence_state + + # Some local users to test with + self.u_apple = hs.parse_userid("@apple:test") + self.u_banana = hs.parse_userid("@banana:test") + # ID of a local user that does not exist + self.u_durian = hs.parse_userid("@durian:test") + + # A remote user + self.u_cabbage = hs.parse_userid("@cabbage:elsewhere") + + self.handler = hs.get_handlers().presence_handler + + self.mock_start = Mock() + self.mock_stop = Mock() + + self.handler.start_polling_presence = self.mock_start + self.handler.stop_polling_presence = self.mock_stop + + @defer.inlineCallbacks + def test_invite_local(self): + # TODO(paul): This test will likely break if/when real auth permissions + # are added; for now the HS will always accept any invite + + yield self.handler.send_invite( + observer_user=self.u_apple, observed_user=self.u_banana) + + self.datastore.add_presence_list_pending.assert_called_with( + "apple", "@banana:test") + self.datastore.allow_presence_visible.assert_called_with( + "banana", "@apple:test") + self.datastore.set_presence_list_accepted.assert_called_with( + "apple", "@banana:test") + + self.mock_start.assert_called_with( + self.u_apple, target_user=self.u_banana) + + @defer.inlineCallbacks + def test_invite_local_nonexistant(self): + yield self.handler.send_invite( + observer_user=self.u_apple, observed_user=self.u_durian) + + self.datastore.add_presence_list_pending.assert_called_with( + "apple", "@durian:test") + self.datastore.del_presence_list.assert_called_with( + "apple", "@durian:test") + + @defer.inlineCallbacks + def test_invite_remote(self): + self.replication.send_edu.return_value = defer.succeed((200, "OK")) + + yield self.handler.send_invite( + observer_user=self.u_apple, observed_user=self.u_cabbage) + + self.datastore.add_presence_list_pending.assert_called_with( + "apple", "@cabbage:elsewhere") + + self.replication.send_edu.assert_called_with( + destination="elsewhere", + edu_type="m.presence_invite", + content={ + "observer_user": "@apple:test", + "observed_user": "@cabbage:elsewhere", + } + ) + + @defer.inlineCallbacks + def test_accept_remote(self): + # TODO(paul): This test will likely break if/when real auth permissions + # are added; for now the HS will always accept any invite + self.replication.send_edu.return_value = defer.succeed((200, "OK")) + + yield self.replication.received_edu( + "elsewhere", "m.presence_invite", { + "observer_user": "@cabbage:elsewhere", + "observed_user": "@apple:test", + } + ) + + self.datastore.allow_presence_visible.assert_called_with( + "apple", "@cabbage:elsewhere") + + self.replication.send_edu.assert_called_with( + destination="elsewhere", + edu_type="m.presence_accept", + content={ + "observer_user": "@cabbage:elsewhere", + "observed_user": "@apple:test", + } + ) + + @defer.inlineCallbacks + def test_invited_remote_nonexistant(self): + self.replication.send_edu.return_value = defer.succeed((200, "OK")) + + yield self.replication.received_edu( + "elsewhere", "m.presence_invite", { + "observer_user": "@cabbage:elsewhere", + "observed_user": "@durian:test", + } + ) + + self.replication.send_edu.assert_called_with( + destination="elsewhere", + edu_type="m.presence_deny", + content={ + "observer_user": "@cabbage:elsewhere", + "observed_user": "@durian:test", + } + ) + + @defer.inlineCallbacks + def test_accepted_remote(self): + yield self.replication.received_edu( + "elsewhere", "m.presence_accept", { + "observer_user": "@apple:test", + "observed_user": "@cabbage:elsewhere", + } + ) + + self.datastore.set_presence_list_accepted.assert_called_with( + "apple", "@cabbage:elsewhere") + + self.mock_start.assert_called_with( + self.u_apple, target_user=self.u_cabbage) + + @defer.inlineCallbacks + def test_denied_remote(self): + yield self.replication.received_edu( + "elsewhere", "m.presence_deny", { + "observer_user": "@apple:test", + "observed_user": "@eggplant:elsewhere", + } + ) + + self.datastore.del_presence_list.assert_called_with( + "apple", "@eggplant:elsewhere") + + @defer.inlineCallbacks + def test_drop_local(self): + yield self.handler.drop( + observer_user=self.u_apple, observed_user=self.u_banana) + + self.datastore.del_presence_list.assert_called_with( + "apple", "@banana:test") + + self.mock_stop.assert_called_with( + self.u_apple, target_user=self.u_banana) + + @defer.inlineCallbacks + def test_get_presence_list(self): + self.datastore.get_presence_list.return_value = defer.succeed( + [{"observed_user_id": "@banana:test"}] + ) + + presence = yield self.handler.get_presence_list( + observer_user=self.u_apple) + + self.assertEquals([{"observed_user": self.u_banana, + "state": OFFLINE}], presence) + + self.datastore.get_presence_list.assert_called_with("apple", + accepted=None) + + + self.datastore.get_presence_list.return_value = defer.succeed( + [{"observed_user_id": "@banana:test"}] + ) + + presence = yield self.handler.get_presence_list( + observer_user=self.u_apple, accepted=True) + + self.assertEquals([{"observed_user": self.u_banana, + "state": OFFLINE}], presence) + + self.datastore.get_presence_list.assert_called_with("apple", + accepted=True) + + +class PresencePushTestCase(unittest.TestCase): + """ Tests steady-state presence status updates. + + They assert that presence state update messages are pushed around the place + when users change state, presuming that the watches are all established. + + These tests are MASSIVELY fragile currently as they poke internals of the + presence handler; namely the _local_pushmap and _remote_recvmap. + BE WARNED... + """ + def setUp(self): + self.replication = MockReplication() + self.replication.send_edu = Mock() + self.replication.send_edu.return_value = defer.succeed((200, "OK")) + + hs = HomeServer("test", + db_pool=None, + datastore=Mock(spec=[ + "set_presence_state", + ]), + handlers=None, + http_server=Mock(), + http_client=None, + replication_layer=self.replication, + ) + hs.handlers = JustPresenceHandlers(hs) + + self.mock_update_client = Mock() + self.mock_update_client.return_value = defer.succeed(None) + + self.datastore = hs.get_datastore() + self.handler = hs.get_handlers().presence_handler + self.handler.push_update_to_clients = self.mock_update_client + + # Mock the RoomMemberHandler + hs.handlers.room_member_handler = Mock(spec=[ + "get_rooms_for_user", + "get_room_members", + ]) + self.room_member_handler = hs.handlers.room_member_handler + + self.room_members = [] + + def get_rooms_for_user(user): + if user in self.room_members: + return defer.succeed(["a-room"]) + else: + return defer.succeed([]) + self.room_member_handler.get_rooms_for_user = get_rooms_for_user + + def get_room_members(room_id): + if room_id == "a-room": + return defer.succeed(self.room_members) + else: + return defer.succeed([]) + self.room_member_handler.get_room_members = get_room_members + + @defer.inlineCallbacks + def fetch_room_distributions_into(room_id, localusers=None, + remotedomains=None, ignore_user=None): + + members = yield get_room_members(room_id) + for member in members: + if ignore_user is not None and member == ignore_user: + continue + + if member.is_mine: + if localusers is not None: + localusers.add(member) + else: + if remotedomains is not None: + remotedomains.add(member.domain) + self.room_member_handler.fetch_room_distributions_into = ( + fetch_room_distributions_into) + + def get_presence_list(user_localpart, accepted=None): + if user_localpart == "apple": + return defer.succeed([ + {"observed_user_id": "@banana:test"}, + {"observed_user_id": "@clementine:test"}, + ]) + else: + return defer.succeed([]) + self.datastore.get_presence_list = get_presence_list + + def is_presence_visible(observer_userid, observed_localpart): + if (observed_localpart == "clementine" and + observer_userid == "@banana:test"): + return False + return False + self.datastore.is_presence_visible = is_presence_visible + + self.distributor = hs.get_distributor() + self.distributor.declare("user_joined_room") + + # 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") + self.u_elderberry = hs.parse_userid("@elderberry:test") + + # Remote user + self.u_onion = hs.parse_userid("@onion:farm") + self.u_potato = hs.parse_userid("@potato:remote") + + @defer.inlineCallbacks + def test_push_local(self): + self.room_members = [self.u_apple, self.u_elderberry] + + self.datastore.set_presence_state.return_value = defer.succeed( + {"state": ONLINE}) + + # TODO(paul): Gut-wrenching + self.handler._user_cachemap[self.u_apple] = UserPresenceCache() + apple_set = self.handler._local_pushmap.setdefault("apple", set()) + apple_set.add(self.u_banana) + apple_set.add(self.u_clementine) + + yield self.handler.set_state(self.u_apple, self.u_apple, + {"state": ONLINE}) + + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_apple, + observed_user=self.u_apple, + statuscache=ANY), # self-reflection + call(observer_user=self.u_banana, + observed_user=self.u_apple, + statuscache=ANY), + call(observer_user=self.u_clementine, + observed_user=self.u_apple, + statuscache=ANY), + call(observer_user=self.u_elderberry, + observed_user=self.u_apple, + statuscache=ANY), + ], any_order=True) + self.mock_update_client.reset_mock() + + presence = yield self.handler.get_presence_list( + observer_user=self.u_apple, accepted=True) + + self.assertEquals([ + {"observed_user": self.u_banana, "state": OFFLINE}, + {"observed_user": self.u_clementine, "state": OFFLINE}], + presence) + + yield self.handler.set_state(self.u_banana, self.u_banana, + {"state": ONLINE}) + + presence = yield self.handler.get_presence_list( + observer_user=self.u_apple, accepted=True) + + self.assertEquals([ + {"observed_user": self.u_banana, "state": ONLINE}, + {"observed_user": self.u_clementine, "state": OFFLINE}], + presence) + + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_banana, + observed_user=self.u_banana, + statuscache=ANY), # self-reflection + ]) # and no others... + + @defer.inlineCallbacks + def test_push_remote(self): + self.room_members = [self.u_apple, self.u_onion] + + self.datastore.set_presence_state.return_value = defer.succeed( + {"state": ONLINE}) + + # TODO(paul): Gut-wrenching + self.handler._user_cachemap[self.u_apple] = UserPresenceCache() + apple_set = self.handler._remote_sendmap.setdefault("apple", set()) + apple_set.add(self.u_potato.domain) + + yield self.handler.set_state(self.u_apple, self.u_apple, + {"state": ONLINE}) + + self.replication.send_edu.assert_has_calls([ + call( + destination="remote", + edu_type="m.presence", + content={ + "push": [ + {"user_id": "@apple:test", + "state": 2}, + ], + }), + call( + destination="farm", + edu_type="m.presence", + content={ + "push": [ + {"user_id": "@apple:test", + "state": 2}, + ], + }) + ], any_order=True) + + @defer.inlineCallbacks + def test_recv_remote(self): + # TODO(paul): Gut-wrenching + potato_set = self.handler._remote_recvmap.setdefault(self.u_potato, + set()) + potato_set.add(self.u_apple) + + self.room_members = [self.u_banana, self.u_potato] + + yield self.replication.received_edu( + "remote", "m.presence", { + "push": [ + {"user_id": "@potato:remote", + "state": 2}, + ], + } + ) + + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_apple, + observed_user=self.u_potato, + statuscache=ANY), + call(observer_user=self.u_banana, + observed_user=self.u_potato, + statuscache=ANY), + ], any_order=True) + + state = yield self.handler.get_state(self.u_potato, self.u_apple) + + self.assertEquals({"state": ONLINE}, state) + + @defer.inlineCallbacks + def test_join_room_local(self): + self.room_members = [self.u_apple, self.u_banana] + + yield self.distributor.fire("user_joined_room", self.u_elderberry, + "a-room" + ) + + self.mock_update_client.assert_has_calls([ + # Apple and Elderberry see each other + call(observer_user=self.u_apple, + observed_user=self.u_elderberry, + statuscache=ANY), + call(observer_user=self.u_elderberry, + observed_user=self.u_apple, + statuscache=ANY), + # Banana and Elderberry see each other + call(observer_user=self.u_banana, + observed_user=self.u_elderberry, + statuscache=ANY), + call(observer_user=self.u_elderberry, + observed_user=self.u_banana, + statuscache=ANY), + ], any_order=True) + + @defer.inlineCallbacks + def test_join_room_remote(self): + ## Sending local user state to a newly-joined remote user + + # TODO(paul): Gut-wrenching + self.handler._user_cachemap[self.u_apple] = UserPresenceCache() + self.handler._user_cachemap[self.u_apple].update( + {"state": PresenceState.ONLINE}, self.u_apple) + self.room_members = [self.u_apple, self.u_banana] + + yield self.distributor.fire("user_joined_room", self.u_potato, + "a-room" + ) + + self.replication.send_edu.assert_has_calls([ + call( + destination="remote", + edu_type="m.presence", + content={ + "push": [ + {"user_id": "@apple:test", + "state": 2}, + ], + }), + call( + destination="remote", + edu_type="m.presence", + content={ + "push": [ + {"user_id": "@banana:test", + "state": 0}, + ], + }), + ], any_order=True) + + self.replication.send_edu.reset_mock() + + ## Sending newly-joined local user state to remote users + + self.handler._user_cachemap[self.u_clementine] = UserPresenceCache() + self.handler._user_cachemap[self.u_clementine].update( + {"state": PresenceState.ONLINE}, self.u_clementine) + self.room_members.append(self.u_potato) + + yield self.distributor.fire("user_joined_room", self.u_clementine, + "a-room" + ) + + self.replication.send_edu.assert_has_calls( + call( + destination="remote", + edu_type="m.presence", + content={ + "push": [ + {"user_id": "@clementine:test", + "state": 2}, + ], + }), + ) + + +class PresencePollingTestCase(unittest.TestCase): + """ Tests presence status polling. """ + + # For this test, we have three local users; apple is watching and is + # watched by the other two, but the others don't watch each other. + # Additionally clementine is watching a remote user. + PRESENCE_LIST = { + 'apple': [ "@banana:test", "@clementine:test" ], + 'banana': [ "@apple:test" ], + 'clementine': [ "@apple:test", "@potato:remote" ], + } + + + def setUp(self): + self.replication = MockReplication() + self.replication.send_edu = Mock() + + hs = HomeServer("test", + db_pool=None, + datastore=Mock(spec=[]), + handlers=None, + http_server=Mock(), + http_client=None, + replication_layer=self.replication, + ) + hs.handlers = JustPresenceHandlers(hs) + + self.datastore = hs.get_datastore() + + self.mock_update_client = Mock() + self.mock_update_client.return_value = defer.succeed(None) + + self.handler = hs.get_handlers().presence_handler + self.handler.push_update_to_clients = self.mock_update_client + + hs.handlers.room_member_handler = Mock(spec=[ + "get_rooms_for_user", + ]) + # For this test no users are ever in rooms + def get_rooms_for_user(user): + return defer.succeed([]) + hs.handlers.room_member_handler.get_rooms_for_user = get_rooms_for_user + + # Mocked database state + # Local users always start offline + self.current_user_state = { + "apple": OFFLINE, + "banana": OFFLINE, + "clementine": OFFLINE, + } + + def get_presence_state(user_localpart): + return defer.succeed( + {"state": self.current_user_state[user_localpart], + "status_msg": None} + ) + self.datastore.get_presence_state = get_presence_state + + def set_presence_state(user_localpart, new_state): + was = self.current_user_state[user_localpart] + self.current_user_state[user_localpart] = new_state["state"] + return defer.succeed({"state": was}) + self.datastore.set_presence_state = set_presence_state + + def get_presence_list(user_localpart, accepted): + return defer.succeed([ + {"observed_user_id": u} for u in + self.PRESENCE_LIST[user_localpart]]) + self.datastore.get_presence_list = get_presence_list + + def is_presence_visible(observed_localpart, observer_userid): + return True + self.datastore.is_presence_visible = is_presence_visible + + # Local users + 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 users + self.u_potato = hs.parse_userid("@potato:remote") + + @defer.inlineCallbacks + def test_push_local(self): + # apple goes online + yield self.handler.set_state( + target_user=self.u_apple, auth_user=self.u_apple, + state={"state": ONLINE}) + + # apple should see both banana and clementine currently offline + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_apple, + observed_user=self.u_banana, + statuscache=ANY), + call(observer_user=self.u_apple, + observed_user=self.u_clementine, + statuscache=ANY), + ], any_order=True) + + # Gut-wrenching tests + self.assertTrue("banana" in self.handler._local_pushmap) + self.assertTrue(self.u_apple in self.handler._local_pushmap["banana"]) + self.assertTrue("clementine" in self.handler._local_pushmap) + self.assertTrue(self.u_apple in self.handler._local_pushmap["clementine"]) + + self.mock_update_client.reset_mock() + + # banana goes online + yield self.handler.set_state( + target_user=self.u_banana, auth_user=self.u_banana, + state={"state": ONLINE}) + + # apple and banana should now both see each other online + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_apple, + observed_user=self.u_banana, + statuscache=ANY), + call(observer_user=self.u_banana, + observed_user=self.u_apple, + statuscache=ANY), + ], any_order=True) + + self.assertTrue("apple" in self.handler._local_pushmap) + self.assertTrue(self.u_banana in self.handler._local_pushmap["apple"]) + + self.mock_update_client.reset_mock() + + # apple goes offline + yield self.handler.set_state( + target_user=self.u_apple, auth_user=self.u_apple, + state={"state": OFFLINE}) + + # banana should now be told apple is offline + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_banana, + observed_user=self.u_apple, + statuscache=ANY), + ], any_order=True) + + self.assertFalse("banana" in self.handler._local_pushmap) + self.assertFalse("clementine" in self.handler._local_pushmap) + + @defer.inlineCallbacks + def test_remote_poll_send(self): + # clementine goes online + yield self.handler.set_state( + target_user=self.u_clementine, auth_user=self.u_clementine, + state={"state": ONLINE}) + + self.replication.send_edu.assert_called_with( + destination="remote", + edu_type="m.presence", + content={ + "poll": [ "@potato:remote" ], + }, + ) + + # Gut-wrenching tests + self.assertTrue(self.u_potato in self.handler._remote_recvmap) + self.assertTrue(self.u_clementine in + self.handler._remote_recvmap[self.u_potato]) + + self.replication.send_edu.reset_mock() + + # clementine goes offline + yield self.handler.set_state( + target_user=self.u_clementine, auth_user=self.u_clementine, + state={"state": OFFLINE}) + + self.replication.send_edu.assert_called_with( + destination="remote", + edu_type="m.presence", + content={ + "unpoll": [ "@potato:remote" ], + }, + ) + + self.assertFalse(self.u_potato in self.handler._remote_recvmap) + + @defer.inlineCallbacks + def test_remote_poll_receive(self): + yield self.replication.received_edu( + "remote", "m.presence", { + "poll": [ "@banana:test" ], + } + ) + + # Gut-wrenching tests + self.assertTrue(self.u_banana in self.handler._remote_sendmap) + + self.replication.send_edu.assert_called_with( + destination="remote", + edu_type="m.presence", + content={ + "push": [ + {"user_id": "@banana:test", + "state": 0, + "status_msg": None}, + ], + }, + ) + + yield self.replication.received_edu( + "remote", "m.presence", { + "unpoll": [ "@banana:test" ], + } + ) + + # Gut-wrenching tests + self.assertFalse(self.u_banana in self.handler._remote_sendmap) diff --git a/tests/handlers/test_presencelike.py b/tests/handlers/test_presencelike.py new file mode 100644 index 0000000000..c194e4dd72 --- /dev/null +++ b/tests/handlers/test_presencelike.py @@ -0,0 +1,250 @@ +# -*- coding: utf-8 -*- +"""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 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 +BUSY = PresenceState.BUSY +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 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", + db_pool=None, + datastore=Mock(spec=[ + "set_presence_state", + + "set_profile_displayname", + ]), + handlers=None, + http_server=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() + self.replication.send_edu.return_value = defer.succeed((200, "OK")) + + def get_profile_displayname(user_localpart): + return defer.succeed("Frank") + self.datastore.get_profile_displayname = get_profile_displayname + + def get_profile_avatar_url(user_localpart): + return defer.succeed("http://foo") + self.datastore.get_profile_avatar_url = get_profile_avatar_url + + def get_presence_list(user_localpart, accepted=None): + return defer.succeed([ + {"observed_user_id": "@banana:test"}, + {"observed_user_id": "@clementine:test"}, + ]) + self.datastore.get_presence_list = get_presence_list + + self.handlers = hs.get_handlers() + + self.mock_start = Mock() + self.mock_stop = Mock() + + self.mock_update_client = Mock() + self.mock_update_client.return_value = defer.succeed(None) + + self.handlers.presence_handler.start_polling_presence = self.mock_start + self.handlers.presence_handler.stop_polling_presence = self.mock_stop + 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): + mocked_set = self.datastore.set_presence_state + mocked_set.return_value = defer.succeed({"state": OFFLINE}) + + yield self.handlers.presence_handler.set_state( + target_user=self.u_apple, auth_user=self.u_apple, + state={"state": BUSY, "status_msg": "Away"}) + + mocked_set.assert_called_with("apple", + {"state": 1, "status_msg": "Away"}) + self.mock_start.assert_called_with(self.u_apple, + state={"state": 1, "status_msg": "Away", + "displayname": "Frank", + "avatar_url": "http://foo"}) + + @defer.inlineCallbacks + def test_push_local(self): + self.datastore.set_presence_state.return_value = defer.succeed( + {"state": ONLINE}) + + # TODO(paul): Gut-wrenching + from synapse.handlers.presence import UserPresenceCache + self.handlers.presence_handler._user_cachemap[self.u_apple] = ( + UserPresenceCache()) + 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, {"state": ONLINE}) + yield self.handlers.presence_handler.set_state(self.u_banana, + self.u_banana, {"state": ONLINE}) + + presence = yield self.handlers.presence_handler.get_presence_list( + observer_user=self.u_apple, accepted=True) + + self.assertEquals([ + {"observed_user": self.u_banana, "state": ONLINE, + "displayname": "Frank", "avatar_url": "http://foo"}, + {"observed_user": self.u_clementine, "state": OFFLINE}], + presence) + + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_apple, + observed_user=self.u_apple, + statuscache=ANY), # self-reflection + call(observer_user=self.u_banana, + observed_user=self.u_apple, + statuscache=ANY), + ], any_order=True) + + statuscache = self.mock_update_client.call_args[1]["statuscache"] + self.assertEquals({"state": ONLINE, + "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(observer_user=self.u_apple, + observed_user=self.u_apple, + statuscache=ANY), # self-reflection + call(observer_user=self.u_banana, + observed_user=self.u_apple, + statuscache=ANY), + ], any_order=True) + + statuscache = self.mock_update_client.call_args[1]["statuscache"] + self.assertEquals({"state": ONLINE, + "displayname": "I am an Apple", + "avatar_url": "http://foo"}, statuscache.state) + + @defer.inlineCallbacks + def test_push_remote(self): + self.datastore.set_presence_state.return_value = defer.succeed( + {"state": ONLINE}) + + # TODO(paul): Gut-wrenching + from synapse.handlers.presence import UserPresenceCache + self.handlers.presence_handler._user_cachemap[self.u_apple] = ( + UserPresenceCache()) + 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, {"state": ONLINE}) + + self.replication.send_edu.assert_called_with( + destination="remote", + edu_type="m.presence", + content={ + "push": [ + {"user_id": "@apple:test", + "state": 2, + "displayname": "Frank", + "avatar_url": "http://foo"}, + ], + }, + ) + + @defer.inlineCallbacks + def test_recv_remote(self): + # 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", + "state": 2, + "displayname": "Frank", + "avatar_url": "http://foo"}, + ], + } + ) + + self.mock_update_client.assert_called_with( + observer_user=self.u_apple, + observed_user=self.u_potato, + statuscache=ANY) + + statuscache = self.mock_update_client.call_args[1]["statuscache"] + self.assertEquals({"state": 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({"state": ONLINE, + "displayname": "Frank", + "avatar_url": "http://foo"}, + state) diff --git a/tests/handlers/test_profile.py b/tests/handlers/test_profile.py new file mode 100644 index 0000000000..a4408e9fd3 --- /dev/null +++ b/tests/handlers/test_profile.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- + +from twisted.trial import unittest +from twisted.internet import defer + +from mock import Mock +import logging + +from synapse.api.errors import AuthError +from synapse.server import HomeServer +from synapse.handlers.profile import ProfileHandler + + +logging.getLogger().addHandler(logging.NullHandler()) + + +class ProfileHandlers(object): + def __init__(self, hs): + self.profile_handler = ProfileHandler(hs) + + +class ProfileTestCase(unittest.TestCase): + """ Tests profile management. """ + + def setUp(self): + self.mock_client = Mock(spec=[ + "get_json", + ]) + + hs = HomeServer("test", + db_pool=None, + http_client=self.mock_client, + datastore=Mock(spec=[ + "get_profile_displayname", + "set_profile_displayname", + "get_profile_avatar_url", + "set_profile_avatar_url", + ]), + handlers=None, + http_server=Mock(), + ) + hs.handlers = ProfileHandlers(hs) + + self.datastore = hs.get_datastore() + + self.frank = hs.parse_userid("@1234ABCD:test") + self.bob = hs.parse_userid("@4567:test") + self.alice = hs.parse_userid("@alice:remote") + + self.handler = hs.get_handlers().profile_handler + + # TODO(paul): Icky signal declarings.. booo + hs.get_distributor().declare("changed_presencelike_data") + + @defer.inlineCallbacks + def test_get_my_name(self): + mocked_get = self.datastore.get_profile_displayname + mocked_get.return_value = defer.succeed("Frank") + + displayname = yield self.handler.get_displayname(self.frank) + + self.assertEquals("Frank", displayname) + mocked_get.assert_called_with("1234ABCD") + + @defer.inlineCallbacks + def test_set_my_name(self): + mocked_set = self.datastore.set_profile_displayname + mocked_set.return_value = defer.succeed(()) + + yield self.handler.set_displayname(self.frank, self.frank, "Frank Jr.") + + mocked_set.assert_called_with("1234ABCD", "Frank Jr.") + + @defer.inlineCallbacks + def test_set_my_name_noauth(self): + d = self.handler.set_displayname(self.frank, self.bob, "Frank Jr.") + + yield self.assertFailure(d, AuthError) + + @defer.inlineCallbacks + def test_get_other_name(self): + self.mock_client.get_json.return_value = defer.succeed( + {"displayname": "Alice"}) + + displayname = yield self.handler.get_displayname(self.alice) + + self.assertEquals(displayname, "Alice") + self.mock_client.get_json.assert_called_with( + destination="remote", + path="/matrix/client/api/v1/profile/@alice:remote/displayname" + "?local_only=1" + ) + + @defer.inlineCallbacks + def test_get_my_avatar(self): + mocked_get = self.datastore.get_profile_avatar_url + mocked_get.return_value = defer.succeed("http://my.server/me.png") + + avatar_url = yield self.handler.get_avatar_url(self.frank) + + self.assertEquals("http://my.server/me.png", avatar_url) + mocked_get.assert_called_with("1234ABCD") + + @defer.inlineCallbacks + def test_set_my_avatar(self): + mocked_set = self.datastore.set_profile_avatar_url + mocked_set.return_value = defer.succeed(()) + + yield self.handler.set_avatar_url(self.frank, self.frank, + "http://my.server/pic.gif") + + mocked_set.assert_called_with("1234ABCD", "http://my.server/pic.gif") diff --git a/tests/handlers/test_room.py b/tests/handlers/test_room.py new file mode 100644 index 0000000000..26b233bccd --- /dev/null +++ b/tests/handlers/test_room.py @@ -0,0 +1,363 @@ +# -*- coding: utf-8 -*- + +from twisted.internet import defer +from twisted.trial import unittest + +from synapse.api.events.room import ( + InviteJoinEvent, RoomMemberEvent, RoomConfigEvent +) +from synapse.api.constants import Membership +from synapse.handlers.room import RoomMemberHandler, RoomCreationHandler +from synapse.handlers.profile import ProfileHandler +from synapse.server import HomeServer + +from mock import Mock, NonCallableMock + +import logging + +logging.getLogger().addHandler(logging.NullHandler()) + + +class RoomMemberHandlerTestCase(unittest.TestCase): + + def setUp(self): + self.hostname = "red" + hs = HomeServer( + self.hostname, + db_pool=None, + datastore=NonCallableMock(spec_set=[ + "store_room_member", + "get_joined_hosts_for_room", + "get_room_member", + "get_room", + "store_room", + ]), + http_server=NonCallableMock(), + http_client=NonCallableMock(spec_set=[]), + notifier=NonCallableMock(spec_set=["on_new_room_event"]), + handlers=NonCallableMock(spec_set=[ + "room_member_handler", + "profile_handler", + ]), + auth=NonCallableMock(spec_set=["check"]), + federation=NonCallableMock(spec_set=[ + "handle_new_event", + "get_state_for_room", + ]), + state_handler=NonCallableMock(spec_set=["handle_new_event"]), + ) + + self.datastore = hs.get_datastore() + self.handlers = hs.get_handlers() + self.notifier = hs.get_notifier() + self.federation = hs.get_federation() + self.state_handler = hs.get_state_handler() + self.distributor = hs.get_distributor() + self.hs = hs + + self.handlers.room_member_handler = RoomMemberHandler(self.hs) + self.handlers.profile_handler = ProfileHandler(self.hs) + self.room_member_handler = self.handlers.room_member_handler + + @defer.inlineCallbacks + def test_invite(self): + room_id = "!foo:red" + user_id = "@bob:red" + target_user_id = "@red:blue" + content = {"membership": Membership.INVITE} + + event = self.hs.get_event_factory().create_event( + etype=RoomMemberEvent.TYPE, + user_id=user_id, + target_user_id=target_user_id, + room_id=room_id, + membership=Membership.INVITE, + content=content, + ) + + joined = ["red", "green"] + + self.state_handler.handle_new_event.return_value = defer.succeed(True) + self.datastore.get_joined_hosts_for_room.return_value = ( + defer.succeed(joined) + ) + + store_id = "store_id_fooo" + self.datastore.store_room_member.return_value = defer.succeed(store_id) + + # Actual invocation + yield self.room_member_handler.change_membership(event) + + self.state_handler.handle_new_event.assert_called_once_with(event) + self.federation.handle_new_event.assert_called_once_with(event) + + self.assertEquals( + set(["blue", "red", "green"]), + set(event.destinations) + ) + + self.datastore.store_room_member.assert_called_once_with( + user_id=target_user_id, + sender=user_id, + room_id=room_id, + content=content, + membership=Membership.INVITE, + ) + self.notifier.on_new_room_event.assert_called_once_with( + event, store_id) + + self.assertFalse(self.datastore.get_room.called) + self.assertFalse(self.datastore.store_room.called) + self.assertFalse(self.federation.get_state_for_room.called) + + @defer.inlineCallbacks + def test_simple_join(self): + room_id = "!foo:red" + user_id = "@bob:red" + user = self.hs.parse_userid(user_id) + target_user_id = "@bob:red" + content = {"membership": Membership.JOIN} + + event = self.hs.get_event_factory().create_event( + etype=RoomMemberEvent.TYPE, + user_id=user_id, + target_user_id=target_user_id, + room_id=room_id, + membership=Membership.JOIN, + content=content, + ) + + joined = ["red", "green"] + + self.state_handler.handle_new_event.return_value = defer.succeed(True) + self.datastore.get_joined_hosts_for_room.return_value = ( + defer.succeed(joined) + ) + + store_id = "store_id_fooo" + self.datastore.store_room_member.return_value = defer.succeed(store_id) + self.datastore.get_room.return_value = defer.succeed(1) # Not None. + + prev_state = NonCallableMock() + prev_state.membership = Membership.INVITE + prev_state.sender = "@foo:red" + self.datastore.get_room_member.return_value = defer.succeed(prev_state) + + join_signal_observer = Mock() + self.distributor.observe("user_joined_room", join_signal_observer) + + # Actual invocation + yield self.room_member_handler.change_membership(event) + + self.state_handler.handle_new_event.assert_called_once_with(event) + self.federation.handle_new_event.assert_called_once_with(event) + + self.assertEquals( + set(["red", "green"]), + set(event.destinations) + ) + + self.datastore.store_room_member.assert_called_once_with( + user_id=target_user_id, + sender=user_id, + room_id=room_id, + content=content, + membership=Membership.JOIN, + ) + self.notifier.on_new_room_event.assert_called_once_with( + event, store_id) + + join_signal_observer.assert_called_with( + user=user, room_id=room_id) + + @defer.inlineCallbacks + def STALE_test_invite_join(self): + room_id = "foo" + user_id = "@bob:red" + target_user_id = "@bob:red" + content = {"membership": Membership.JOIN} + + event = self.hs.get_event_factory().create_event( + etype=RoomMemberEvent.TYPE, + user_id=user_id, + target_user_id=target_user_id, + room_id=room_id, + membership=Membership.JOIN, + content=content, + ) + + joined = ["red", "blue", "green"] + + self.state_handler.handle_new_event.return_value = defer.succeed(True) + self.datastore.get_joined_hosts_for_room.return_value = ( + defer.succeed(joined) + ) + + store_id = "store_id_fooo" + self.datastore.store_room_member.return_value = defer.succeed(store_id) + self.datastore.get_room.return_value = defer.succeed(None) + + prev_state = NonCallableMock(name="prev_state") + prev_state.membership = Membership.INVITE + prev_state.sender = "@foo:blue" + self.datastore.get_room_member.return_value = defer.succeed(prev_state) + + # Actual invocation + yield self.room_member_handler.change_membership(event) + + self.datastore.get_room_member.assert_called_once_with( + target_user_id, room_id + ) + + self.assertTrue(self.federation.handle_new_event.called) + args = self.federation.handle_new_event.call_args[0] + invite_join_event = args[0] + + self.assertTrue(InviteJoinEvent.TYPE, invite_join_event.TYPE) + self.assertTrue("blue", invite_join_event.target_host) + self.assertTrue(room_id, invite_join_event.room_id) + self.assertTrue(user_id, invite_join_event.user_id) + self.assertFalse(hasattr(invite_join_event, "state_key")) + + self.assertEquals( + set(["blue"]), + set(invite_join_event.destinations) + ) + + self.federation.get_state_for_room.assert_called_once_with( + "blue", room_id + ) + + self.assertFalse(self.datastore.store_room_member.called) + + self.assertFalse(self.notifier.on_new_room_event.called) + self.assertFalse(self.state_handler.handle_new_event.called) + + @defer.inlineCallbacks + def STALE_test_invite_join_public(self): + room_id = "#foo:blue" + user_id = "@bob:red" + target_user_id = "@bob:red" + content = {"membership": Membership.JOIN} + + event = self.hs.get_event_factory().create_event( + etype=RoomMemberEvent.TYPE, + user_id=user_id, + target_user_id=target_user_id, + room_id=room_id, + membership=Membership.JOIN, + content=content, + ) + + joined = ["red", "blue", "green"] + + self.state_handler.handle_new_event.return_value = defer.succeed(True) + self.datastore.get_joined_hosts_for_room.return_value = ( + defer.succeed(joined) + ) + + store_id = "store_id_fooo" + self.datastore.store_room_member.return_value = defer.succeed(store_id) + self.datastore.get_room.return_value = defer.succeed(None) + + prev_state = NonCallableMock(name="prev_state") + prev_state.membership = Membership.INVITE + prev_state.sender = "@foo:blue" + self.datastore.get_room_member.return_value = defer.succeed(prev_state) + + # Actual invocation + yield self.room_member_handler.change_membership(event) + + self.assertTrue(self.federation.handle_new_event.called) + args = self.federation.handle_new_event.call_args[0] + invite_join_event = args[0] + + self.assertTrue(InviteJoinEvent.TYPE, invite_join_event.TYPE) + self.assertTrue("blue", invite_join_event.target_host) + self.assertTrue("foo", invite_join_event.room_id) + self.assertTrue(user_id, invite_join_event.user_id) + self.assertFalse(hasattr(invite_join_event, "state_key")) + + self.assertEquals( + set(["blue"]), + set(invite_join_event.destinations) + ) + + self.federation.get_state_for_room.assert_called_once_with( + "blue", "foo" + ) + + self.assertFalse(self.datastore.store_room_member.called) + + self.assertFalse(self.notifier.on_new_room_event.called) + self.assertFalse(self.state_handler.handle_new_event.called) + + +class RoomCreationTest(unittest.TestCase): + + def setUp(self): + self.hostname = "red" + hs = HomeServer( + self.hostname, + db_pool=None, + datastore=NonCallableMock(spec_set=[ + "store_room", + ]), + http_server=NonCallableMock(), + http_client=NonCallableMock(spec_set=[]), + notifier=NonCallableMock(spec_set=["on_new_room_event"]), + handlers=NonCallableMock(spec_set=[ + "room_creation_handler", + "room_member_handler", + ]), + auth=NonCallableMock(spec_set=["check"]), + federation=NonCallableMock(spec_set=[ + "handle_new_event", + ]), + state_handler=NonCallableMock(spec_set=["handle_new_event"]), + ) + + self.datastore = hs.get_datastore() + self.handlers = hs.get_handlers() + self.notifier = hs.get_notifier() + self.federation = hs.get_federation() + self.state_handler = hs.get_state_handler() + self.hs = hs + + self.handlers.room_creation_handler = RoomCreationHandler(self.hs) + self.room_creation_handler = self.handlers.room_creation_handler + + self.handlers.room_member_handler = NonCallableMock(spec_set=[ + "change_membership" + ]) + self.room_member_handler = self.handlers.room_member_handler + + @defer.inlineCallbacks + def test_room_creation(self): + user_id = "@foo:red" + room_id = "!bobs_room:red" + config = {"visibility": "private"} + + yield self.room_creation_handler.create_room( + user_id=user_id, + room_id=room_id, + config=config, + ) + + self.assertTrue(self.room_member_handler.change_membership.called) + join_event = self.room_member_handler.change_membership.call_args[0][0] + + self.assertEquals(RoomMemberEvent.TYPE, join_event.type) + self.assertEquals(room_id, join_event.room_id) + self.assertEquals(user_id, join_event.user_id) + self.assertEquals(user_id, join_event.target_user_id) + + self.assertTrue(self.state_handler.handle_new_event.called) + + self.assertTrue(self.federation.handle_new_event.called) + config_event = self.federation.handle_new_event.call_args[0][0] + + self.assertEquals(RoomConfigEvent.TYPE, config_event.type) + self.assertEquals(room_id, config_event.room_id) + self.assertEquals(user_id, config_event.user_id) + self.assertEquals(config, config_event.content) -- cgit 1.4.1