2007-07-24 20:46:06 +00:00
|
|
|
from base64 import b32encode, b32decode
|
2007-03-27 23:12:11 +00:00
|
|
|
|
|
|
|
from twisted.trial import unittest
|
|
|
|
from twisted.internet import defer, reactor
|
|
|
|
from twisted.python import log
|
|
|
|
|
|
|
|
from foolscap import Tub, Referenceable
|
2007-03-28 00:16:13 +00:00
|
|
|
from foolscap.eventual import flushEventualQueue
|
2007-03-27 23:12:11 +00:00
|
|
|
from twisted.application import service
|
|
|
|
from allmydata.introducer import IntroducerClient, Introducer
|
2007-07-24 20:46:06 +00:00
|
|
|
from allmydata.util import testutil
|
2007-03-27 23:12:11 +00:00
|
|
|
|
|
|
|
class MyNode(Referenceable):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class LoggingMultiService(service.MultiService):
|
|
|
|
def log(self, msg):
|
|
|
|
pass
|
|
|
|
|
2007-05-30 00:39:39 +00:00
|
|
|
class TestIntroducer(unittest.TestCase, testutil.PollMixin):
|
2007-03-27 23:12:11 +00:00
|
|
|
def setUp(self):
|
|
|
|
self.parent = LoggingMultiService()
|
|
|
|
self.parent.startService()
|
|
|
|
def tearDown(self):
|
|
|
|
log.msg("TestIntroducer.tearDown")
|
2007-04-04 23:09:13 +00:00
|
|
|
d = defer.succeed(None)
|
2007-03-27 23:12:11 +00:00
|
|
|
d.addCallback(lambda res: self.parent.stopService())
|
2007-03-28 00:16:13 +00:00
|
|
|
d.addCallback(flushEventualQueue)
|
2007-03-27 23:12:11 +00:00
|
|
|
return d
|
|
|
|
|
|
|
|
|
|
|
|
def test_create(self):
|
2007-05-22 21:08:30 +00:00
|
|
|
ic = IntroducerClient(None, "introducer", "myfurl")
|
2007-03-27 23:12:11 +00:00
|
|
|
def _ignore(nodeid, rref):
|
|
|
|
pass
|
2007-05-08 02:10:24 +00:00
|
|
|
ic.notify_on_new_connection(_ignore)
|
2007-03-27 23:12:11 +00:00
|
|
|
|
|
|
|
def test_listen(self):
|
|
|
|
i = Introducer()
|
|
|
|
i.setServiceParent(self.parent)
|
|
|
|
|
|
|
|
def test_system(self):
|
|
|
|
|
|
|
|
self.central_tub = tub = Tub()
|
|
|
|
#tub.setOption("logLocalFailures", True)
|
|
|
|
#tub.setOption("logRemoteFailures", True)
|
|
|
|
tub.setServiceParent(self.parent)
|
|
|
|
l = tub.listenOn("tcp:0")
|
|
|
|
portnum = l.getPortnum()
|
|
|
|
tub.setLocation("localhost:%d" % portnum)
|
|
|
|
|
|
|
|
i = Introducer()
|
|
|
|
i.setServiceParent(self.parent)
|
|
|
|
iurl = tub.registerReference(i)
|
|
|
|
NUMCLIENTS = 5
|
|
|
|
|
|
|
|
self.waiting_for_connections = NUMCLIENTS*NUMCLIENTS
|
|
|
|
d = self._done_counting = defer.Deferred()
|
2007-05-08 02:10:24 +00:00
|
|
|
def _count(nodeid, rref):
|
2007-07-24 20:46:06 +00:00
|
|
|
log.msg("NEW CONNECTION! %s %s" % (b32encode(nodeid).lower(), rref))
|
2007-05-08 02:10:24 +00:00
|
|
|
self.waiting_for_connections -= 1
|
|
|
|
if self.waiting_for_connections == 0:
|
|
|
|
self._done_counting.callback("done!")
|
2007-03-27 23:12:11 +00:00
|
|
|
|
|
|
|
clients = []
|
|
|
|
tubs = {}
|
|
|
|
for i in range(NUMCLIENTS):
|
|
|
|
tub = Tub()
|
|
|
|
#tub.setOption("logLocalFailures", True)
|
|
|
|
#tub.setOption("logRemoteFailures", True)
|
|
|
|
tub.setServiceParent(self.parent)
|
|
|
|
l = tub.listenOn("tcp:0")
|
|
|
|
portnum = l.getPortnum()
|
|
|
|
tub.setLocation("localhost:%d" % portnum)
|
|
|
|
|
|
|
|
n = MyNode()
|
2007-05-22 21:08:30 +00:00
|
|
|
node_furl = tub.registerReference(n)
|
|
|
|
c = IntroducerClient(tub, iurl, node_furl)
|
2007-05-08 02:10:24 +00:00
|
|
|
c.notify_on_new_connection(_count)
|
2007-03-27 23:12:11 +00:00
|
|
|
c.setServiceParent(self.parent)
|
|
|
|
clients.append(c)
|
|
|
|
tubs[c] = tub
|
|
|
|
|
|
|
|
# d will fire once everybody is connected
|
|
|
|
|
|
|
|
def _check(res):
|
|
|
|
log.msg("doing _check")
|
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), NUMCLIENTS)
|
2007-05-08 02:10:24 +00:00
|
|
|
# now disconnect somebody's connection to someone else
|
2007-03-27 23:12:11 +00:00
|
|
|
self.waiting_for_connections = 2
|
|
|
|
d2 = self._done_counting = defer.Deferred()
|
|
|
|
origin_c = clients[0]
|
|
|
|
# find a target that is not themselves
|
|
|
|
for nodeid,rref in origin_c.connections.items():
|
2007-07-24 20:46:06 +00:00
|
|
|
if b32encode(nodeid).lower() != tubs[origin_c].tubID:
|
2007-03-27 23:12:11 +00:00
|
|
|
victim = rref
|
|
|
|
break
|
|
|
|
log.msg(" disconnecting %s->%s" % (tubs[origin_c].tubID, victim))
|
|
|
|
victim.tracker.broker.transport.loseConnection()
|
|
|
|
log.msg(" did disconnect")
|
|
|
|
return d2
|
|
|
|
d.addCallback(_check)
|
|
|
|
def _check_again(res):
|
|
|
|
log.msg("doing _check_again")
|
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), NUMCLIENTS)
|
2007-05-08 02:10:24 +00:00
|
|
|
# now disconnect somebody's connection to themselves. This will
|
|
|
|
# only result in one new connection, since it is a loopback.
|
2007-03-27 23:12:11 +00:00
|
|
|
self.waiting_for_connections = 1
|
|
|
|
d2 = self._done_counting = defer.Deferred()
|
|
|
|
origin_c = clients[0]
|
|
|
|
# find a target that *is* themselves
|
|
|
|
for nodeid,rref in origin_c.connections.items():
|
2007-07-24 20:46:06 +00:00
|
|
|
if b32encode(nodeid).lower() == tubs[origin_c].tubID:
|
2007-03-27 23:12:11 +00:00
|
|
|
victim = rref
|
|
|
|
break
|
|
|
|
log.msg(" disconnecting %s->%s" % (tubs[origin_c].tubID, victim))
|
|
|
|
victim.tracker.broker.transport.loseConnection()
|
|
|
|
log.msg(" did disconnect")
|
|
|
|
return d2
|
|
|
|
d.addCallback(_check_again)
|
|
|
|
def _check_again2(res):
|
|
|
|
log.msg("doing _check_again2")
|
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), NUMCLIENTS)
|
2007-05-08 02:10:24 +00:00
|
|
|
# now disconnect somebody's connection to themselves
|
2007-03-27 23:12:11 +00:00
|
|
|
d.addCallback(_check_again2)
|
|
|
|
return d
|
2007-05-01 06:16:06 +00:00
|
|
|
test_system.timeout = 2400
|
2007-03-27 23:12:11 +00:00
|
|
|
|
|
|
|
def stall(self, res, timeout):
|
|
|
|
d = defer.Deferred()
|
|
|
|
reactor.callLater(timeout, d.callback, res)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def test_system_this_one_breaks(self):
|
|
|
|
# this uses a single Tub, which has a strong effect on the
|
|
|
|
# failingness
|
|
|
|
tub = Tub()
|
|
|
|
tub.setOption("logLocalFailures", True)
|
|
|
|
tub.setOption("logRemoteFailures", True)
|
|
|
|
tub.setServiceParent(self.parent)
|
|
|
|
l = tub.listenOn("tcp:0")
|
|
|
|
portnum = l.getPortnum()
|
|
|
|
tub.setLocation("localhost:%d" % portnum)
|
|
|
|
|
|
|
|
i = Introducer()
|
|
|
|
i.setServiceParent(self.parent)
|
|
|
|
iurl = tub.registerReference(i)
|
|
|
|
|
|
|
|
clients = []
|
|
|
|
for i in range(5):
|
|
|
|
n = MyNode()
|
2007-05-22 21:08:30 +00:00
|
|
|
node_furl = tub.registerReference(n)
|
|
|
|
c = IntroducerClient(tub, iurl, node_furl)
|
2007-03-27 23:12:11 +00:00
|
|
|
c.setServiceParent(self.parent)
|
|
|
|
clients.append(c)
|
|
|
|
|
|
|
|
# time passes..
|
|
|
|
d = defer.Deferred()
|
|
|
|
def _check(res):
|
|
|
|
log.msg("doing _check")
|
|
|
|
self.failUnlessEqual(len(clients[0].connections), 5)
|
|
|
|
d.addCallback(_check)
|
|
|
|
reactor.callLater(2, d.callback, None)
|
|
|
|
return d
|
|
|
|
del test_system_this_one_breaks
|
|
|
|
|
|
|
|
|
|
|
|
def test_system_this_one_breaks_too(self):
|
|
|
|
# this one shuts down so quickly that it fails in a different way
|
|
|
|
self.central_tub = tub = Tub()
|
|
|
|
tub.setOption("logLocalFailures", True)
|
|
|
|
tub.setOption("logRemoteFailures", True)
|
|
|
|
tub.setServiceParent(self.parent)
|
|
|
|
l = tub.listenOn("tcp:0")
|
|
|
|
portnum = l.getPortnum()
|
|
|
|
tub.setLocation("localhost:%d" % portnum)
|
|
|
|
|
|
|
|
i = Introducer()
|
|
|
|
i.setServiceParent(self.parent)
|
|
|
|
iurl = tub.registerReference(i)
|
|
|
|
|
|
|
|
clients = []
|
|
|
|
for i in range(5):
|
|
|
|
tub = Tub()
|
|
|
|
tub.setOption("logLocalFailures", True)
|
|
|
|
tub.setOption("logRemoteFailures", True)
|
|
|
|
tub.setServiceParent(self.parent)
|
|
|
|
l = tub.listenOn("tcp:0")
|
|
|
|
portnum = l.getPortnum()
|
|
|
|
tub.setLocation("localhost:%d" % portnum)
|
|
|
|
|
|
|
|
n = MyNode()
|
2007-05-22 21:08:30 +00:00
|
|
|
node_furl = tub.registerReference(n)
|
|
|
|
c = IntroducerClient(tub, iurl, node_furl)
|
2007-03-27 23:12:11 +00:00
|
|
|
c.setServiceParent(self.parent)
|
|
|
|
clients.append(c)
|
|
|
|
|
|
|
|
# time passes..
|
|
|
|
d = defer.Deferred()
|
|
|
|
reactor.callLater(0.01, d.callback, None)
|
|
|
|
def _check(res):
|
|
|
|
log.msg("doing _check")
|
|
|
|
self.fail("BOOM")
|
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), 5)
|
|
|
|
c.connections.values()[0].tracker.broker.transport.loseConnection()
|
|
|
|
return self.stall(None, 2)
|
|
|
|
d.addCallback(_check)
|
|
|
|
def _check_again(res):
|
|
|
|
log.msg("doing _check_again")
|
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), 5)
|
|
|
|
d.addCallback(_check_again)
|
|
|
|
return d
|
|
|
|
del test_system_this_one_breaks_too
|
|
|
|
|