Merge branch 'develop' into storage_transactions

This commit is contained in:
Mark Haines 2014-08-27 16:54:12 +01:00
commit 1d95e78759
34 changed files with 1414 additions and 865 deletions

View file

@ -0,0 +1,250 @@
# -*- 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.
from twisted.trial import unittest
from twisted.internet import defer
from mock import Mock, call, ANY
import json
import logging
from ..utils import MockHttpResource, MockClock, DeferredMockCallable
from synapse.server import HomeServer
from synapse.handlers.typing import TypingNotificationHandler
logging.getLogger().addHandler(logging.NullHandler())
def _expect_edu(destination, edu_type, content, origin="test"):
return {
"origin": origin,
"ts": 1000000,
"pdus": [],
"edus": [
{
"origin": origin,
"destination": destination,
"edu_type": edu_type,
"content": content,
}
],
}
def _make_edu_json(origin, edu_type, content):
return json.dumps(_expect_edu("test", edu_type, content, origin=origin))
class JustTypingNotificationHandlers(object):
def __init__(self, hs):
self.typing_notification_handler = TypingNotificationHandler(hs)
class TypingNotificationsTestCase(unittest.TestCase):
"""Tests typing notifications to rooms."""
def setUp(self):
self.clock = MockClock()
self.mock_http_client = Mock(spec=[])
self.mock_http_client.put_json = DeferredMockCallable()
self.mock_federation_resource = MockHttpResource()
hs = HomeServer("test",
clock=self.clock,
db_pool=None,
datastore=Mock(spec=[
# Bits that Federation needs
"prep_send_transaction",
"delivered_txn",
"get_received_txn_response",
"set_received_txn_response",
]),
handlers=None,
resource_for_client=Mock(),
resource_for_federation=self.mock_federation_resource,
http_client=self.mock_http_client,
)
hs.handlers = JustTypingNotificationHandlers(hs)
self.mock_update_client = Mock()
self.mock_update_client.return_value = defer.succeed(None)
self.handler = hs.get_handlers().typing_notification_handler
self.handler.push_update_to_clients = self.mock_update_client
self.datastore = hs.get_datastore()
def get_received_txn_response(*args):
return defer.succeed(None)
self.datastore.get_received_txn_response = get_received_txn_response
self.room_id = "a-room"
# Mock the RoomMemberHandler
hs.handlers.room_member_handler = Mock(spec=[])
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([self.room_id])
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 == self.room_id:
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)
# Some local users to test with
self.u_apple = hs.parse_userid("@apple:test")
self.u_banana = hs.parse_userid("@banana:test")
# Remote user
self.u_onion = hs.parse_userid("@onion:farm")
@defer.inlineCallbacks
def test_started_typing_local(self):
self.room_members = [self.u_apple, self.u_banana]
yield self.handler.started_typing(
target_user=self.u_apple,
auth_user=self.u_apple,
room_id=self.room_id,
timeout=20000,
)
self.mock_update_client.assert_has_calls([
call(observer_user=self.u_banana,
observed_user=self.u_apple,
room_id=self.room_id,
typing=True),
])
@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("farm", "m.typing",
content={
"room_id": self.room_id,
"user_id": self.u_apple.to_string(),
"typing": True,
}
)
),
defer.succeed((200, "OK"))
)
yield self.handler.started_typing(
target_user=self.u_apple,
auth_user=self.u_apple,
room_id=self.room_id,
timeout=20000,
)
yield put_json.await_calls()
@defer.inlineCallbacks
def test_started_typing_remote_recv(self):
self.room_members = [self.u_apple, self.u_onion]
yield self.mock_federation_resource.trigger("PUT",
"/matrix/federation/v1/send/1000000/",
_make_edu_json("farm", "m.typing",
content={
"room_id": self.room_id,
"user_id": self.u_onion.to_string(),
"typing": True,
}
)
)
self.mock_update_client.assert_has_calls([
call(observer_user=self.u_apple,
observed_user=self.u_onion,
room_id=self.room_id,
typing=True),
])
@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("farm", "m.typing",
content={
"room_id": self.room_id,
"user_id": self.u_apple.to_string(),
"typing": False,
}
)
),
defer.succeed((200, "OK"))
)
# Gut-wrenching
from synapse.handlers.typing import RoomMember
self.handler._member_typing_until[
RoomMember(self.room_id, self.u_apple)
] = 1002000
yield self.handler.stopped_typing(
target_user=self.u_apple,
auth_user=self.u_apple,
room_id=self.room_id,
)
self.mock_update_client.assert_has_calls([
call(observer_user=self.u_banana,
observed_user=self.u_apple,
room_id=self.room_id,
typing=False),
])
yield put_json.await_calls()

View file

@ -179,9 +179,8 @@ class EventStreamPermissionsTestCase(RestTestCase):
@defer.inlineCallbacks
def test_stream_room_permissions(self):
room_id = "!rid1:test"
yield self.create_room_as(room_id, self.other_user,
tok=self.other_token)
room_id = yield self.create_room_as(self.other_user,
tok=self.other_token)
yield self.send(room_id, tok=self.other_token)
# invited to room (expect no content for room)

View file

@ -171,7 +171,7 @@ class PresenceListTestCase(unittest.TestCase):
)
(code, response) = yield self.mock_resource.trigger("GET",
"/presence_list/%s" % (myid), None)
"/presence/list/%s" % (myid), None)
self.assertEquals(200, code)
self.assertEquals(
@ -192,7 +192,7 @@ class PresenceListTestCase(unittest.TestCase):
)
(code, response) = yield self.mock_resource.trigger("POST",
"/presence_list/%s" % (myid),
"/presence/list/%s" % (myid),
"""{"invite": ["@banana:test"]}"""
)
@ -212,7 +212,7 @@ class PresenceListTestCase(unittest.TestCase):
)
(code, response) = yield self.mock_resource.trigger("POST",
"/presence_list/%s" % (myid),
"/presence/list/%s" % (myid),
"""{"drop": ["@banana:test"]}"""
)

View file

@ -74,13 +74,11 @@ class RoomPermissionsTestCase(RestTestCase):
# create some rooms under the name rmcreator_id
self.uncreated_rmid = "!aa:test"
self.created_rmid = "!abc:test"
yield self.create_room_as(self.created_rmid, self.rmcreator_id,
is_public=False)
self.created_rmid = yield self.create_room_as(self.rmcreator_id,
is_public=False)
self.created_public_rmid = "!def1234ghi:test"
yield self.create_room_as(self.created_public_rmid, self.rmcreator_id,
is_public=True)
self.created_public_rmid = yield self.create_room_as(self.rmcreator_id,
is_public=True)
# send a message in one of the rooms
self.created_rmid_msg_path = ("/rooms/%s/send/m.room.message/a1" %
@ -423,8 +421,7 @@ class RoomsMemberListTestCase(RestTestCase):
@defer.inlineCallbacks
def test_get_member_list(self):
room_id = "!aa:test"
yield self.create_room_as(room_id, self.user_id)
room_id = yield self.create_room_as(self.user_id)
(code, response) = yield self.mock_resource.trigger_get(
"/rooms/%s/members" % room_id)
self.assertEquals(200, code, msg=str(response))
@ -437,18 +434,16 @@ class RoomsMemberListTestCase(RestTestCase):
@defer.inlineCallbacks
def test_get_member_list_no_permission(self):
room_id = "!bb:test"
yield self.create_room_as(room_id, "@some_other_guy:red")
room_id = yield self.create_room_as("@some_other_guy:red")
(code, response) = yield self.mock_resource.trigger_get(
"/rooms/%s/members" % room_id)
self.assertEquals(403, code, msg=str(response))
@defer.inlineCallbacks
def test_get_member_list_mixed_memberships(self):
room_id = "!bb:test"
room_creator = "@some_other_guy:blue"
room_id = yield self.create_room_as(room_creator)
room_path = "/rooms/%s/members" % room_id
yield self.create_room_as(room_id, room_creator)
yield self.invite(room=room_id, src=room_creator,
targ=self.user_id)
# can't see list if you're just invited.
@ -503,107 +498,57 @@ class RoomsCreateTestCase(RestTestCase):
@defer.inlineCallbacks
def test_post_room_no_keys(self):
# POST with no config keys, expect new room id
(code, response) = yield self.mock_resource.trigger("POST", "/rooms",
"{}")
(code, response) = yield self.mock_resource.trigger("POST",
"/createRoom",
"{}")
self.assertEquals(200, code, response)
self.assertTrue("room_id" in response)
@defer.inlineCallbacks
def test_post_room_visibility_key(self):
# POST with visibility config key, expect new room id
(code, response) = yield self.mock_resource.trigger("POST", "/rooms",
'{"visibility":"private"}')
(code, response) = yield self.mock_resource.trigger(
"POST",
"/createRoom",
'{"visibility":"private"}')
self.assertEquals(200, code)
self.assertTrue("room_id" in response)
@defer.inlineCallbacks
def test_post_room_custom_key(self):
# POST with custom config keys, expect new room id
(code, response) = yield self.mock_resource.trigger("POST", "/rooms",
'{"custom":"stuff"}')
(code, response) = yield self.mock_resource.trigger(
"POST",
"/createRoom",
'{"custom":"stuff"}')
self.assertEquals(200, code)
self.assertTrue("room_id" in response)
@defer.inlineCallbacks
def test_post_room_known_and_unknown_keys(self):
# POST with custom + known config keys, expect new room id
(code, response) = yield self.mock_resource.trigger("POST", "/rooms",
'{"visibility":"private","custom":"things"}')
(code, response) = yield self.mock_resource.trigger(
"POST",
"/createRoom",
'{"visibility":"private","custom":"things"}')
self.assertEquals(200, code)
self.assertTrue("room_id" in response)
@defer.inlineCallbacks
def test_post_room_invalid_content(self):
# POST with invalid content / paths, expect 400
(code, response) = yield self.mock_resource.trigger("POST", "/rooms",
'{"visibili')
self.assertEquals(400, code)
(code, response) = yield self.mock_resource.trigger("POST", "/rooms",
'["hello"]')
self.assertEquals(400, code)
@defer.inlineCallbacks
def test_put_room_no_keys(self):
# PUT with no config keys, expect new room id
(code, response) = yield self.mock_resource.trigger(
"PUT", "/rooms/%21aa%3Atest", "{}"
)
self.assertEquals(200, code)
self.assertTrue("room_id" in response)
@defer.inlineCallbacks
def test_put_room_visibility_key(self):
# PUT with known config keys, expect new room id
(code, response) = yield self.mock_resource.trigger(
"PUT", "/rooms/%21bb%3Atest", '{"visibility":"private"}'
)
self.assertEquals(200, code)
self.assertTrue("room_id" in response)
@defer.inlineCallbacks
def test_put_room_custom_key(self):
# PUT with custom config keys, expect new room id
(code, response) = yield self.mock_resource.trigger(
"PUT", "/rooms/%21cc%3Atest", '{"custom":"stuff"}'
)
self.assertEquals(200, code)
self.assertTrue("room_id" in response)
@defer.inlineCallbacks
def test_put_room_known_and_unknown_keys(self):
# PUT with custom + known config keys, expect new room id
(code, response) = yield self.mock_resource.trigger(
"PUT", "/rooms/%21dd%3Atest",
'{"visibility":"private","custom":"things"}'
)
self.assertEquals(200, code)
self.assertTrue("room_id" in response)
@defer.inlineCallbacks
def test_put_room_invalid_content(self):
# PUT with invalid content / room names, expect 400
(code, response) = yield self.mock_resource.trigger(
"PUT", "/rooms/ee", '{"sdf"'
)
"POST",
"/createRoom",
'{"visibili')
self.assertEquals(400, code)
(code, response) = yield self.mock_resource.trigger(
"PUT", "/rooms/ee", '["hello"]'
)
"POST",
"/createRoom",
'["hello"]')
self.assertEquals(400, code)
@defer.inlineCallbacks
def test_put_room_conflict(self):
yield self.create_room_as("!aa:test", self.user_id)
# PUT with conflicting room ID, expect 409
(code, response) = yield self.mock_resource.trigger(
"PUT", "/rooms/%21aa%3Atest", "{}"
)
self.assertEquals(409, code)
class RoomTopicTestCase(RestTestCase):
""" Tests /rooms/$room_id/topic REST events. """
@ -613,8 +558,6 @@ class RoomTopicTestCase(RestTestCase):
def setUp(self):
self.mock_resource = MockHttpResource(prefix=PATH_PREFIX)
self.auth_user_id = self.user_id
self.room_id = "!rid1:test"
self.path = "/rooms/%s/state/m.room.topic" % self.room_id
state_handler = Mock(spec=["handle_new_event"])
state_handler.handle_new_event.return_value = True
@ -640,7 +583,8 @@ class RoomTopicTestCase(RestTestCase):
synapse.rest.room.register_servlets(hs, self.mock_resource)
# create the room
yield self.create_room_as(self.room_id, self.user_id)
self.room_id = yield self.create_room_as(self.user_id)
self.path = "/rooms/%s/state/m.room.topic" % self.room_id
def tearDown(self):
pass
@ -717,7 +661,6 @@ class RoomMemberStateTestCase(RestTestCase):
def setUp(self):
self.mock_resource = MockHttpResource(prefix=PATH_PREFIX)
self.auth_user_id = self.user_id
self.room_id = "!rid1:test"
state_handler = Mock(spec=["handle_new_event"])
state_handler.handle_new_event.return_value = True
@ -742,7 +685,7 @@ class RoomMemberStateTestCase(RestTestCase):
synapse.rest.room.register_servlets(hs, self.mock_resource)
yield self.create_room_as(self.room_id, self.user_id)
self.room_id = yield self.create_room_as(self.user_id)
def tearDown(self):
pass
@ -843,7 +786,6 @@ class RoomMessagesTestCase(RestTestCase):
def setUp(self):
self.mock_resource = MockHttpResource(prefix=PATH_PREFIX)
self.auth_user_id = self.user_id
self.room_id = "!rid1:test"
state_handler = Mock(spec=["handle_new_event"])
state_handler.handle_new_event.return_value = True
@ -868,7 +810,7 @@ class RoomMessagesTestCase(RestTestCase):
synapse.rest.room.register_servlets(hs, self.mock_resource)
yield self.create_room_as(self.room_id, self.user_id)
self.room_id = yield self.create_room_as(self.user_id)
def tearDown(self):
pass

View file

@ -24,6 +24,7 @@ from synapse.api.constants import Membership
import json
import time
class RestTestCase(unittest.TestCase):
"""Contains extra helper functions to quickly and clearly perform a given
REST action, which isn't the focus of the test.
@ -40,18 +41,19 @@ class RestTestCase(unittest.TestCase):
return self.auth_user_id
@defer.inlineCallbacks
def create_room_as(self, room_id, room_creator, is_public=True, tok=None):
def create_room_as(self, room_creator, is_public=True, tok=None):
temp_id = self.auth_user_id
self.auth_user_id = room_creator
path = "/rooms/%s" % room_id
path = "/createRoom"
content = "{}"
if not is_public:
content = '{"visibility":"private"}'
if tok:
path = path + "?access_token=%s" % tok
(code, response) = yield self.mock_resource.trigger("PUT", path, content)
(code, response) = yield self.mock_resource.trigger("POST", path, content)
self.assertEquals(200, code, msg=str(response))
self.auth_user_id = temp_id
defer.returnValue(response["room_id"])
@defer.inlineCallbacks
def invite(self, room=None, src=None, targ=None, expect_code=200, tok=None):