Implement directory service federation by Federation Queries; avoid local_only hack; add unit tests

This commit is contained in:
Paul "LeoNerd" Evans 2014-08-13 18:03:37 +01:00
parent 7fb93f2a47
commit 3a1cfe18cf
3 changed files with 141 additions and 27 deletions

View file

@ -35,9 +35,11 @@ class DirectoryHandler(BaseHandler):
def __init__(self, hs):
super(DirectoryHandler, self).__init__(hs)
self.hs = hs
self.http_client = hs.get_http_client()
self.clock = hs.get_clock()
self.federation = hs.get_replication_layer()
self.federation.register_query_handler(
"directory", self.on_directory_query
)
@defer.inlineCallbacks
def create_association(self, room_alias, room_id, servers):
@ -58,9 +60,7 @@ class DirectoryHandler(BaseHandler):
)
@defer.inlineCallbacks
def get_association(self, room_alias, local_only=False):
# TODO(erikj): Do auth
def get_association(self, room_alias):
room_id = None
if room_alias.is_mine:
result = yield self.store.get_association_from_room_alias(
@ -70,22 +70,13 @@ class DirectoryHandler(BaseHandler):
if result:
room_id = result.room_id
servers = result.servers
elif not local_only:
path = "%s/ds/room/%s?local_only=1" % (
PREFIX,
urllib.quote(room_alias.to_string())
else:
result = yield self.federation.make_query(
destination=room_alias.domain,
query_type="directory",
args={"room_alias": room_alias.to_string()},
)
result = None
try:
result = yield self.http_client.get_json(
destination=room_alias.domain,
path=path,
)
except:
# TODO(erikj): Handle this better?
logger.exception("Failed to get remote room alias")
if result and "room_id" in result and "servers" in result:
room_id = result["room_id"]
servers = result["servers"]
@ -99,3 +90,20 @@ class DirectoryHandler(BaseHandler):
"servers": servers,
})
return
@defer.inlineCallbacks
def on_directory_query(self, args):
room_alias = self.hs.parse_roomalias(args["room_alias"])
if not room_alias.is_mine:
raise SynapseError(
400, "Room Alias is not hosted on this Home Server"
)
result = yield self.store.get_association_from_room_alias(
room_alias
)
defer.returnValue({
"room_id": result.room_id,
"servers": result.servers,
})

View file

@ -35,16 +35,10 @@ class ClientDirectoryServer(RestServlet):
@defer.inlineCallbacks
def on_GET(self, request, room_alias):
# TODO(erikj): Handle request
local_only = "local_only" in request.args
room_alias = self.hs.parse_roomalias(urllib.unquote(room_alias))
dir_handler = self.handlers.directory_handler
res = yield dir_handler.get_association(
room_alias,
local_only=local_only
)
res = yield dir_handler.get_association(room_alias)
defer.returnValue((200, res))

View file

@ -0,0 +1,112 @@
# -*- 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
import logging
from synapse.server import HomeServer
from synapse.handlers.directory import DirectoryHandler
from synapse.storage.directory import RoomAliasMapping
logging.getLogger().addHandler(logging.NullHandler())
class DirectoryHandlers(object):
def __init__(self, hs):
self.directory_handler = DirectoryHandler(hs)
class DirectoryTestCase(unittest.TestCase):
""" Tests the directory service. """
def setUp(self):
self.mock_federation = Mock(spec=[
"make_query",
])
self.query_handlers = {}
def register_query_handler(query_type, handler):
self.query_handlers[query_type] = handler
self.mock_federation.register_query_handler = register_query_handler
hs = HomeServer("test",
datastore=Mock(spec=[
"get_association_from_room_alias",
]),
http_client=None,
http_server=Mock(),
replication_layer=self.mock_federation,
)
hs.handlers = DirectoryHandlers(hs)
self.handler = hs.get_handlers().directory_handler
self.datastore = hs.get_datastore()
self.my_room = hs.parse_roomalias("#my-room:test")
self.remote_room = hs.parse_roomalias("#another:remote")
@defer.inlineCallbacks
def test_get_local_association(self):
mocked_get = self.datastore.get_association_from_room_alias
mocked_get.return_value = defer.succeed(
RoomAliasMapping("!8765qwer:test", "#my-room:test", ["test"])
)
result = yield self.handler.get_association(self.my_room)
self.assertEquals({
"room_id": "!8765qwer:test",
"servers": ["test"],
}, result)
@defer.inlineCallbacks
def test_get_remote_association(self):
self.mock_federation.make_query.return_value = defer.succeed(
{"room_id": "!8765qwer:test", "servers": ["test", "remote"]}
)
result = yield self.handler.get_association(self.remote_room)
self.assertEquals({
"room_id": "!8765qwer:test",
"servers": ["test", "remote"],
}, result)
self.mock_federation.make_query.assert_called_with(
destination="remote",
query_type="directory",
args={"room_alias": "#another:remote"}
)
@defer.inlineCallbacks
def test_incoming_fed_query(self):
mocked_get = self.datastore.get_association_from_room_alias
mocked_get.return_value = defer.succeed(
RoomAliasMapping("!8765asdf:test", "#your-room:test", ["test"])
)
response = yield self.query_handlers["directory"](
{"room_alias": "#your-room:test"}
)
self.assertEquals({
"room_id": "!8765asdf:test",
"servers": ["test"],
}, response)