mirror of git://git.psyced.org/git/pypsyc
354 lines
14 KiB
Python
354 lines
14 KiB
Python
|
"""
|
||
|
:copyright: 2010 by Manuel Jacob
|
||
|
:license: MIT
|
||
|
"""
|
||
|
from mock import Mock
|
||
|
from nose.tools import assert_raises
|
||
|
from tests.constants import (SERVER1, SERVER2, SERVER1_UNI, SERVER2_UNI,
|
||
|
SERVER3_UNI, USER1, USER2, USER1_UNI, USER2_UNI, RESOURCE, RESOURCE1_UNI,
|
||
|
RESOURCE2_UNI, PLACE_UNI, INTERFACE, IP, PORT, CONTENT)
|
||
|
from tests.helpers import (inited_header, connect_circuits, mockified,
|
||
|
AsyncMethod, PlaceHolder)
|
||
|
|
||
|
from pypsyc.core.mmp import Uni
|
||
|
from pypsyc.protocol import Error
|
||
|
from pypsyc.server.routing import (InvalidTargetError, InvalidSourceError,
|
||
|
ServerCircuit, _TreeNode, Routing)
|
||
|
from pypsyc.util import DNSError
|
||
|
|
||
|
|
||
|
class TestServerCircuit(object):
|
||
|
def setup(self):
|
||
|
self.sc = ServerCircuit()
|
||
|
self.sc.factory = self.routing = Mock()
|
||
|
self.sc.psyc = Mock()
|
||
|
self.sc.allowed_sources.append(SERVER2_UNI)
|
||
|
|
||
|
def _send(self, header):
|
||
|
self.sc.packet_received(inited_header(header), CONTENT)
|
||
|
|
||
|
def test_withtarget(self):
|
||
|
HEADER1 = {'_target': SERVER1_UNI}
|
||
|
HEADER2 = {'_target': SERVER1_UNI, '_source': SERVER2_UNI}
|
||
|
HEADER3 = {'_target': SERVER1_UNI, '_source': SERVER3_UNI}
|
||
|
|
||
|
self._send(HEADER1)
|
||
|
assert self.routing.method_calls == [
|
||
|
('route_singlecast', (HEADER1, CONTENT))]
|
||
|
|
||
|
self._send(HEADER2)
|
||
|
assert self.routing.method_calls == [
|
||
|
('route_singlecast', (HEADER1, CONTENT)),
|
||
|
('route_singlecast', (HEADER2, CONTENT))]
|
||
|
|
||
|
self._send(HEADER3)
|
||
|
assert self.routing.method_calls == [
|
||
|
('route_singlecast', (HEADER1, CONTENT)),
|
||
|
('route_singlecast', (HEADER2, CONTENT))]
|
||
|
|
||
|
def test_withouttarget(self):
|
||
|
HEADER1 = {}
|
||
|
HEADER2 = {'_source': SERVER2_UNI}
|
||
|
HEADER3 = {'_source': SERVER3_UNI}
|
||
|
|
||
|
self._send(HEADER1)
|
||
|
assert self.routing.method_calls == []
|
||
|
assert self.sc.psyc.method_calls == [
|
||
|
('handle_packet', (HEADER1, CONTENT))]
|
||
|
|
||
|
self._send(HEADER2)
|
||
|
assert self.routing.method_calls == []
|
||
|
assert self.sc.psyc.method_calls == [
|
||
|
('handle_packet', (HEADER1, CONTENT)),
|
||
|
('handle_packet', (HEADER2, CONTENT))]
|
||
|
|
||
|
self._send(HEADER3)
|
||
|
assert self.routing.method_calls == []
|
||
|
assert self.sc.psyc.method_calls == [
|
||
|
('handle_packet', (HEADER1, CONTENT)),
|
||
|
('handle_packet', (HEADER2, CONTENT))]
|
||
|
|
||
|
def test_context(self):
|
||
|
HEADER1 = {'_context': PLACE_UNI}
|
||
|
HEADER2 = {'_context': PLACE_UNI, '_target': USER1_UNI}
|
||
|
|
||
|
self._send(HEADER1)
|
||
|
assert self.routing.method_calls == [
|
||
|
('route_multicast', (HEADER1, CONTENT))]
|
||
|
|
||
|
self._send(HEADER2)
|
||
|
assert self.routing.method_calls == [
|
||
|
('route_multicast', (HEADER1, CONTENT)),
|
||
|
('route_singlecast', (HEADER2, CONTENT))]
|
||
|
|
||
|
def test_context_withsource(self):
|
||
|
HEADER1 = {'_context': PLACE_UNI, '_source': USER1_UNI}
|
||
|
HEADER2 = {'_context': PLACE_UNI, '_source': USER2_UNI,
|
||
|
'_target': USER1_UNI}
|
||
|
|
||
|
assert_raises(NotImplementedError, self._send, HEADER1)
|
||
|
assert self.routing.method_calls == []
|
||
|
|
||
|
assert_raises(NotImplementedError, self._send, HEADER2)
|
||
|
assert self.routing.method_calls == []
|
||
|
|
||
|
def test_verification(self):
|
||
|
sc1, sc2 = connect_circuits(ServerCircuit(), ServerCircuit())
|
||
|
sc2.factory = Mock()
|
||
|
|
||
|
sc1.request_verification(SERVER1_UNI, SERVER2_UNI)
|
||
|
assert sc2.factory.method_calls == [
|
||
|
('verify_address', (sc2, SERVER1_UNI, SERVER2_UNI))]
|
||
|
assert type(sc2.factory.method_calls[0][1][1]) is Uni
|
||
|
assert sc1.allowed_sources == [SERVER2_UNI]
|
||
|
assert sc2.allowed_sources == [SERVER1_UNI]
|
||
|
assert type(sc2.allowed_sources[0]) is Uni
|
||
|
|
||
|
def test_verification_invalid_source(self):
|
||
|
sc1, sc2 = connect_circuits(ServerCircuit(), ServerCircuit())
|
||
|
sc2.factory = Mock()
|
||
|
sc2.factory.verify_address.side_effect = InvalidSourceError
|
||
|
|
||
|
assert_raises(InvalidSourceError, sc1.request_verification,
|
||
|
SERVER1_UNI, SERVER2_UNI)
|
||
|
assert sc1.allowed_sources == []
|
||
|
assert sc2.allowed_sources == []
|
||
|
|
||
|
def test_verification_invalid_target(self):
|
||
|
sc1, sc2 = connect_circuits(ServerCircuit(), ServerCircuit())
|
||
|
sc2.factory = Mock()
|
||
|
sc2.factory.verify_address.side_effect = InvalidTargetError
|
||
|
|
||
|
assert_raises(InvalidTargetError, sc1.request_verification,
|
||
|
SERVER1_UNI, SERVER2_UNI)
|
||
|
assert sc1.allowed_sources == []
|
||
|
assert sc2.allowed_sources == []
|
||
|
|
||
|
def test_connection_lost(self):
|
||
|
root = self.routing.root = _TreeNode()
|
||
|
person = Mock()
|
||
|
person_entity = _TreeNode(root, USER1)
|
||
|
person_entity.packages = {'person': person}
|
||
|
self.sc.allowed_sources.append(RESOURCE1_UNI)
|
||
|
|
||
|
self.routing.srouting_table = {SERVER2: Mock()}
|
||
|
self.sc.connectionLost(None)
|
||
|
assert self.routing.srouting_table == {}
|
||
|
assert person.method_calls == [('unlink', (RESOURCE,))]
|
||
|
|
||
|
|
||
|
def test_treenode():
|
||
|
root = _TreeNode()
|
||
|
assert root._root == root
|
||
|
|
||
|
n1 = _TreeNode(root, 'n1')
|
||
|
assert root.children == {'n1': n1}
|
||
|
assert n1._parent == root
|
||
|
assert n1._root == root
|
||
|
|
||
|
n2 = _TreeNode(n1, 'n2')
|
||
|
assert n1.children == {'n2': n2}
|
||
|
assert n2._parent == n1
|
||
|
assert n2._root == root
|
||
|
|
||
|
|
||
|
class StubEntity(_TreeNode):
|
||
|
def __init__(self, *args, **kwds):
|
||
|
_TreeNode.__init__(self, *args, **kwds)
|
||
|
self.headers = []
|
||
|
|
||
|
def handle_packet(self, header, contents):
|
||
|
self.headers.append(header)
|
||
|
|
||
|
EXTERN_HEADER = {'_source': USER1_UNI, '_target': SERVER2_UNI}
|
||
|
|
||
|
class TestRouting(object):
|
||
|
def test_sroute_local(self):
|
||
|
HEADER1 = {'_target': SERVER1_UNI}
|
||
|
HEADER2 = {'_target': USER1_UNI}
|
||
|
HEADER3 = {'_target': RESOURCE2_UNI}
|
||
|
|
||
|
root = StubEntity()
|
||
|
user1 = StubEntity(root, USER1)
|
||
|
user2 = StubEntity(root, USER2)
|
||
|
home = StubEntity(user2, RESOURCE)
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.init(root)
|
||
|
|
||
|
routing.route_singlecast(inited_header(HEADER1), CONTENT)
|
||
|
routing.route_singlecast(inited_header(HEADER2), CONTENT)
|
||
|
routing.route_singlecast(inited_header(HEADER3), CONTENT)
|
||
|
assert root.headers == [HEADER1]
|
||
|
assert user1.headers == [HEADER2]
|
||
|
assert user2.headers == []
|
||
|
assert home.headers == [HEADER3]
|
||
|
|
||
|
def test_sroute_unkown_target(self):
|
||
|
HEADER1 = inited_header({'_source': USER1_UNI, '_target': USER2_UNI})
|
||
|
HEADER2 = inited_header({'_target': USER2_UNI, '_tag': 'tag'})
|
||
|
KWDS = {'mc': '_error_unknown_target', '_uni': USER2_UNI, 'data': None}
|
||
|
|
||
|
root = StubEntity()
|
||
|
root.sendmsg = Mock()
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.init(root)
|
||
|
|
||
|
routing.route_singlecast(HEADER1, CONTENT)
|
||
|
routing.route_singlecast(HEADER2, CONTENT)
|
||
|
assert root.sendmsg.call_args_list == [
|
||
|
((USER1_UNI, None, None), KWDS),
|
||
|
((None, None, {'_tag_relay': 'tag'}), KWDS)]
|
||
|
assert root.headers == []
|
||
|
|
||
|
def test_sroute_extern(self):
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
circuit = routing.srouting_table[SERVER2] = Mock()
|
||
|
|
||
|
routing.route_singlecast(inited_header(EXTERN_HEADER), CONTENT)
|
||
|
assert circuit.method_calls == [(('send'), (EXTERN_HEADER, CONTENT))]
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['resolve_hostname', 'connect'])
|
||
|
def test_sroute_extern_queued(self, resolve_hostname, connect):
|
||
|
resolve_hostname.return_value = IP, PORT
|
||
|
connected = connect.side_effect = AsyncMethod()
|
||
|
root = Mock()
|
||
|
root.uni = SERVER1_UNI
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.init(root)
|
||
|
|
||
|
routing.route_singlecast(inited_header(EXTERN_HEADER), CONTENT)
|
||
|
routing.route_singlecast(inited_header(EXTERN_HEADER), CONTENT)
|
||
|
assert connect.call_args_list == [
|
||
|
((IP, PORT, routing), {'bindAddress': (INTERFACE, 0)})]
|
||
|
|
||
|
circuit = Mock()
|
||
|
connected.callback(circuit)
|
||
|
assert circuit.method_calls == [
|
||
|
('request_verification', (SERVER1_UNI, SERVER2_UNI)),
|
||
|
('send', (EXTERN_HEADER, CONTENT)),
|
||
|
('send', (EXTERN_HEADER, CONTENT))]
|
||
|
assert type(circuit.method_calls[0][1][1]) is Uni
|
||
|
assert routing.srouting_table == {SERVER2: circuit}
|
||
|
assert routing.queues == {}
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['resolve_hostname'])
|
||
|
def test_sroute_extern_resolution_fail(self, resolve_hostname):
|
||
|
KWDS = {'mc': '_failure_unsuccessful_delivery', '_uni': SERVER2_UNI}
|
||
|
resolved = resolve_hostname.side_effect = AsyncMethod()
|
||
|
data_ph = KWDS['data'] = PlaceHolder()
|
||
|
root = Mock()
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.init(root)
|
||
|
|
||
|
routing.route_singlecast(inited_header(EXTERN_HEADER), CONTENT)
|
||
|
routing.route_singlecast(inited_header(EXTERN_HEADER), CONTENT)
|
||
|
resolved.errback(DNSError)
|
||
|
assert root.method_calls == [
|
||
|
('sendmsg', (USER1_UNI, None, None), KWDS)] * 2
|
||
|
assert 'resolve' in data_ph.obj
|
||
|
assert routing.queues == {}
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['resolve_hostname', 'connect'])
|
||
|
def test_sroute_extern_connection_fail(self, resolve_hostname, connect):
|
||
|
KWDS = {'mc': '_failure_unsuccessful_delivery', '_uni': SERVER2_UNI}
|
||
|
resolve_hostname.return_value = None, None
|
||
|
connected = connect.side_effect = AsyncMethod()
|
||
|
data_ph = KWDS['data'] = PlaceHolder()
|
||
|
root = Mock()
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.init(root)
|
||
|
|
||
|
routing.route_singlecast(inited_header(EXTERN_HEADER), CONTENT)
|
||
|
connected.errback(Exception('error'))
|
||
|
assert root.method_calls == [
|
||
|
('sendmsg', (USER1_UNI, None, None), KWDS)]
|
||
|
assert 'connect' in data_ph.obj
|
||
|
assert routing.queues == {}
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['resolve_hostname', 'connect'])
|
||
|
def test_sroute_extern_verification_fail(self, resolve_hostname, connect):
|
||
|
KWDS = {'mc': '_failure_unsuccessful_delivery', '_uni': SERVER2_UNI}
|
||
|
resolve_hostname.return_value = None, None
|
||
|
circuit = connect.return_value
|
||
|
verified = circuit.request_verification.side_effect = AsyncMethod()
|
||
|
data_ph = KWDS['data'] = PlaceHolder()
|
||
|
root = Mock()
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.init(root)
|
||
|
|
||
|
routing.route_singlecast(inited_header(EXTERN_HEADER), CONTENT)
|
||
|
verified.errback(Error)
|
||
|
assert root.method_calls == [
|
||
|
('sendmsg', (USER1_UNI, None, None), KWDS)]
|
||
|
assert 'verify' in data_ph.obj
|
||
|
assert routing.queues == {}
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['resolve_hostname', 'connect'])
|
||
|
def test_sroute_extern_no_source(self, resolve_hostname, connect):
|
||
|
header = inited_header({'_target': SERVER2_UNI})
|
||
|
header.source = Mock()
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
|
||
|
routing.route_singlecast(header, CONTENT)
|
||
|
header['_source'] = ''
|
||
|
routing.route_singlecast(header, CONTENT)
|
||
|
assert resolve_hostname.call_args_list == []
|
||
|
assert connect.call_args_list == []
|
||
|
assert routing.srouting_table == {}
|
||
|
assert routing.queues == {}
|
||
|
|
||
|
def test_mroute(self):
|
||
|
HEADER = {'_context': PLACE_UNI}
|
||
|
circuit1 = Mock()
|
||
|
circuit2 = Mock()
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.mrouting_table[PLACE_UNI] = [circuit1, circuit2]
|
||
|
|
||
|
routing.route_multicast(inited_header(HEADER), iter(CONTENT))
|
||
|
assert circuit1.method_calls == [('send', (HEADER, CONTENT))]
|
||
|
assert circuit2.method_calls == [('send', (HEADER, CONTENT))]
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['reactor'])
|
||
|
def test_listen(self, reactor):
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.listen(PORT)
|
||
|
assert reactor.method_calls == [
|
||
|
('listenTCP', (PORT, routing), {'interface': INTERFACE})]
|
||
|
|
||
|
def _setup_verification(self):
|
||
|
root = Mock()
|
||
|
root.uni = SERVER1_UNI
|
||
|
routing = Routing(SERVER1, INTERFACE)
|
||
|
routing.init(root)
|
||
|
circuit = Mock()
|
||
|
circuit.transport.client = IP, 35771
|
||
|
return routing, circuit
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['resolve_hostname'])
|
||
|
def test_verification(self, resolve_hostname):
|
||
|
resolve_hostname.return_value = IP, PORT
|
||
|
routing, circuit = self._setup_verification()
|
||
|
|
||
|
routing.verify_address(circuit, SERVER2_UNI, SERVER1_UNI)
|
||
|
assert resolve_hostname.call_args_list == [((SERVER2,),)]
|
||
|
assert routing.srouting_table == {SERVER2: circuit}
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['resolve_hostname'])
|
||
|
def test_verification_invalid_target(self, resolve_hostname):
|
||
|
routing, circuit = self._setup_verification()
|
||
|
|
||
|
assert_raises(InvalidTargetError, routing.verify_address,
|
||
|
circuit, SERVER2_UNI, SERVER3_UNI)
|
||
|
assert resolve_hostname.call_args_list == []
|
||
|
assert routing.srouting_table == {}
|
||
|
|
||
|
@mockified('pypsyc.server.routing', ['resolve_hostname'])
|
||
|
def test_verification_invalid_source(self, resolve_hostname):
|
||
|
resolve_hostname.return_value = '10.0.0.2', PORT
|
||
|
routing, circuit = self._setup_verification()
|
||
|
|
||
|
assert_raises(InvalidSourceError, routing.verify_address,
|
||
|
circuit, SERVER2_UNI, SERVER1_UNI)
|
||
|
assert resolve_hostname.call_args_list == [((SERVER2,),)]
|
||
|
assert routing.srouting_table == {}
|