2007-07-25 01:13:58 +00:00
|
|
|
from base64 import b32encode
|
2007-03-27 23:12:11 +00:00
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
import os
|
|
|
|
|
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-12-03 21:52:42 +00:00
|
|
|
from foolscap.eventual import fireEventually, flushEventualQueue
|
2007-03-27 23:12:11 +00:00
|
|
|
from twisted.application import service
|
2007-12-03 21:52:42 +00:00
|
|
|
from allmydata.introducer import IntroducerClient, IntroducerService, IntroducerNode
|
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):
|
2007-11-20 01:23:18 +00:00
|
|
|
def log(self, msg, **kw):
|
|
|
|
log.msg(msg, **kw)
|
2007-03-27 23:12:11 +00:00
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
class TestIntroducerNode(testutil.SignalMixin, unittest.TestCase):
|
|
|
|
def test_loadable(self):
|
|
|
|
basedir = "introducer.IntroducerNode.test_loadable"
|
|
|
|
os.mkdir(basedir)
|
|
|
|
q = IntroducerNode(basedir)
|
|
|
|
d = fireEventually(None)
|
|
|
|
d.addCallback(lambda res: q.startService())
|
|
|
|
d.addCallback(lambda res: q.when_tub_ready())
|
|
|
|
def _check_parameters(res):
|
|
|
|
i = q.getServiceNamed("introducer")
|
|
|
|
self.failUnlessEqual(i._encoding_parameters, (3, 7, 10))
|
|
|
|
d.addCallback(_check_parameters)
|
|
|
|
d.addCallback(lambda res: q.stopService())
|
|
|
|
d.addCallback(flushEventualQueue)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def test_set_parameters(self):
|
|
|
|
basedir = "introducer.IntroducerNode.test_set_parameters"
|
|
|
|
os.mkdir(basedir)
|
|
|
|
f = open(os.path.join(basedir, "encoding_parameters"), "w")
|
|
|
|
f.write("25 75 100")
|
|
|
|
f.close()
|
|
|
|
q = IntroducerNode(basedir)
|
|
|
|
d = fireEventually(None)
|
|
|
|
d.addCallback(lambda res: q.startService())
|
|
|
|
d.addCallback(lambda res: q.when_tub_ready())
|
|
|
|
def _check_parameters(res):
|
|
|
|
i = q.getServiceNamed("introducer")
|
|
|
|
self.failUnlessEqual(i._encoding_parameters, (25, 75, 100))
|
|
|
|
d.addCallback(_check_parameters)
|
|
|
|
d.addCallback(lambda res: q.stopService())
|
|
|
|
d.addCallback(flushEventualQueue)
|
|
|
|
return d
|
|
|
|
|
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):
|
2007-12-03 21:52:42 +00:00
|
|
|
i = IntroducerService()
|
2007-03-27 23:12:11 +00:00
|
|
|
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)
|
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
i = IntroducerService()
|
2007-03-27 23:12:11 +00:00
|
|
|
i.setServiceParent(self.parent)
|
|
|
|
iurl = tub.registerReference(i)
|
|
|
|
NUMCLIENTS = 5
|
|
|
|
|
|
|
|
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-12-11 03:22:59 +00:00
|
|
|
|
2007-03-27 23:12:11 +00:00
|
|
|
c.setServiceParent(self.parent)
|
|
|
|
clients.append(c)
|
|
|
|
tubs[c] = tub
|
|
|
|
|
2007-12-11 03:22:59 +00:00
|
|
|
def _wait_for_all_connections(res):
|
|
|
|
dl = [] # list of when_enough_peers() for each peer
|
|
|
|
# will fire once everybody is connected
|
|
|
|
for c in clients:
|
|
|
|
dl.append(c.when_enough_peers(NUMCLIENTS))
|
|
|
|
return defer.DeferredList(dl, fireOnOneErrback=True)
|
|
|
|
|
|
|
|
d = _wait_for_all_connections(None)
|
2007-03-27 23:12:11 +00:00
|
|
|
|
2007-09-19 18:50:13 +00:00
|
|
|
def _check1(res):
|
|
|
|
log.msg("doing _check1")
|
2007-03-27 23:12:11 +00:00
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), NUMCLIENTS)
|
2007-09-19 18:50:13 +00:00
|
|
|
self.failUnless(c._connected) # to the introducer
|
|
|
|
d.addCallback(_check1)
|
2007-12-11 03:22:59 +00:00
|
|
|
origin_c = clients[0]
|
2007-09-19 18:50:13 +00:00
|
|
|
def _disconnect_somebody_else(res):
|
2007-05-08 02:10:24 +00:00
|
|
|
# now disconnect somebody's connection to someone else
|
2007-03-27 23:12:11 +00:00
|
|
|
# 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")
|
2007-09-19 18:50:13 +00:00
|
|
|
d.addCallback(_disconnect_somebody_else)
|
2007-12-11 03:22:59 +00:00
|
|
|
def _wait_til_he_notices(res):
|
|
|
|
# wait til the origin_c notices the loss
|
|
|
|
log.msg(" waiting until peer notices the disconnection")
|
|
|
|
return origin_c.when_fewer_than_peers(NUMCLIENTS)
|
|
|
|
d.addCallback(_wait_til_he_notices)
|
|
|
|
def _wait_for_reconnection(res):
|
|
|
|
log.msg(" doing _wait_for_reconnection()")
|
|
|
|
return origin_c.when_enough_peers(NUMCLIENTS)
|
|
|
|
d.addCallback(_wait_for_reconnection)
|
2007-09-19 18:50:13 +00:00
|
|
|
def _check2(res):
|
|
|
|
log.msg("doing _check2")
|
2007-03-27 23:12:11 +00:00
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), NUMCLIENTS)
|
2007-09-19 18:50:13 +00:00
|
|
|
d.addCallback(_check2)
|
|
|
|
def _disconnect_yourself(res):
|
2007-12-11 03:22:59 +00:00
|
|
|
# now disconnect somebody's connection to themselves.
|
2007-03-27 23:12:11 +00:00
|
|
|
# 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()
|
2007-12-11 03:22:59 +00:00
|
|
|
log.msg(" did disconnect from self")
|
2007-09-19 18:50:13 +00:00
|
|
|
d.addCallback(_disconnect_yourself)
|
2007-12-11 03:22:59 +00:00
|
|
|
d.addCallback(_wait_til_he_notices)
|
|
|
|
d.addCallback(_wait_for_all_connections)
|
2007-09-19 18:50:13 +00:00
|
|
|
def _check3(res):
|
|
|
|
log.msg("doing _check3")
|
2007-03-27 23:12:11 +00:00
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), NUMCLIENTS)
|
2007-09-19 18:50:13 +00:00
|
|
|
d.addCallback(_check3)
|
|
|
|
def _shutdown_introducer(res):
|
|
|
|
# now shut down the introducer. We do this by shutting down the
|
|
|
|
# tub it's using. Nobody's connections (to each other) should go
|
|
|
|
# down. All clients should notice the loss, and no other errors
|
|
|
|
# should occur.
|
|
|
|
log.msg("shutting down the introducer")
|
|
|
|
return self.central_tub.disownServiceParent()
|
|
|
|
d.addCallback(_shutdown_introducer)
|
|
|
|
d.addCallback(self.stall, 2)
|
|
|
|
def _check4(res):
|
|
|
|
log.msg("doing _check4")
|
|
|
|
for c in clients:
|
|
|
|
self.failUnlessEqual(len(c.connections), NUMCLIENTS)
|
|
|
|
self.failIf(c._connected)
|
|
|
|
d.addCallback(_check4)
|
2007-03-27 23:12:11 +00:00
|
|
|
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)
|
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
i = IntroducerService()
|
2007-03-27 23:12:11 +00:00
|
|
|
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)
|
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
i = IntroducerService()
|
2007-03-27 23:12:11 +00:00
|
|
|
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
|