mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-29 09:18:53 +00:00
186 lines
6.9 KiB
Python
186 lines
6.9 KiB
Python
from base64 import b32decode
|
|
|
|
import os
|
|
|
|
from twisted.trial import unittest
|
|
from twisted.internet import defer
|
|
from twisted.python import log
|
|
|
|
from foolscap import Tub, Referenceable
|
|
from foolscap.eventual import fireEventually, flushEventualQueue
|
|
from twisted.application import service
|
|
from allmydata.introducer import IntroducerClient, IntroducerService, IntroducerNode
|
|
from allmydata.util import testutil
|
|
|
|
class FakeNode(Referenceable):
|
|
pass
|
|
|
|
class LoggingMultiService(service.MultiService):
|
|
def log(self, msg, **kw):
|
|
log.msg(msg, **kw)
|
|
|
|
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())
|
|
d.addCallback(lambda res: q.stopService())
|
|
d.addCallback(flushEventualQueue)
|
|
return d
|
|
|
|
class TestIntroducer(unittest.TestCase, testutil.PollMixin):
|
|
def setUp(self):
|
|
self.parent = LoggingMultiService()
|
|
self.parent.startService()
|
|
def tearDown(self):
|
|
log.msg("TestIntroducer.tearDown")
|
|
d = defer.succeed(None)
|
|
d.addCallback(lambda res: self.parent.stopService())
|
|
d.addCallback(flushEventualQueue)
|
|
return d
|
|
|
|
|
|
def test_create(self):
|
|
ic = IntroducerClient(None, "introducer.furl", "my_nickname",
|
|
"my_version", "oldest_version")
|
|
|
|
def test_listen(self):
|
|
i = IntroducerService()
|
|
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 = IntroducerService()
|
|
i.setServiceParent(self.parent)
|
|
introducer_furl = tub.registerReference(i)
|
|
NUMCLIENTS = 5
|
|
# we have 5 clients who publish themselves, and an extra one which
|
|
# does not. When the connections are fully established, all six nodes
|
|
# should have 5 connections each.
|
|
|
|
clients = []
|
|
tubs = {}
|
|
for i in range(NUMCLIENTS+1):
|
|
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 = FakeNode()
|
|
log.msg("creating client %d: %s" % (i, tub.getShortTubID()))
|
|
c = IntroducerClient(tub, introducer_furl,
|
|
"nickname-%d" % i, "version", "oldest")
|
|
if i < NUMCLIENTS:
|
|
node_furl = tub.registerReference(n)
|
|
c.publish(node_furl, "storage", "ri_name")
|
|
# the last one does not publish anything
|
|
|
|
c.subscribe_to("storage")
|
|
|
|
c.setServiceParent(self.parent)
|
|
clients.append(c)
|
|
tubs[c] = tub
|
|
|
|
def _wait_for_all_connections():
|
|
for c in clients:
|
|
if len(c.get_all_connections()) < NUMCLIENTS:
|
|
return False
|
|
return True
|
|
d = self.poll(_wait_for_all_connections)
|
|
|
|
def _check1(res):
|
|
log.msg("doing _check1")
|
|
for c in clients:
|
|
self.failUnless(c.connected_to_introducer())
|
|
self.failUnlessEqual(len(c.get_all_connections()), NUMCLIENTS)
|
|
self.failUnlessEqual(len(c.get_all_peerids()), NUMCLIENTS)
|
|
self.failUnlessEqual(len(c.get_all_connections_for("storage")),
|
|
NUMCLIENTS)
|
|
d.addCallback(_check1)
|
|
|
|
origin_c = clients[0]
|
|
def _disconnect_somebody_else(res):
|
|
# now disconnect somebody's connection to someone else
|
|
current_counter = origin_c.counter
|
|
victim_nodeid = b32decode(tubs[clients[1]].tubID.upper())
|
|
log.msg(" disconnecting %s->%s" % (tubs[origin_c].tubID,
|
|
victim_nodeid))
|
|
origin_c.debug_disconnect_from_peerid(victim_nodeid)
|
|
log.msg(" did disconnect")
|
|
|
|
# then wait until something changes, which ought to be them
|
|
# noticing the loss
|
|
def _compare():
|
|
return current_counter != origin_c.counter
|
|
return self.poll(_compare)
|
|
|
|
d.addCallback(_disconnect_somebody_else)
|
|
|
|
# and wait for them to reconnect
|
|
d.addCallback(lambda res: self.poll(_wait_for_all_connections))
|
|
def _check2(res):
|
|
log.msg("doing _check2")
|
|
for c in clients:
|
|
self.failUnlessEqual(len(c.get_all_connections()), NUMCLIENTS)
|
|
d.addCallback(_check2)
|
|
|
|
def _disconnect_yourself(res):
|
|
# now disconnect somebody's connection to themselves.
|
|
current_counter = origin_c.counter
|
|
victim_nodeid = b32decode(tubs[clients[0]].tubID.upper())
|
|
log.msg(" disconnecting %s->%s" % (tubs[origin_c].tubID,
|
|
victim_nodeid))
|
|
origin_c.debug_disconnect_from_peerid(victim_nodeid)
|
|
log.msg(" did disconnect from self")
|
|
|
|
def _compare():
|
|
return current_counter != origin_c.counter
|
|
return self.poll(_compare)
|
|
d.addCallback(_disconnect_yourself)
|
|
|
|
d.addCallback(lambda res: self.poll(_wait_for_all_connections))
|
|
def _check3(res):
|
|
log.msg("doing _check3")
|
|
for c in clients:
|
|
self.failUnlessEqual(len(c.get_all_connections_for("storage")),
|
|
NUMCLIENTS)
|
|
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)
|
|
def _wait_for_introducer_loss():
|
|
for c in clients:
|
|
if c.connected_to_introducer():
|
|
return False
|
|
return True
|
|
d.addCallback(lambda res: self.poll(_wait_for_introducer_loss))
|
|
|
|
def _check4(res):
|
|
log.msg("doing _check4")
|
|
for c in clients:
|
|
self.failUnlessEqual(len(c.get_all_connections_for("storage")),
|
|
NUMCLIENTS)
|
|
self.failIf(c.connected_to_introducer())
|
|
d.addCallback(_check4)
|
|
return d
|
|
|