diff --git a/tests/handlers/test_directory.py b/tests/handlers/test_directory.py
index 9bf395e923..5b2105bc76 100644
--- a/tests/handlers/test_directory.py
+++ b/tests/handlers/test_directory.py
@@ -111,7 +111,7 @@ class TestCreateAliasACL(unittest.HomeserverTestCase):
servlets = [directory.register_servlets, room.register_servlets]
- def prepare(self, hs, reactor, clock):
+ def prepare(self, reactor, clock, hs):
# We cheekily override the config to add custom alias creation rules
config = {}
config["alias_creation_rules"] = [
@@ -151,3 +151,60 @@ class TestCreateAliasACL(unittest.HomeserverTestCase):
)
self.render(request)
self.assertEquals(200, channel.code, channel.result)
+
+
+class TestRoomListSearchDisabled(unittest.HomeserverTestCase):
+ user_id = "@test:test"
+
+ servlets = [directory.register_servlets, room.register_servlets]
+
+ def prepare(self, reactor, clock, hs):
+ room_id = self.helper.create_room_as(self.user_id)
+
+ request, channel = self.make_request(
+ "PUT",
+ b"directory/list/room/%s" % (room_id.encode('ascii'),),
+ b'{}',
+ )
+ self.render(request)
+ self.assertEquals(200, channel.code, channel.result)
+
+ self.room_list_handler = hs.get_room_list_handler()
+ self.directory_handler = hs.get_handlers().directory_handler
+
+ return hs
+
+ def test_disabling_room_list(self):
+ self.room_list_handler.enable_room_list_search = True
+ self.directory_handler.enable_room_list_search = True
+
+ # Room list is enabled so we should get some results
+ request, channel = self.make_request(
+ "GET",
+ b"publicRooms",
+ )
+ self.render(request)
+ self.assertEquals(200, channel.code, channel.result)
+ self.assertTrue(len(channel.json_body["chunk"]) > 0)
+
+ self.room_list_handler.enable_room_list_search = False
+ self.directory_handler.enable_room_list_search = False
+
+ # Room list disabled so we should get no results
+ request, channel = self.make_request(
+ "GET",
+ b"publicRooms",
+ )
+ self.render(request)
+ self.assertEquals(200, channel.code, channel.result)
+ self.assertTrue(len(channel.json_body["chunk"]) == 0)
+
+ # Room list disabled so we shouldn't be allowed to publish rooms
+ room_id = self.helper.create_room_as(self.user_id)
+ request, channel = self.make_request(
+ "PUT",
+ b"directory/list/room/%s" % (room_id.encode('ascii'),),
+ b'{}',
+ )
+ self.render(request)
+ self.assertEquals(403, channel.code, channel.result)
diff --git a/tests/handlers/test_profile.py b/tests/handlers/test_profile.py
index 80da1c8954..d60c124eec 100644
--- a/tests/handlers/test_profile.py
+++ b/tests/handlers/test_profile.py
@@ -55,11 +55,11 @@ class ProfileTestCase(unittest.TestCase):
federation_client=self.mock_federation,
federation_server=Mock(),
federation_registry=self.mock_registry,
- ratelimiter=NonCallableMock(spec_set=["send_message"]),
+ ratelimiter=NonCallableMock(spec_set=["can_do_action"]),
)
self.ratelimiter = hs.get_ratelimiter()
- self.ratelimiter.send_message.return_value = (True, 0)
+ self.ratelimiter.can_do_action.return_value = (True, 0)
self.store = hs.get_datastore()
diff --git a/tests/handlers/test_register.py b/tests/handlers/test_register.py
index c9c1506273..017ea0385e 100644
--- a/tests/handlers/test_register.py
+++ b/tests/handlers/test_register.py
@@ -22,8 +22,6 @@ from synapse.api.errors import ResourceLimitError, SynapseError
from synapse.handlers.register import RegistrationHandler
from synapse.types import RoomAlias, UserID, create_requester
-from tests.utils import setup_test_homeserver
-
from .. import unittest
@@ -32,176 +30,197 @@ class RegistrationHandlers(object):
self.registration_handler = RegistrationHandler(hs)
-class RegistrationTestCase(unittest.TestCase):
+class RegistrationTestCase(unittest.HomeserverTestCase):
""" Tests the RegistrationHandler. """
- @defer.inlineCallbacks
- def setUp(self):
+ def make_homeserver(self, reactor, clock):
+ hs_config = self.default_config("test")
+
+ # some of the tests rely on us having a user consent version
+ hs_config.user_consent_version = "test_consent_version"
+ hs_config.max_mau_value = 50
+
+ hs = self.setup_test_homeserver(config=hs_config, expire_access_token=True)
+ return hs
+
+ def prepare(self, reactor, clock, hs):
self.mock_distributor = Mock()
self.mock_distributor.declare("registered_user")
self.mock_captcha_client = Mock()
- self.hs = yield setup_test_homeserver(
- self.addCleanup,
- expire_access_token=True,
- )
self.macaroon_generator = Mock(
generate_access_token=Mock(return_value='secret')
)
self.hs.get_macaroon_generator = Mock(return_value=self.macaroon_generator)
self.handler = self.hs.get_registration_handler()
self.store = self.hs.get_datastore()
- self.hs.config.max_mau_value = 50
self.lots_of_users = 100
self.small_number_of_users = 1
self.requester = create_requester("@requester:test")
- @defer.inlineCallbacks
def test_user_is_created_and_logged_in_if_doesnt_exist(self):
frank = UserID.from_string("@frank:test")
user_id = frank.to_string()
requester = create_requester(user_id)
- result_user_id, result_token = yield self.handler.get_or_create_user(
- requester, frank.localpart, "Frankie"
+ result_user_id, result_token = self.get_success(
+ self.handler.get_or_create_user(requester, frank.localpart, "Frankie")
)
self.assertEquals(result_user_id, user_id)
self.assertTrue(result_token is not None)
self.assertEquals(result_token, 'secret')
- @defer.inlineCallbacks
def test_if_user_exists(self):
store = self.hs.get_datastore()
frank = UserID.from_string("@frank:test")
- yield store.register(
- user_id=frank.to_string(),
- token="jkv;g498752-43gj['eamb!-5",
- password_hash=None,
+ self.get_success(
+ store.register(
+ user_id=frank.to_string(),
+ token="jkv;g498752-43gj['eamb!-5",
+ password_hash=None,
+ )
)
local_part = frank.localpart
user_id = frank.to_string()
requester = create_requester(user_id)
- result_user_id, result_token = yield self.handler.get_or_create_user(
- requester, local_part, None
+ result_user_id, result_token = self.get_success(
+ self.handler.get_or_create_user(requester, local_part, None)
)
self.assertEquals(result_user_id, user_id)
self.assertTrue(result_token is not None)
- @defer.inlineCallbacks
def test_mau_limits_when_disabled(self):
self.hs.config.limit_usage_by_mau = False
# Ensure does not throw exception
- yield self.handler.get_or_create_user(self.requester, 'a', "display_name")
+ self.get_success(
+ self.handler.get_or_create_user(self.requester, 'a', "display_name")
+ )
- @defer.inlineCallbacks
def test_get_or_create_user_mau_not_blocked(self):
self.hs.config.limit_usage_by_mau = True
self.store.count_monthly_users = Mock(
return_value=defer.succeed(self.hs.config.max_mau_value - 1)
)
# Ensure does not throw exception
- yield self.handler.get_or_create_user(self.requester, 'c', "User")
+ self.get_success(self.handler.get_or_create_user(self.requester, 'c', "User"))
- @defer.inlineCallbacks
def test_get_or_create_user_mau_blocked(self):
self.hs.config.limit_usage_by_mau = True
self.store.get_monthly_active_count = Mock(
return_value=defer.succeed(self.lots_of_users)
)
- with self.assertRaises(ResourceLimitError):
- yield self.handler.get_or_create_user(self.requester, 'b', "display_name")
+ self.get_failure(
+ self.handler.get_or_create_user(self.requester, 'b', "display_name"),
+ ResourceLimitError,
+ )
self.store.get_monthly_active_count = Mock(
return_value=defer.succeed(self.hs.config.max_mau_value)
)
- with self.assertRaises(ResourceLimitError):
- yield self.handler.get_or_create_user(self.requester, 'b', "display_name")
+ self.get_failure(
+ self.handler.get_or_create_user(self.requester, 'b', "display_name"),
+ ResourceLimitError,
+ )
- @defer.inlineCallbacks
def test_register_mau_blocked(self):
self.hs.config.limit_usage_by_mau = True
self.store.get_monthly_active_count = Mock(
return_value=defer.succeed(self.lots_of_users)
)
- with self.assertRaises(ResourceLimitError):
- yield self.handler.register(localpart="local_part")
+ self.get_failure(
+ self.handler.register(localpart="local_part"), ResourceLimitError
+ )
self.store.get_monthly_active_count = Mock(
return_value=defer.succeed(self.hs.config.max_mau_value)
)
- with self.assertRaises(ResourceLimitError):
- yield self.handler.register(localpart="local_part")
+ self.get_failure(
+ self.handler.register(localpart="local_part"), ResourceLimitError
+ )
- @defer.inlineCallbacks
def test_auto_create_auto_join_rooms(self):
room_alias_str = "#room:test"
self.hs.config.auto_join_rooms = [room_alias_str]
- res = yield self.handler.register(localpart='jeff')
- rooms = yield self.store.get_rooms_for_user(res[0])
+ res = self.get_success(self.handler.register(localpart='jeff'))
+ rooms = self.get_success(self.store.get_rooms_for_user(res[0]))
directory_handler = self.hs.get_handlers().directory_handler
room_alias = RoomAlias.from_string(room_alias_str)
- room_id = yield directory_handler.get_association(room_alias)
+ room_id = self.get_success(directory_handler.get_association(room_alias))
self.assertTrue(room_id['room_id'] in rooms)
self.assertEqual(len(rooms), 1)
- @defer.inlineCallbacks
def test_auto_create_auto_join_rooms_with_no_rooms(self):
self.hs.config.auto_join_rooms = []
frank = UserID.from_string("@frank:test")
- res = yield self.handler.register(frank.localpart)
+ res = self.get_success(self.handler.register(frank.localpart))
self.assertEqual(res[0], frank.to_string())
- rooms = yield self.store.get_rooms_for_user(res[0])
+ rooms = self.get_success(self.store.get_rooms_for_user(res[0]))
self.assertEqual(len(rooms), 0)
- @defer.inlineCallbacks
def test_auto_create_auto_join_where_room_is_another_domain(self):
self.hs.config.auto_join_rooms = ["#room:another"]
frank = UserID.from_string("@frank:test")
- res = yield self.handler.register(frank.localpart)
+ res = self.get_success(self.handler.register(frank.localpart))
self.assertEqual(res[0], frank.to_string())
- rooms = yield self.store.get_rooms_for_user(res[0])
+ rooms = self.get_success(self.store.get_rooms_for_user(res[0]))
self.assertEqual(len(rooms), 0)
- @defer.inlineCallbacks
def test_auto_create_auto_join_where_auto_create_is_false(self):
self.hs.config.autocreate_auto_join_rooms = False
room_alias_str = "#room:test"
self.hs.config.auto_join_rooms = [room_alias_str]
- res = yield self.handler.register(localpart='jeff')
- rooms = yield self.store.get_rooms_for_user(res[0])
+ res = self.get_success(self.handler.register(localpart='jeff'))
+ rooms = self.get_success(self.store.get_rooms_for_user(res[0]))
self.assertEqual(len(rooms), 0)
- @defer.inlineCallbacks
def test_auto_create_auto_join_rooms_when_support_user_exists(self):
room_alias_str = "#room:test"
self.hs.config.auto_join_rooms = [room_alias_str]
self.store.is_support_user = Mock(return_value=True)
- res = yield self.handler.register(localpart='support')
- rooms = yield self.store.get_rooms_for_user(res[0])
+ res = self.get_success(self.handler.register(localpart='support'))
+ rooms = self.get_success(self.store.get_rooms_for_user(res[0]))
self.assertEqual(len(rooms), 0)
directory_handler = self.hs.get_handlers().directory_handler
room_alias = RoomAlias.from_string(room_alias_str)
- with self.assertRaises(SynapseError):
- yield directory_handler.get_association(room_alias)
+ self.get_failure(directory_handler.get_association(room_alias), SynapseError)
- @defer.inlineCallbacks
def test_auto_create_auto_join_where_no_consent(self):
- self.hs.config.user_consent_at_registration = True
- self.hs.config.block_events_without_consent_error = "Error"
+ """Test to ensure that the first user is not auto-joined to a room if
+ they have not given general consent.
+ """
+
+ # Given:-
+ # * a user must give consent,
+ # * they have not given that consent
+ # * The server is configured to auto-join to a room
+ # (and autocreate if necessary)
+
+ event_creation_handler = self.hs.get_event_creation_handler()
+ # (Messing with the internals of event_creation_handler is fragile
+ # but can't see a better way to do this. One option could be to subclass
+ # the test with custom config.)
+ event_creation_handler._block_events_without_consent_error = "Error"
+ event_creation_handler._consent_uri_builder = Mock()
room_alias_str = "#room:test"
self.hs.config.auto_join_rooms = [room_alias_str]
- res = yield self.handler.register(localpart='jeff')
- yield self.handler.post_consent_actions(res[0])
- rooms = yield self.store.get_rooms_for_user(res[0])
+
+ # When:-
+ # * the user is registered and post consent actions are called
+ res = self.get_success(self.handler.register(localpart='jeff'))
+ self.get_success(self.handler.post_consent_actions(res[0]))
+
+ # Then:-
+ # * Ensure that they have not been joined to the room
+ rooms = self.get_success(self.store.get_rooms_for_user(res[0]))
self.assertEqual(len(rooms), 0)
- @defer.inlineCallbacks
def test_register_support_user(self):
- res = yield self.handler.register(localpart='user', user_type=UserTypes.SUPPORT)
+ res = self.get_success(
+ self.handler.register(localpart='user', user_type=UserTypes.SUPPORT)
+ )
self.assertTrue(self.store.is_support_user(res[0]))
- @defer.inlineCallbacks
def test_register_not_support_user(self):
- res = yield self.handler.register(localpart='user')
+ res = self.get_success(self.handler.register(localpart='user'))
self.assertFalse(self.store.is_support_user(res[0]))
diff --git a/tests/handlers/test_typing.py b/tests/handlers/test_typing.py
index 36e136cded..6460cbc708 100644
--- a/tests/handlers/test_typing.py
+++ b/tests/handlers/test_typing.py
@@ -24,13 +24,17 @@ from synapse.api.errors import AuthError
from synapse.types import UserID
from tests import unittest
+from tests.utils import register_federation_servlets
-from ..utils import (
- DeferredMockCallable,
- MockClock,
- MockHttpResource,
- setup_test_homeserver,
-)
+# Some local users to test with
+U_APPLE = UserID.from_string("@apple:test")
+U_BANANA = UserID.from_string("@banana:test")
+
+# Remote user
+U_ONION = UserID.from_string("@onion:farm")
+
+# Test room id
+ROOM_ID = "a-room"
def _expect_edu_transaction(edu_type, content, origin="test"):
@@ -46,30 +50,21 @@ def _make_edu_transaction_json(edu_type, content):
return json.dumps(_expect_edu_transaction(edu_type, content)).encode('utf8')
-class TypingNotificationsTestCase(unittest.TestCase):
- """Tests typing notifications to rooms."""
-
- @defer.inlineCallbacks
- def setUp(self):
- self.clock = MockClock()
+class TypingNotificationsTestCase(unittest.HomeserverTestCase):
+ servlets = [register_federation_servlets]
- self.mock_http_client = Mock(spec=[])
- self.mock_http_client.put_json = DeferredMockCallable()
+ def make_homeserver(self, reactor, clock):
+ # we mock out the keyring so as to skip the authentication check on the
+ # federation API call.
+ mock_keyring = Mock(spec=["verify_json_for_server"])
+ mock_keyring.verify_json_for_server.return_value = defer.succeed(True)
- self.mock_federation_resource = MockHttpResource()
-
- mock_notifier = Mock()
- self.on_new_event = mock_notifier.on_new_event
+ # we mock out the federation client too
+ mock_federation_client = Mock(spec=["put_json"])
+ mock_federation_client.put_json.return_value = defer.succeed((200, "OK"))
- self.auth = Mock(spec=[])
- self.state_handler = Mock()
-
- hs = yield setup_test_homeserver(
- self.addCleanup,
- "test",
- auth=self.auth,
- clock=self.clock,
- datastore=Mock(
+ hs = self.setup_test_homeserver(
+ datastore=(Mock(
spec=[
# Bits that Federation needs
"prep_send_transaction",
@@ -82,16 +77,21 @@ class TypingNotificationsTestCase(unittest.TestCase):
"get_user_directory_stream_pos",
"get_current_state_deltas",
]
- ),
- state_handler=self.state_handler,
- handlers=Mock(),
- notifier=mock_notifier,
- resource_for_client=Mock(),
- resource_for_federation=self.mock_federation_resource,
- http_client=self.mock_http_client,
- keyring=Mock(),
+ )),
+ notifier=Mock(),
+ http_client=mock_federation_client,
+ keyring=mock_keyring,
)
+ return hs
+
+ def prepare(self, reactor, clock, hs):
+ # the tests assume that we are starting at unix time 1000
+ reactor.pump((1000, ))
+
+ mock_notifier = hs.get_notifier()
+ self.on_new_event = mock_notifier.on_new_event
+
self.handler = hs.get_typing_handler()
self.event_source = hs.get_event_sources().sources["typing"]
@@ -109,13 +109,12 @@ class TypingNotificationsTestCase(unittest.TestCase):
self.datastore.get_received_txn_response = get_received_txn_response
- self.room_id = "a-room"
-
self.room_members = []
def check_joined_room(room_id, user_id):
if user_id not in [u.to_string() for u in self.room_members]:
raise AuthError(401, "User is not in the room")
+ hs.get_auth().check_joined_room = check_joined_room
def get_joined_hosts_for_room(room_id):
return set(member.domain for member in self.room_members)
@@ -124,8 +123,7 @@ class TypingNotificationsTestCase(unittest.TestCase):
def get_current_user_in_room(room_id):
return set(str(u) for u in self.room_members)
-
- self.state_handler.get_current_user_in_room = get_current_user_in_room
+ hs.get_state_handler().get_current_user_in_room = get_current_user_in_room
self.datastore.get_user_directory_stream_pos.return_value = (
# we deliberately return a non-None stream pos to avoid doing an initial_spam
@@ -134,230 +132,210 @@ class TypingNotificationsTestCase(unittest.TestCase):
self.datastore.get_current_state_deltas.return_value = None
- self.auth.check_joined_room = check_joined_room
-
self.datastore.get_to_device_stream_token = lambda: 0
self.datastore.get_new_device_msgs_for_remote = lambda *args, **kargs: ([], 0)
self.datastore.delete_device_msgs_for_remote = lambda *args, **kargs: None
- # Some local users to test with
- self.u_apple = UserID.from_string("@apple:test")
- self.u_banana = UserID.from_string("@banana:test")
-
- # Remote user
- self.u_onion = UserID.from_string("@onion:farm")
-
- @defer.inlineCallbacks
def test_started_typing_local(self):
- self.room_members = [self.u_apple, self.u_banana]
+ self.room_members = [U_APPLE, U_BANANA]
self.assertEquals(self.event_source.get_current_key(), 0)
- yield self.handler.started_typing(
- target_user=self.u_apple,
- auth_user=self.u_apple,
- room_id=self.room_id,
+ self.successResultOf(self.handler.started_typing(
+ target_user=U_APPLE,
+ auth_user=U_APPLE,
+ room_id=ROOM_ID,
timeout=20000,
- )
+ ))
self.on_new_event.assert_has_calls(
- [call('typing_key', 1, rooms=[self.room_id])]
+ [call('typing_key', 1, rooms=[ROOM_ID])]
)
self.assertEquals(self.event_source.get_current_key(), 1)
- events = yield self.event_source.get_new_events(
- room_ids=[self.room_id], from_key=0
+ events = self.event_source.get_new_events(
+ room_ids=[ROOM_ID], from_key=0
)
self.assertEquals(
events[0],
[
{
"type": "m.typing",
- "room_id": self.room_id,
- "content": {"user_ids": [self.u_apple.to_string()]},
+ "room_id": ROOM_ID,
+ "content": {"user_ids": [U_APPLE.to_string()]},
}
],
)
- @defer.inlineCallbacks
def test_started_typing_remote_send(self):
- self.room_members = [self.u_apple, self.u_onion]
-
- put_json = self.mock_http_client.put_json
- put_json.expect_call_and_return(
- call(
- "farm",
- path="/_matrix/federation/v1/send/1000000/",
- data=_expect_edu_transaction(
- "m.typing",
- content={
- "room_id": self.room_id,
- "user_id": self.u_apple.to_string(),
- "typing": True,
- },
- ),
- json_data_callback=ANY,
- long_retries=True,
- backoff_on_404=True,
- ),
- defer.succeed((200, "OK")),
- )
+ self.room_members = [U_APPLE, U_ONION]
- yield self.handler.started_typing(
- target_user=self.u_apple,
- auth_user=self.u_apple,
- room_id=self.room_id,
+ self.successResultOf(self.handler.started_typing(
+ target_user=U_APPLE,
+ auth_user=U_APPLE,
+ room_id=ROOM_ID,
timeout=20000,
- )
+ ))
- yield put_json.await_calls()
+ put_json = self.hs.get_http_client().put_json
+ put_json.assert_called_once_with(
+ "farm",
+ path="/_matrix/federation/v1/send/1000000",
+ data=_expect_edu_transaction(
+ "m.typing",
+ content={
+ "room_id": ROOM_ID,
+ "user_id": U_APPLE.to_string(),
+ "typing": True,
+ },
+ ),
+ json_data_callback=ANY,
+ long_retries=True,
+ backoff_on_404=True,
+ try_trailing_slash_on_400=True,
+ )
- @defer.inlineCallbacks
def test_started_typing_remote_recv(self):
- self.room_members = [self.u_apple, self.u_onion]
+ self.room_members = [U_APPLE, U_ONION]
self.assertEquals(self.event_source.get_current_key(), 0)
- (code, response) = yield self.mock_federation_resource.trigger(
+ (request, channel) = self.make_request(
"PUT",
- "/_matrix/federation/v1/send/1000000/",
+ "/_matrix/federation/v1/send/1000000",
_make_edu_transaction_json(
"m.typing",
content={
- "room_id": self.room_id,
- "user_id": self.u_onion.to_string(),
+ "room_id": ROOM_ID,
+ "user_id": U_ONION.to_string(),
"typing": True,
},
),
federation_auth_origin=b'farm',
)
+ self.render(request)
+ self.assertEqual(channel.code, 200)
self.on_new_event.assert_has_calls(
- [call('typing_key', 1, rooms=[self.room_id])]
+ [call('typing_key', 1, rooms=[ROOM_ID])]
)
self.assertEquals(self.event_source.get_current_key(), 1)
- events = yield self.event_source.get_new_events(
- room_ids=[self.room_id], from_key=0
+ events = self.event_source.get_new_events(
+ room_ids=[ROOM_ID], from_key=0
)
self.assertEquals(
events[0],
[
{
"type": "m.typing",
- "room_id": self.room_id,
- "content": {"user_ids": [self.u_onion.to_string()]},
+ "room_id": ROOM_ID,
+ "content": {"user_ids": [U_ONION.to_string()]},
}
],
)
- @defer.inlineCallbacks
def test_stopped_typing(self):
- self.room_members = [self.u_apple, self.u_banana, self.u_onion]
-
- put_json = self.mock_http_client.put_json
- put_json.expect_call_and_return(
- call(
- "farm",
- path="/_matrix/federation/v1/send/1000000/",
- data=_expect_edu_transaction(
- "m.typing",
- content={
- "room_id": self.room_id,
- "user_id": self.u_apple.to_string(),
- "typing": False,
- },
- ),
- json_data_callback=ANY,
- long_retries=True,
- backoff_on_404=True,
- ),
- defer.succeed((200, "OK")),
- )
+ self.room_members = [U_APPLE, U_BANANA, U_ONION]
# Gut-wrenching
from synapse.handlers.typing import RoomMember
- member = RoomMember(self.room_id, self.u_apple.to_string())
+ member = RoomMember(ROOM_ID, U_APPLE.to_string())
self.handler._member_typing_until[member] = 1002000
- self.handler._room_typing[self.room_id] = set([self.u_apple.to_string()])
+ self.handler._room_typing[ROOM_ID] = set([U_APPLE.to_string()])
self.assertEquals(self.event_source.get_current_key(), 0)
- yield self.handler.stopped_typing(
- target_user=self.u_apple, auth_user=self.u_apple, room_id=self.room_id
- )
+ self.successResultOf(self.handler.stopped_typing(
+ target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID
+ ))
self.on_new_event.assert_has_calls(
- [call('typing_key', 1, rooms=[self.room_id])]
+ [call('typing_key', 1, rooms=[ROOM_ID])]
)
- yield put_json.await_calls()
+ put_json = self.hs.get_http_client().put_json
+ put_json.assert_called_once_with(
+ "farm",
+ path="/_matrix/federation/v1/send/1000000",
+ data=_expect_edu_transaction(
+ "m.typing",
+ content={
+ "room_id": ROOM_ID,
+ "user_id": U_APPLE.to_string(),
+ "typing": False,
+ },
+ ),
+ json_data_callback=ANY,
+ long_retries=True,
+ backoff_on_404=True,
+ try_trailing_slash_on_400=True,
+ )
self.assertEquals(self.event_source.get_current_key(), 1)
- events = yield self.event_source.get_new_events(
- room_ids=[self.room_id], from_key=0
+ events = self.event_source.get_new_events(
+ room_ids=[ROOM_ID], from_key=0
)
self.assertEquals(
events[0],
[
{
"type": "m.typing",
- "room_id": self.room_id,
+ "room_id": ROOM_ID,
"content": {"user_ids": []},
}
],
)
- @defer.inlineCallbacks
def test_typing_timeout(self):
- self.room_members = [self.u_apple, self.u_banana]
+ self.room_members = [U_APPLE, U_BANANA]
self.assertEquals(self.event_source.get_current_key(), 0)
- yield self.handler.started_typing(
- target_user=self.u_apple,
- auth_user=self.u_apple,
- room_id=self.room_id,
+ self.successResultOf(self.handler.started_typing(
+ target_user=U_APPLE,
+ auth_user=U_APPLE,
+ room_id=ROOM_ID,
timeout=10000,
- )
+ ))
self.on_new_event.assert_has_calls(
- [call('typing_key', 1, rooms=[self.room_id])]
+ [call('typing_key', 1, rooms=[ROOM_ID])]
)
self.on_new_event.reset_mock()
self.assertEquals(self.event_source.get_current_key(), 1)
- events = yield self.event_source.get_new_events(
- room_ids=[self.room_id], from_key=0
+ events = self.event_source.get_new_events(
+ room_ids=[ROOM_ID], from_key=0
)
self.assertEquals(
events[0],
[
{
"type": "m.typing",
- "room_id": self.room_id,
- "content": {"user_ids": [self.u_apple.to_string()]},
+ "room_id": ROOM_ID,
+ "content": {"user_ids": [U_APPLE.to_string()]},
}
],
)
- self.clock.advance_time(16)
+ self.reactor.pump([16, ])
self.on_new_event.assert_has_calls(
- [call('typing_key', 2, rooms=[self.room_id])]
+ [call('typing_key', 2, rooms=[ROOM_ID])]
)
self.assertEquals(self.event_source.get_current_key(), 2)
- events = yield self.event_source.get_new_events(
- room_ids=[self.room_id], from_key=1
+ events = self.event_source.get_new_events(
+ room_ids=[ROOM_ID], from_key=1
)
self.assertEquals(
events[0],
[
{
"type": "m.typing",
- "room_id": self.room_id,
+ "room_id": ROOM_ID,
"content": {"user_ids": []},
}
],
@@ -365,29 +343,29 @@ class TypingNotificationsTestCase(unittest.TestCase):
# SYN-230 - see if we can still set after timeout
- yield self.handler.started_typing(
- target_user=self.u_apple,
- auth_user=self.u_apple,
- room_id=self.room_id,
+ self.successResultOf(self.handler.started_typing(
+ target_user=U_APPLE,
+ auth_user=U_APPLE,
+ room_id=ROOM_ID,
timeout=10000,
- )
+ ))
self.on_new_event.assert_has_calls(
- [call('typing_key', 3, rooms=[self.room_id])]
+ [call('typing_key', 3, rooms=[ROOM_ID])]
)
self.on_new_event.reset_mock()
self.assertEquals(self.event_source.get_current_key(), 3)
- events = yield self.event_source.get_new_events(
- room_ids=[self.room_id], from_key=0
+ events = self.event_source.get_new_events(
+ room_ids=[ROOM_ID], from_key=0
)
self.assertEquals(
events[0],
[
{
"type": "m.typing",
- "room_id": self.room_id,
- "content": {"user_ids": [self.u_apple.to_string()]},
+ "room_id": ROOM_ID,
+ "content": {"user_ids": [U_APPLE.to_string()]},
}
],
)
diff --git a/tests/handlers/test_user_directory.py b/tests/handlers/test_user_directory.py
index 11f2bae698..f1d0aa42b6 100644
--- a/tests/handlers/test_user_directory.py
+++ b/tests/handlers/test_user_directory.py
@@ -14,78 +14,358 @@
# limitations under the License.
from mock import Mock
-from twisted.internet import defer
-
from synapse.api.constants import UserTypes
-from synapse.handlers.user_directory import UserDirectoryHandler
+from synapse.rest.client.v1 import admin, login, room
+from synapse.rest.client.v2_alpha import user_directory
from synapse.storage.roommember import ProfileInfo
from tests import unittest
-from tests.utils import setup_test_homeserver
-class UserDirectoryHandlers(object):
- def __init__(self, hs):
- self.user_directory_handler = UserDirectoryHandler(hs)
+class UserDirectoryTestCase(unittest.HomeserverTestCase):
+ """
+ Tests the UserDirectoryHandler.
+ """
+ servlets = [
+ login.register_servlets,
+ admin.register_servlets,
+ room.register_servlets,
+ ]
-class UserDirectoryTestCase(unittest.TestCase):
- """ Tests the UserDirectoryHandler. """
+ def make_homeserver(self, reactor, clock):
- @defer.inlineCallbacks
- def setUp(self):
- hs = yield setup_test_homeserver(self.addCleanup)
- self.store = hs.get_datastore()
- hs.handlers = UserDirectoryHandlers(hs)
+ config = self.default_config()
+ config.update_user_directory = True
+ return self.setup_test_homeserver(config=config)
- self.handler = hs.get_handlers().user_directory_handler
+ def prepare(self, reactor, clock, hs):
+ self.store = hs.get_datastore()
+ self.handler = hs.get_user_directory_handler()
- @defer.inlineCallbacks
def test_handle_local_profile_change_with_support_user(self):
support_user_id = "@support:test"
- yield self.store.register(
- user_id=support_user_id,
- token="123",
- password_hash=None,
- user_type=UserTypes.SUPPORT
+ self.get_success(
+ self.store.register(
+ user_id=support_user_id,
+ token="123",
+ password_hash=None,
+ user_type=UserTypes.SUPPORT,
+ )
)
- yield self.handler.handle_local_profile_change(support_user_id, None)
- profile = yield self.store.get_user_in_directory(support_user_id)
+ self.get_success(
+ self.handler.handle_local_profile_change(support_user_id, None)
+ )
+ profile = self.get_success(self.store.get_user_in_directory(support_user_id))
self.assertTrue(profile is None)
display_name = 'display_name'
- profile_info = ProfileInfo(
- avatar_url='avatar_url',
- display_name=display_name,
- )
+ profile_info = ProfileInfo(avatar_url='avatar_url', display_name=display_name)
regular_user_id = '@regular:test'
- yield self.handler.handle_local_profile_change(regular_user_id, profile_info)
- profile = yield self.store.get_user_in_directory(regular_user_id)
+ self.get_success(
+ self.handler.handle_local_profile_change(regular_user_id, profile_info)
+ )
+ profile = self.get_success(self.store.get_user_in_directory(regular_user_id))
self.assertTrue(profile['display_name'] == display_name)
- @defer.inlineCallbacks
def test_handle_user_deactivated_support_user(self):
s_user_id = "@support:test"
- self.store.register(
- user_id=s_user_id,
- token="123",
- password_hash=None,
- user_type=UserTypes.SUPPORT
+ self.get_success(
+ self.store.register(
+ user_id=s_user_id,
+ token="123",
+ password_hash=None,
+ user_type=UserTypes.SUPPORT,
+ )
)
self.store.remove_from_user_dir = Mock()
self.store.remove_from_user_in_public_room = Mock()
- yield self.handler.handle_user_deactivated(s_user_id)
+ self.get_success(self.handler.handle_user_deactivated(s_user_id))
self.store.remove_from_user_dir.not_called()
self.store.remove_from_user_in_public_room.not_called()
- @defer.inlineCallbacks
def test_handle_user_deactivated_regular_user(self):
r_user_id = "@regular:test"
- self.store.register(user_id=r_user_id, token="123", password_hash=None)
+ self.get_success(
+ self.store.register(user_id=r_user_id, token="123", password_hash=None)
+ )
self.store.remove_from_user_dir = Mock()
- self.store.remove_from_user_in_public_room = Mock()
- yield self.handler.handle_user_deactivated(r_user_id)
+ self.get_success(self.handler.handle_user_deactivated(r_user_id))
self.store.remove_from_user_dir.called_once_with(r_user_id)
- self.store.remove_from_user_in_public_room.assert_called_once_with(r_user_id)
+
+ def test_private_room(self):
+ """
+ A user can be searched for only by people that are either in a public
+ room, or that share a private chat.
+ """
+ u1 = self.register_user("user1", "pass")
+ u1_token = self.login(u1, "pass")
+ u2 = self.register_user("user2", "pass")
+ u2_token = self.login(u2, "pass")
+ u3 = self.register_user("user3", "pass")
+
+ # We do not add users to the directory until they join a room.
+ s = self.get_success(self.handler.search_users(u1, "user2", 10))
+ self.assertEqual(len(s["results"]), 0)
+
+ room = self.helper.create_room_as(u1, is_public=False, tok=u1_token)
+ self.helper.invite(room, src=u1, targ=u2, tok=u1_token)
+ self.helper.join(room, user=u2, tok=u2_token)
+
+ # Check we have populated the database correctly.
+ shares_private = self.get_users_who_share_private_rooms()
+ public_users = self.get_users_in_public_rooms()
+
+ self.assertEqual(
+ self._compress_shared(shares_private), set([(u1, u2, room), (u2, u1, room)])
+ )
+ self.assertEqual(public_users, [])
+
+ # We get one search result when searching for user2 by user1.
+ s = self.get_success(self.handler.search_users(u1, "user2", 10))
+ self.assertEqual(len(s["results"]), 1)
+
+ # We get NO search results when searching for user2 by user3.
+ s = self.get_success(self.handler.search_users(u3, "user2", 10))
+ self.assertEqual(len(s["results"]), 0)
+
+ # We get NO search results when searching for user3 by user1.
+ s = self.get_success(self.handler.search_users(u1, "user3", 10))
+ self.assertEqual(len(s["results"]), 0)
+
+ # User 2 then leaves.
+ self.helper.leave(room, user=u2, tok=u2_token)
+
+ # Check we have removed the values.
+ shares_private = self.get_users_who_share_private_rooms()
+ public_users = self.get_users_in_public_rooms()
+
+ self.assertEqual(self._compress_shared(shares_private), set())
+ self.assertEqual(public_users, [])
+
+ # User1 now gets no search results for any of the other users.
+ s = self.get_success(self.handler.search_users(u1, "user2", 10))
+ self.assertEqual(len(s["results"]), 0)
+
+ s = self.get_success(self.handler.search_users(u1, "user3", 10))
+ self.assertEqual(len(s["results"]), 0)
+
+ def _compress_shared(self, shared):
+ """
+ Compress a list of users who share rooms dicts to a list of tuples.
+ """
+ r = set()
+ for i in shared:
+ r.add((i["user_id"], i["other_user_id"], i["room_id"]))
+ return r
+
+ def get_users_in_public_rooms(self):
+ r = self.get_success(
+ self.store._simple_select_list(
+ "users_in_public_rooms", None, ("user_id", "room_id")
+ )
+ )
+ retval = []
+ for i in r:
+ retval.append((i["user_id"], i["room_id"]))
+ return retval
+
+ def get_users_who_share_private_rooms(self):
+ return self.get_success(
+ self.store._simple_select_list(
+ "users_who_share_private_rooms",
+ None,
+ ["user_id", "other_user_id", "room_id"],
+ )
+ )
+
+ def _add_background_updates(self):
+ """
+ Add the background updates we need to run.
+ """
+ # Ugh, have to reset this flag
+ self.store._all_done = False
+
+ self.get_success(
+ self.store._simple_insert(
+ "background_updates",
+ {
+ "update_name": "populate_user_directory_createtables",
+ "progress_json": "{}",
+ },
+ )
+ )
+ self.get_success(
+ self.store._simple_insert(
+ "background_updates",
+ {
+ "update_name": "populate_user_directory_process_rooms",
+ "progress_json": "{}",
+ "depends_on": "populate_user_directory_createtables",
+ },
+ )
+ )
+ self.get_success(
+ self.store._simple_insert(
+ "background_updates",
+ {
+ "update_name": "populate_user_directory_process_users",
+ "progress_json": "{}",
+ "depends_on": "populate_user_directory_process_rooms",
+ },
+ )
+ )
+ self.get_success(
+ self.store._simple_insert(
+ "background_updates",
+ {
+ "update_name": "populate_user_directory_cleanup",
+ "progress_json": "{}",
+ "depends_on": "populate_user_directory_process_users",
+ },
+ )
+ )
+
+ def test_initial(self):
+ """
+ The user directory's initial handler correctly updates the search tables.
+ """
+ u1 = self.register_user("user1", "pass")
+ u1_token = self.login(u1, "pass")
+ u2 = self.register_user("user2", "pass")
+ u2_token = self.login(u2, "pass")
+ u3 = self.register_user("user3", "pass")
+ u3_token = self.login(u3, "pass")
+
+ room = self.helper.create_room_as(u1, is_public=True, tok=u1_token)
+ self.helper.invite(room, src=u1, targ=u2, tok=u1_token)
+ self.helper.join(room, user=u2, tok=u2_token)
+
+ private_room = self.helper.create_room_as(u1, is_public=False, tok=u1_token)
+ self.helper.invite(private_room, src=u1, targ=u3, tok=u1_token)
+ self.helper.join(private_room, user=u3, tok=u3_token)
+
+ self.get_success(self.store.update_user_directory_stream_pos(None))
+ self.get_success(self.store.delete_all_from_user_dir())
+
+ shares_private = self.get_users_who_share_private_rooms()
+ public_users = self.get_users_in_public_rooms()
+
+ # Nothing updated yet
+ self.assertEqual(shares_private, [])
+ self.assertEqual(public_users, [])
+
+ # Do the initial population of the user directory via the background update
+ self._add_background_updates()
+
+ while not self.get_success(self.store.has_completed_background_updates()):
+ self.get_success(self.store.do_next_background_update(100), by=0.1)
+
+ shares_private = self.get_users_who_share_private_rooms()
+ public_users = self.get_users_in_public_rooms()
+
+ # User 1 and User 2 are in the same public room
+ self.assertEqual(set(public_users), set([(u1, room), (u2, room)]))
+
+ # User 1 and User 3 share private rooms
+ self.assertEqual(
+ self._compress_shared(shares_private),
+ set([(u1, u3, private_room), (u3, u1, private_room)]),
+ )
+
+ def test_initial_share_all_users(self):
+ """
+ Search all users = True means that a user does not have to share a
+ private room with the searching user or be in a public room to be search
+ visible.
+ """
+ self.handler.search_all_users = True
+ self.hs.config.user_directory_search_all_users = True
+
+ u1 = self.register_user("user1", "pass")
+ self.register_user("user2", "pass")
+ u3 = self.register_user("user3", "pass")
+
+ # Wipe the user dir
+ self.get_success(self.store.update_user_directory_stream_pos(None))
+ self.get_success(self.store.delete_all_from_user_dir())
+
+ # Do the initial population of the user directory via the background update
+ self._add_background_updates()
+
+ while not self.get_success(self.store.has_completed_background_updates()):
+ self.get_success(self.store.do_next_background_update(100), by=0.1)
+
+ shares_private = self.get_users_who_share_private_rooms()
+ public_users = self.get_users_in_public_rooms()
+
+ # No users share rooms
+ self.assertEqual(public_users, [])
+ self.assertEqual(self._compress_shared(shares_private), set([]))
+
+ # Despite not sharing a room, search_all_users means we get a search
+ # result.
+ s = self.get_success(self.handler.search_users(u1, u3, 10))
+ self.assertEqual(len(s["results"]), 1)
+
+ # We can find the other two users
+ s = self.get_success(self.handler.search_users(u1, "user", 10))
+ self.assertEqual(len(s["results"]), 2)
+
+ # Registering a user and then searching for them works.
+ u4 = self.register_user("user4", "pass")
+ s = self.get_success(self.handler.search_users(u1, u4, 10))
+ self.assertEqual(len(s["results"]), 1)
+
+
+class TestUserDirSearchDisabled(unittest.HomeserverTestCase):
+ user_id = "@test:test"
+
+ servlets = [
+ user_directory.register_servlets,
+ room.register_servlets,
+ login.register_servlets,
+ admin.register_servlets,
+ ]
+
+ def make_homeserver(self, reactor, clock):
+ config = self.default_config()
+ config.update_user_directory = True
+ hs = self.setup_test_homeserver(config=config)
+
+ self.config = hs.config
+
+ return hs
+
+ def test_disabling_room_list(self):
+ self.config.user_directory_search_enabled = True
+
+ # First we create a room with another user so that user dir is non-empty
+ # for our user
+ self.helper.create_room_as(self.user_id)
+ u2 = self.register_user("user2", "pass")
+ room = self.helper.create_room_as(self.user_id)
+ self.helper.join(room, user=u2)
+
+ # Assert user directory is not empty
+ request, channel = self.make_request(
+ "POST",
+ b"user_directory/search",
+ b'{"search_term":"user2"}',
+ )
+ self.render(request)
+ self.assertEquals(200, channel.code, channel.result)
+ self.assertTrue(len(channel.json_body["results"]) > 0)
+
+ # Disable user directory and check search returns nothing
+ self.config.user_directory_search_enabled = False
+ request, channel = self.make_request(
+ "POST",
+ b"user_directory/search",
+ b'{"search_term":"user2"}',
+ )
+ self.render(request)
+ self.assertEquals(200, channel.code, channel.result)
+ self.assertTrue(len(channel.json_body["results"]) == 0)
|