2018-02-07 10:05:21 +00:00
|
|
|
import base64
|
|
|
|
import os
|
|
|
|
import stat
|
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
import mock
|
2007-05-23 22:08:55 +00:00
|
|
|
|
2018-08-24 22:51:47 +00:00
|
|
|
from unittest import skipIf
|
2015-07-17 21:03:53 +00:00
|
|
|
|
2007-05-23 22:08:55 +00:00
|
|
|
from twisted.trial import unittest
|
2007-05-24 00:55:04 +00:00
|
|
|
from twisted.internet import defer
|
2007-05-23 22:08:55 +00:00
|
|
|
from twisted.python import log
|
|
|
|
|
2009-05-22 00:38:23 +00:00
|
|
|
from foolscap.api import flushEventualQueue
|
2015-07-17 21:03:53 +00:00
|
|
|
import foolscap.logging.log
|
|
|
|
|
2007-05-23 22:08:55 +00:00
|
|
|
from twisted.application import service
|
2018-01-28 08:27:25 +00:00
|
|
|
from allmydata.node import create_tub_options
|
|
|
|
from allmydata.node import create_main_tub
|
2018-03-04 21:29:17 +00:00
|
|
|
from allmydata.node import create_node_dir
|
2018-01-28 08:27:25 +00:00
|
|
|
from allmydata.node import create_connection_handlers
|
2018-03-04 21:29:17 +00:00
|
|
|
from allmydata.node import config_from_string
|
|
|
|
from allmydata.node import read_config
|
|
|
|
from allmydata.node import MissingConfigEntry
|
|
|
|
from allmydata.node import _tub_portlocation
|
|
|
|
from allmydata.node import formatTimeTahoeStyle
|
2017-09-06 01:08:35 +00:00
|
|
|
from allmydata.introducer.server import create_introducer
|
2018-02-28 18:13:14 +00:00
|
|
|
from allmydata import client
|
|
|
|
|
2015-02-09 19:48:06 +00:00
|
|
|
from allmydata.util import fileutil, iputil
|
2015-07-17 21:03:53 +00:00
|
|
|
from allmydata.util.namespace import Namespace
|
2018-05-29 23:11:28 +00:00
|
|
|
from allmydata.util.configutil import UnknownConfigError
|
2018-01-31 01:04:08 +00:00
|
|
|
from allmydata.util.i2p_provider import create as create_i2p_provider
|
|
|
|
from allmydata.util.tor_provider import create as create_tor_provider
|
2010-02-26 08:14:33 +00:00
|
|
|
import allmydata.test.common_util as testutil
|
2007-05-23 22:08:55 +00:00
|
|
|
|
2015-07-17 21:03:53 +00:00
|
|
|
|
2007-05-23 22:08:55 +00:00
|
|
|
class LoggingMultiService(service.MultiService):
|
2007-11-20 01:23:18 +00:00
|
|
|
def log(self, msg, **kw):
|
2007-05-23 22:08:55 +00:00
|
|
|
pass
|
|
|
|
|
2017-09-06 01:08:35 +00:00
|
|
|
|
2018-01-28 08:27:25 +00:00
|
|
|
def testing_tub(config_data=''):
|
2018-08-31 19:27:47 +00:00
|
|
|
"""
|
|
|
|
Creates a 'main' Tub for testing purposes, from config data
|
|
|
|
"""
|
2018-01-28 08:27:25 +00:00
|
|
|
from twisted.internet import reactor
|
|
|
|
basedir = 'dummy_basedir'
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
|
2018-01-28 08:27:25 +00:00
|
|
|
fileutil.make_dirs(os.path.join(basedir, 'private'))
|
|
|
|
|
2018-01-31 20:15:01 +00:00
|
|
|
i2p_provider = create_i2p_provider(reactor, config)
|
|
|
|
tor_provider = create_tor_provider(reactor, config)
|
|
|
|
handlers = create_connection_handlers(reactor, config, i2p_provider, tor_provider)
|
2018-01-28 08:27:25 +00:00
|
|
|
default_connection_handlers, foolscap_connection_handlers = handlers
|
|
|
|
tub_options = create_tub_options(config)
|
|
|
|
|
2018-03-06 23:29:24 +00:00
|
|
|
main_tub = create_main_tub(
|
2018-01-31 20:15:01 +00:00
|
|
|
config, tub_options, default_connection_handlers,
|
2018-01-28 08:27:25 +00:00
|
|
|
foolscap_connection_handlers, i2p_provider, tor_provider,
|
|
|
|
cert_filename='DEFAULT_CERTFILE_BLANK'
|
|
|
|
)
|
|
|
|
return main_tub
|
2017-09-06 01:08:35 +00:00
|
|
|
|
2007-05-23 22:08:55 +00:00
|
|
|
|
2009-02-23 21:43:12 +00:00
|
|
|
class TestCase(testutil.SignalMixin, unittest.TestCase):
|
2017-08-08 16:42:11 +00:00
|
|
|
|
|
|
|
@defer.inlineCallbacks
|
2007-05-23 22:08:55 +00:00
|
|
|
def setUp(self):
|
2009-02-23 21:43:12 +00:00
|
|
|
testutil.SignalMixin.setUp(self)
|
2007-05-23 22:08:55 +00:00
|
|
|
self.parent = LoggingMultiService()
|
|
|
|
self.parent.startService()
|
2017-08-08 16:42:11 +00:00
|
|
|
self._available_port = yield iputil.allocate_tcp_port()
|
|
|
|
|
2007-05-23 22:08:55 +00:00
|
|
|
def tearDown(self):
|
|
|
|
log.msg("%s.tearDown" % self.__class__.__name__)
|
2009-02-23 21:43:12 +00:00
|
|
|
testutil.SignalMixin.tearDown(self)
|
2007-05-23 22:08:55 +00:00
|
|
|
d = defer.succeed(None)
|
|
|
|
d.addCallback(lambda res: self.parent.stopService())
|
|
|
|
d.addCallback(flushEventualQueue)
|
|
|
|
return d
|
|
|
|
|
2015-02-09 19:48:06 +00:00
|
|
|
def _test_location(self, basedir, expected_addresses, tub_port=None, tub_location=None, local_addresses=None):
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "testing")
|
2018-03-04 21:29:17 +00:00
|
|
|
config_data = "[node]\n"
|
|
|
|
if tub_port:
|
|
|
|
config_data += "tub.port = {}\n".format(tub_port)
|
|
|
|
if tub_location is not None:
|
|
|
|
config_data += "tub.location = {}\n".format(tub_location)
|
2007-05-23 22:08:55 +00:00
|
|
|
|
2015-02-09 19:48:06 +00:00
|
|
|
if local_addresses:
|
2016-04-27 01:21:36 +00:00
|
|
|
self.patch(iputil, 'get_local_addresses_sync',
|
|
|
|
lambda: local_addresses)
|
2015-02-09 19:48:06 +00:00
|
|
|
|
2018-01-28 08:27:25 +00:00
|
|
|
tub = testing_tub(config_data)
|
|
|
|
tub.setServiceParent(self.parent)
|
|
|
|
|
|
|
|
class Foo(object):
|
|
|
|
pass
|
|
|
|
|
|
|
|
furl = tub.registerReference(Foo())
|
2016-04-27 01:21:36 +00:00
|
|
|
for address in expected_addresses:
|
|
|
|
self.failUnlessIn(address, furl)
|
2007-05-23 22:08:55 +00:00
|
|
|
|
2015-02-09 19:45:31 +00:00
|
|
|
def test_location1(self):
|
|
|
|
return self._test_location(basedir="test_node/test_location1",
|
|
|
|
expected_addresses=["192.0.2.0:1234"],
|
|
|
|
tub_location="192.0.2.0:1234")
|
2008-09-30 06:08:16 +00:00
|
|
|
|
2015-02-09 19:45:31 +00:00
|
|
|
def test_location2(self):
|
|
|
|
return self._test_location(basedir="test_node/test_location2",
|
|
|
|
expected_addresses=["192.0.2.0:1234", "example.org:8091"],
|
|
|
|
tub_location="192.0.2.0:1234,example.org:8091")
|
2008-09-30 06:08:16 +00:00
|
|
|
|
2015-02-09 19:48:06 +00:00
|
|
|
def test_location_not_set(self):
|
|
|
|
"""Checks the autogenerated furl when tub.location is not set."""
|
2017-08-08 16:42:11 +00:00
|
|
|
return self._test_location(
|
|
|
|
basedir="test_node/test_location3",
|
|
|
|
expected_addresses=[
|
|
|
|
"127.0.0.1:{}".format(self._available_port),
|
|
|
|
"192.0.2.0:{}".format(self._available_port),
|
|
|
|
],
|
|
|
|
tub_port=self._available_port,
|
|
|
|
local_addresses=["127.0.0.1", "192.0.2.0"],
|
|
|
|
)
|
2015-02-09 19:48:06 +00:00
|
|
|
|
|
|
|
def test_location_auto_and_explicit(self):
|
|
|
|
"""Checks the autogenerated furl when tub.location contains 'AUTO'."""
|
2017-08-08 16:42:11 +00:00
|
|
|
return self._test_location(
|
|
|
|
basedir="test_node/test_location4",
|
|
|
|
expected_addresses=[
|
|
|
|
"127.0.0.1:{}".format(self._available_port),
|
|
|
|
"192.0.2.0:{}".format(self._available_port),
|
|
|
|
"example.com:4321",
|
|
|
|
],
|
|
|
|
tub_port=self._available_port,
|
|
|
|
tub_location="AUTO,example.com:{}".format(self._available_port),
|
|
|
|
local_addresses=["127.0.0.1", "192.0.2.0", "example.com:4321"],
|
|
|
|
)
|
2008-09-30 06:08:16 +00:00
|
|
|
|
2011-08-08 18:05:52 +00:00
|
|
|
def test_tahoe_cfg_utf8(self):
|
|
|
|
basedir = "test_node/test_tahoe_cfg_utf8"
|
|
|
|
fileutil.make_dirs(basedir)
|
|
|
|
f = open(os.path.join(basedir, 'tahoe.cfg'), 'wt')
|
|
|
|
f.write(u"\uFEFF[node]\n".encode('utf-8'))
|
|
|
|
f.write(u"nickname = \u2621\n".encode('utf-8'))
|
|
|
|
f.close()
|
|
|
|
|
2018-01-31 18:30:46 +00:00
|
|
|
config = read_config(basedir, "")
|
|
|
|
self.failUnlessEqual(config.get_config("node", "nickname").decode('utf-8'),
|
2016-04-27 01:21:36 +00:00
|
|
|
u"\u2621")
|
2011-08-08 18:05:52 +00:00
|
|
|
|
2014-05-05 21:55:50 +00:00
|
|
|
def test_tahoe_cfg_hash_in_name(self):
|
|
|
|
basedir = "test_node/test_cfg_hash_in_name"
|
|
|
|
nickname = "Hash#Bang!" # a clever nickname containing a hash
|
|
|
|
fileutil.make_dirs(basedir)
|
|
|
|
f = open(os.path.join(basedir, 'tahoe.cfg'), 'wt')
|
|
|
|
f.write("[node]\n")
|
|
|
|
f.write("nickname = %s\n" % (nickname,))
|
|
|
|
f.close()
|
2018-01-31 18:30:46 +00:00
|
|
|
|
|
|
|
config = read_config(basedir, "")
|
|
|
|
self.failUnless(config.nickname == nickname)
|
2014-05-05 21:55:50 +00:00
|
|
|
|
2018-03-01 23:07:52 +00:00
|
|
|
def test_config_required(self):
|
2018-08-24 22:50:04 +00:00
|
|
|
"""
|
|
|
|
Asking for missing (but required) configuration is an error
|
|
|
|
"""
|
2018-03-01 23:07:52 +00:00
|
|
|
basedir = u"test_node/test_config_required"
|
|
|
|
config = read_config(basedir, "portnum")
|
|
|
|
|
2018-03-02 03:51:35 +00:00
|
|
|
with self.assertRaises(Exception):
|
2018-03-01 23:07:52 +00:00
|
|
|
config.get_config_from_file("it_does_not_exist", required=True)
|
|
|
|
|
2018-08-24 22:51:47 +00:00
|
|
|
@skipIf(
|
|
|
|
"win32" in sys.platform.lower() or "cygwin" in sys.platform.lower(),
|
|
|
|
"We don't know how to set permissions on Windows.",
|
|
|
|
)
|
2018-03-01 23:07:52 +00:00
|
|
|
def test_private_config_unreadable(self):
|
2018-08-24 22:50:04 +00:00
|
|
|
"""
|
|
|
|
Asking for inaccessible private config is an error
|
|
|
|
"""
|
2018-03-01 23:07:52 +00:00
|
|
|
basedir = u"test_node/test_private_config_unreadable"
|
|
|
|
create_node_dir(basedir, "testing")
|
|
|
|
config = read_config(basedir, "portnum")
|
|
|
|
config.get_or_create_private_config("foo", "contents")
|
|
|
|
fname = os.path.join(basedir, "private", "foo")
|
|
|
|
os.chmod(fname, 0)
|
|
|
|
|
2018-03-02 03:51:35 +00:00
|
|
|
with self.assertRaises(Exception):
|
2018-03-01 23:07:52 +00:00
|
|
|
config.get_or_create_private_config("foo")
|
|
|
|
|
2018-08-25 06:36:58 +00:00
|
|
|
@skipIf(
|
|
|
|
"win32" in sys.platform.lower() or "cygwin" in sys.platform.lower(),
|
|
|
|
"We don't know how to set permissions on Windows.",
|
|
|
|
)
|
2018-03-01 23:07:52 +00:00
|
|
|
def test_private_config_unreadable_preexisting(self):
|
2018-08-25 06:36:58 +00:00
|
|
|
"""
|
|
|
|
error if reading private config data fails
|
|
|
|
"""
|
2018-03-01 23:07:52 +00:00
|
|
|
basedir = u"test_node/test_private_config_unreadable_preexisting"
|
|
|
|
create_node_dir(basedir, "testing")
|
|
|
|
config = read_config(basedir, "portnum")
|
|
|
|
fname = os.path.join(basedir, "private", "foo")
|
|
|
|
with open(fname, "w") as f:
|
|
|
|
f.write("stuff")
|
|
|
|
os.chmod(fname, 0)
|
|
|
|
|
2018-03-02 03:51:35 +00:00
|
|
|
with self.assertRaises(Exception):
|
2018-03-01 23:07:52 +00:00
|
|
|
config.get_private_config("foo")
|
|
|
|
|
|
|
|
def test_private_config_missing(self):
|
2018-08-25 06:31:16 +00:00
|
|
|
"""
|
|
|
|
a missing config with no default is an error
|
|
|
|
"""
|
2018-03-01 23:07:52 +00:00
|
|
|
basedir = u"test_node/test_private_config_missing"
|
|
|
|
create_node_dir(basedir, "testing")
|
|
|
|
config = read_config(basedir, "portnum")
|
|
|
|
|
2018-03-02 03:51:35 +00:00
|
|
|
with self.assertRaises(MissingConfigEntry):
|
2018-03-01 23:07:52 +00:00
|
|
|
config.get_or_create_private_config("foo")
|
|
|
|
|
2012-06-11 00:46:38 +00:00
|
|
|
def test_private_config(self):
|
2018-01-29 01:59:56 +00:00
|
|
|
basedir = u"test_node/test_private_config"
|
2012-06-11 00:46:38 +00:00
|
|
|
privdir = os.path.join(basedir, "private")
|
|
|
|
fileutil.make_dirs(privdir)
|
|
|
|
f = open(os.path.join(privdir, 'already'), 'wt')
|
|
|
|
f.write("secret")
|
|
|
|
f.close()
|
|
|
|
|
2018-01-29 01:59:56 +00:00
|
|
|
basedir = fileutil.abspath_expanduser_unicode(basedir)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(basedir, "", "")
|
2018-01-31 18:30:46 +00:00
|
|
|
|
2018-08-25 06:37:11 +00:00
|
|
|
self.assertEqual(config.get_private_config("already"), "secret")
|
|
|
|
self.assertEqual(config.get_private_config("not", "default"), "default")
|
|
|
|
self.assertRaises(MissingConfigEntry, config.get_private_config, "not")
|
2018-01-31 18:30:46 +00:00
|
|
|
value = config.get_or_create_private_config("new", "start")
|
2018-08-25 06:37:11 +00:00
|
|
|
self.assertEqual(value, "start")
|
|
|
|
self.assertEqual(config.get_private_config("new"), "start")
|
2012-06-11 00:46:38 +00:00
|
|
|
counter = []
|
|
|
|
def make_newer():
|
|
|
|
counter.append("called")
|
|
|
|
return "newer"
|
2018-01-31 18:30:46 +00:00
|
|
|
value = config.get_or_create_private_config("newer", make_newer)
|
2018-08-25 06:37:11 +00:00
|
|
|
self.assertEqual(len(counter), 1)
|
|
|
|
self.assertEqual(value, "newer")
|
|
|
|
self.assertEqual(config.get_private_config("newer"), "newer")
|
2012-06-11 00:46:38 +00:00
|
|
|
|
2018-01-31 18:30:46 +00:00
|
|
|
value = config.get_or_create_private_config("newer", make_newer)
|
2018-08-25 06:37:11 +00:00
|
|
|
self.assertEqual(len(counter), 1) # don't call unless necessary
|
|
|
|
self.assertEqual(value, "newer")
|
2012-06-11 00:46:38 +00:00
|
|
|
|
2018-01-31 18:30:46 +00:00
|
|
|
def test_write_config_unwritable_file(self):
|
2018-02-27 01:25:55 +00:00
|
|
|
"""
|
|
|
|
Existing behavior merely logs any errors upon writing
|
2018-02-27 22:01:18 +00:00
|
|
|
configuration files; this bad behavior should probably be
|
|
|
|
fixed to do something better (like fail entirely). See #2905
|
2018-02-27 01:25:55 +00:00
|
|
|
"""
|
2018-01-31 18:30:46 +00:00
|
|
|
basedir = "test_node/configdir"
|
|
|
|
fileutil.make_dirs(basedir)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(basedir, "", "")
|
2018-01-31 18:30:46 +00:00
|
|
|
with open(os.path.join(basedir, "bad"), "w") as f:
|
|
|
|
f.write("bad")
|
|
|
|
os.chmod(os.path.join(basedir, "bad"), 0o000)
|
|
|
|
|
|
|
|
config.write_config_file("bad", "some value")
|
|
|
|
|
2018-02-27 22:01:18 +00:00
|
|
|
errs = self.flushLoggedErrors(IOError)
|
2018-01-31 18:30:46 +00:00
|
|
|
self.assertEqual(1, len(errs))
|
|
|
|
|
2007-10-31 07:54:42 +00:00
|
|
|
def test_timestamp(self):
|
|
|
|
# this modified logger doesn't seem to get used during the tests,
|
|
|
|
# probably because we don't modify the LogObserver that trial
|
|
|
|
# installs (only the one that twistd installs). So manually exercise
|
|
|
|
# it a little bit.
|
|
|
|
t = formatTimeTahoeStyle("ignored", time.time())
|
|
|
|
self.failUnless("Z" in t)
|
|
|
|
t2 = formatTimeTahoeStyle("ignored", int(time.time()))
|
|
|
|
self.failUnless("Z" in t2)
|
2007-12-17 23:39:54 +00:00
|
|
|
|
|
|
|
def test_secrets_dir(self):
|
|
|
|
basedir = "test_node/test_secrets_dir"
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "testing")
|
2007-12-17 23:39:54 +00:00
|
|
|
self.failUnless(os.path.exists(os.path.join(basedir, "private")))
|
|
|
|
|
|
|
|
def test_secrets_dir_protected(self):
|
|
|
|
if "win32" in sys.platform.lower() or "cygwin" in sys.platform.lower():
|
|
|
|
# We don't know how to test that unprivileged users can't read this
|
|
|
|
# thing. (Also we don't know exactly how to set the permissions so
|
|
|
|
# that unprivileged users can't read this thing.)
|
|
|
|
raise unittest.SkipTest("We don't know how to set permissions on Windows.")
|
|
|
|
basedir = "test_node/test_secrets_dir_protected"
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "nothing to see here")
|
2018-01-31 18:30:46 +00:00
|
|
|
|
2018-02-27 22:00:31 +00:00
|
|
|
# make sure private dir was created with correct modes
|
2007-12-17 23:39:54 +00:00
|
|
|
privdir = os.path.join(basedir, "private")
|
|
|
|
st = os.stat(privdir)
|
|
|
|
bits = stat.S_IMODE(st[stat.ST_MODE])
|
|
|
|
self.failUnless(bits & 0001 == 0, bits)
|
2012-04-29 02:28:44 +00:00
|
|
|
|
2018-03-04 21:29:17 +00:00
|
|
|
@defer.inlineCallbacks
|
2015-07-17 21:03:53 +00:00
|
|
|
def test_logdir_is_str(self):
|
2012-04-29 02:28:44 +00:00
|
|
|
basedir = "test_node/test_logdir_is_str"
|
|
|
|
|
2015-07-17 21:03:53 +00:00
|
|
|
ns = Namespace()
|
|
|
|
ns.called = False
|
2012-04-29 02:28:44 +00:00
|
|
|
def call_setLogDir(logdir):
|
2015-07-17 21:03:53 +00:00
|
|
|
ns.called = True
|
2012-04-29 02:28:44 +00:00
|
|
|
self.failUnless(isinstance(logdir, str), logdir)
|
2015-07-17 21:03:53 +00:00
|
|
|
self.patch(foolscap.logging.log, 'setLogDir', call_setLogDir)
|
2012-04-29 02:28:44 +00:00
|
|
|
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "nothing to see here")
|
2018-03-05 01:20:13 +00:00
|
|
|
yield client.create_client(basedir)
|
2015-07-17 21:03:53 +00:00
|
|
|
self.failUnless(ns.called)
|
2016-08-30 01:49:20 +00:00
|
|
|
|
2018-02-27 22:00:31 +00:00
|
|
|
|
2018-02-27 22:56:58 +00:00
|
|
|
class TestMissingPorts(unittest.TestCase):
|
|
|
|
"""
|
|
|
|
Test certain error-cases for ports setup
|
|
|
|
"""
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.basedir = self.mktemp()
|
|
|
|
create_node_dir(self.basedir, "testing")
|
|
|
|
|
2018-08-25 06:31:16 +00:00
|
|
|
def test_parsing_tcp(self):
|
|
|
|
"""
|
|
|
|
parse explicit tub.port with explicitly-default tub.location
|
|
|
|
"""
|
2018-02-27 22:56:58 +00:00
|
|
|
get_addr = mock.patch(
|
|
|
|
"allmydata.util.iputil.get_local_addresses_sync",
|
|
|
|
return_value=["LOCAL"],
|
|
|
|
)
|
|
|
|
alloc_port = mock.patch(
|
|
|
|
"allmydata.util.iputil.allocate_tcp_port",
|
|
|
|
return_value=999,
|
|
|
|
)
|
2018-03-05 04:30:52 +00:00
|
|
|
config_data = (
|
|
|
|
"[node]\n"
|
|
|
|
"tub.port = tcp:777\n"
|
|
|
|
"tub.location = AUTO\n"
|
|
|
|
)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(self.basedir, "portnum", config_data)
|
2018-02-27 22:56:58 +00:00
|
|
|
|
|
|
|
with get_addr, alloc_port:
|
2018-03-05 04:30:52 +00:00
|
|
|
tubport, tublocation = _tub_portlocation(config)
|
2018-02-27 22:56:58 +00:00
|
|
|
self.assertEqual(tubport, "tcp:777")
|
|
|
|
self.assertEqual(tublocation, "tcp:LOCAL:777")
|
|
|
|
|
2018-08-25 06:31:16 +00:00
|
|
|
def test_parsing_defaults(self):
|
|
|
|
"""
|
|
|
|
parse empty config, check defaults
|
|
|
|
"""
|
2018-02-27 22:56:58 +00:00
|
|
|
get_addr = mock.patch(
|
|
|
|
"allmydata.util.iputil.get_local_addresses_sync",
|
|
|
|
return_value=["LOCAL"],
|
|
|
|
)
|
|
|
|
alloc_port = mock.patch(
|
|
|
|
"allmydata.util.iputil.allocate_tcp_port",
|
|
|
|
return_value=999,
|
2018-05-29 21:52:09 +00:00
|
|
|
)
|
2018-03-05 04:30:52 +00:00
|
|
|
config_data = (
|
|
|
|
"[node]\n"
|
|
|
|
)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(self.basedir, "portnum", config_data)
|
2018-02-27 22:56:58 +00:00
|
|
|
|
|
|
|
with get_addr, alloc_port:
|
2018-03-05 04:30:52 +00:00
|
|
|
tubport, tublocation = _tub_portlocation(config)
|
2018-02-27 22:56:58 +00:00
|
|
|
self.assertEqual(tubport, "tcp:999")
|
|
|
|
self.assertEqual(tublocation, "tcp:LOCAL:999")
|
|
|
|
|
2018-08-25 06:31:16 +00:00
|
|
|
def test_parsing_location_complex(self):
|
|
|
|
"""
|
|
|
|
location with two options (including defaults)
|
|
|
|
"""
|
2018-02-27 22:56:58 +00:00
|
|
|
get_addr = mock.patch(
|
|
|
|
"allmydata.util.iputil.get_local_addresses_sync",
|
|
|
|
return_value=["LOCAL"],
|
|
|
|
)
|
|
|
|
alloc_port = mock.patch(
|
|
|
|
"allmydata.util.iputil.allocate_tcp_port",
|
|
|
|
return_value=999,
|
|
|
|
)
|
2018-03-05 04:30:52 +00:00
|
|
|
config_data = (
|
|
|
|
"[node]\n"
|
|
|
|
"tub.location = tcp:HOST:888,AUTO\n"
|
|
|
|
)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(self.basedir, "portnum", config_data)
|
2018-02-27 22:56:58 +00:00
|
|
|
|
|
|
|
with get_addr, alloc_port:
|
2018-03-05 04:30:52 +00:00
|
|
|
tubport, tublocation = _tub_portlocation(config)
|
2018-02-27 22:56:58 +00:00
|
|
|
self.assertEqual(tubport, "tcp:999")
|
|
|
|
self.assertEqual(tublocation, "tcp:HOST:888,tcp:LOCAL:999")
|
|
|
|
|
2018-08-25 06:31:16 +00:00
|
|
|
def test_parsing_all_disabled(self):
|
|
|
|
"""
|
|
|
|
parse config with both port + location disabled
|
|
|
|
"""
|
2018-02-27 22:56:58 +00:00
|
|
|
get_addr = mock.patch(
|
|
|
|
"allmydata.util.iputil.get_local_addresses_sync",
|
|
|
|
return_value=["LOCAL"],
|
|
|
|
)
|
|
|
|
alloc_port = mock.patch(
|
|
|
|
"allmydata.util.iputil.allocate_tcp_port",
|
|
|
|
return_value=999,
|
|
|
|
)
|
2018-03-05 04:30:52 +00:00
|
|
|
config_data = (
|
|
|
|
"[node]\n"
|
|
|
|
"tub.port = disabled\n"
|
|
|
|
"tub.location = disabled\n"
|
|
|
|
)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(self.basedir, "portnum", config_data)
|
2018-02-27 22:56:58 +00:00
|
|
|
|
|
|
|
with get_addr, alloc_port:
|
2018-03-05 04:30:52 +00:00
|
|
|
res = _tub_portlocation(config)
|
2018-02-27 22:56:58 +00:00
|
|
|
self.assertTrue(res is None)
|
|
|
|
|
|
|
|
def test_empty_tub_port(self):
|
2018-08-25 06:31:16 +00:00
|
|
|
"""
|
|
|
|
port povided, but empty is an error
|
|
|
|
"""
|
|
|
|
config_data = (
|
|
|
|
"[node]\n"
|
|
|
|
"tub.port = \n"
|
|
|
|
)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(self.basedir, "portnum", config_data)
|
2018-02-27 22:56:58 +00:00
|
|
|
|
|
|
|
with self.assertRaises(ValueError) as ctx:
|
2018-03-05 04:30:52 +00:00
|
|
|
_tub_portlocation(config)
|
2018-02-27 22:56:58 +00:00
|
|
|
self.assertIn(
|
|
|
|
"tub.port must not be empty",
|
|
|
|
str(ctx.exception)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_empty_tub_location(self):
|
2018-08-25 06:31:16 +00:00
|
|
|
"""
|
|
|
|
location povided, but empty is an error
|
|
|
|
"""
|
|
|
|
config_data = (
|
|
|
|
"[node]\n"
|
|
|
|
"tub.location = \n"
|
|
|
|
)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(self.basedir, "portnum", config_data)
|
2018-02-27 22:56:58 +00:00
|
|
|
|
|
|
|
with self.assertRaises(ValueError) as ctx:
|
2018-03-05 04:30:52 +00:00
|
|
|
_tub_portlocation(config)
|
2018-02-27 22:56:58 +00:00
|
|
|
self.assertIn(
|
|
|
|
"tub.location must not be empty",
|
|
|
|
str(ctx.exception)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_disabled_port_not_tub(self):
|
2018-08-25 06:31:16 +00:00
|
|
|
"""
|
|
|
|
error to disable port but not location
|
|
|
|
"""
|
|
|
|
config_data = (
|
|
|
|
"[node]\n"
|
|
|
|
"tub.port = disabled\n"
|
|
|
|
"tub.location = not_disabled\n"
|
|
|
|
)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(self.basedir, "portnum", config_data)
|
2018-02-27 22:56:58 +00:00
|
|
|
|
|
|
|
with self.assertRaises(ValueError) as ctx:
|
2018-03-05 04:30:52 +00:00
|
|
|
_tub_portlocation(config)
|
2018-02-27 22:56:58 +00:00
|
|
|
self.assertIn(
|
|
|
|
"tub.port is disabled, but not tub.location",
|
|
|
|
str(ctx.exception)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_disabled_tub_not_port(self):
|
2018-08-25 06:31:16 +00:00
|
|
|
"""
|
|
|
|
error to disable location but not port
|
|
|
|
"""
|
|
|
|
config_data = (
|
|
|
|
"[node]\n"
|
|
|
|
"tub.port = not_disabled\n"
|
|
|
|
"tub.location = disabled\n"
|
|
|
|
)
|
2018-03-13 23:11:30 +00:00
|
|
|
config = config_from_string(self.basedir, "portnum", config_data)
|
2018-02-27 22:56:58 +00:00
|
|
|
|
|
|
|
with self.assertRaises(ValueError) as ctx:
|
2018-03-05 04:30:52 +00:00
|
|
|
_tub_portlocation(config)
|
2018-02-27 22:56:58 +00:00
|
|
|
self.assertIn(
|
|
|
|
"tub.location is disabled, but not tub.port",
|
|
|
|
str(ctx.exception)
|
|
|
|
)
|
2018-01-28 08:32:13 +00:00
|
|
|
|
|
|
|
|
2016-09-01 00:16:23 +00:00
|
|
|
BASE_CONFIG = """
|
2016-08-30 01:49:20 +00:00
|
|
|
[client]
|
|
|
|
introducer.furl = empty
|
2016-09-01 00:16:23 +00:00
|
|
|
[tor]
|
|
|
|
enabled = false
|
|
|
|
[i2p]
|
|
|
|
enabled = false
|
|
|
|
[node]
|
2016-08-30 01:49:20 +00:00
|
|
|
"""
|
|
|
|
|
2016-09-01 00:16:23 +00:00
|
|
|
NOLISTEN = """
|
|
|
|
[node]
|
|
|
|
tub.port = disabled
|
|
|
|
tub.location = disabled
|
|
|
|
"""
|
|
|
|
|
|
|
|
DISABLE_STORAGE = """
|
|
|
|
[storage]
|
|
|
|
enabled = false
|
|
|
|
"""
|
2016-08-30 01:49:20 +00:00
|
|
|
|
2016-09-01 00:16:23 +00:00
|
|
|
ENABLE_STORAGE = """
|
|
|
|
[storage]
|
|
|
|
enabled = true
|
|
|
|
"""
|
|
|
|
|
|
|
|
ENABLE_HELPER = """
|
|
|
|
[helper]
|
|
|
|
enabled = true
|
|
|
|
"""
|
|
|
|
|
2016-09-20 20:04:06 +00:00
|
|
|
class FakeTub:
|
|
|
|
def __init__(self):
|
|
|
|
self.tubID = base64.b32encode("foo")
|
|
|
|
self.listening_ports = []
|
|
|
|
def setOption(self, name, value): pass
|
|
|
|
def removeAllConnectionHintHandlers(self): pass
|
|
|
|
def addConnectionHintHandler(self, hint_type, handler): pass
|
|
|
|
def listenOn(self, what):
|
|
|
|
self.listening_ports.append(what)
|
|
|
|
def setLocation(self, location): pass
|
|
|
|
def setServiceParent(self, parent): pass
|
|
|
|
|
2017-07-19 17:24:24 +00:00
|
|
|
class Listeners(unittest.TestCase):
|
2018-01-28 08:27:25 +00:00
|
|
|
|
2018-03-05 04:45:07 +00:00
|
|
|
def test_listen_on_zero(self):
|
|
|
|
"""
|
|
|
|
Trying to listen on port 0 should be an error
|
|
|
|
"""
|
|
|
|
basedir = self.mktemp()
|
|
|
|
create_node_dir(basedir, "testing")
|
|
|
|
with open(os.path.join(basedir, "tahoe.cfg"), "w") as f:
|
|
|
|
f.write(BASE_CONFIG)
|
|
|
|
f.write("tub.port = tcp:0\n")
|
|
|
|
f.write("tub.location = AUTO\n")
|
|
|
|
|
|
|
|
config = client.read_config(basedir, "client.port")
|
|
|
|
i2p_provider = mock.Mock()
|
|
|
|
tor_provider = mock.Mock()
|
|
|
|
dfh, fch = create_connection_handlers(None, config, i2p_provider, tor_provider)
|
|
|
|
tub_options = create_tub_options(config)
|
|
|
|
t = FakeTub()
|
|
|
|
|
|
|
|
with mock.patch("allmydata.node.Tub", return_value=t):
|
|
|
|
with self.assertRaises(ValueError) as ctx:
|
|
|
|
create_main_tub(config, tub_options, dfh, fch, i2p_provider, tor_provider)
|
|
|
|
self.assertIn(
|
|
|
|
"you must choose",
|
|
|
|
str(ctx.exception),
|
|
|
|
)
|
|
|
|
|
2016-09-20 20:04:06 +00:00
|
|
|
def test_multiple_ports(self):
|
2018-02-27 22:00:31 +00:00
|
|
|
basedir = self.mktemp()
|
|
|
|
create_node_dir(basedir, "testing")
|
2016-09-20 20:04:06 +00:00
|
|
|
port1 = iputil.allocate_tcp_port()
|
|
|
|
port2 = iputil.allocate_tcp_port()
|
|
|
|
port = ("tcp:%d:interface=127.0.0.1,tcp:%d:interface=127.0.0.1" %
|
|
|
|
(port1, port2))
|
|
|
|
location = "tcp:localhost:%d,tcp:localhost:%d" % (port1, port2)
|
2018-02-27 22:00:31 +00:00
|
|
|
with open(os.path.join(basedir, "tahoe.cfg"), "w") as f:
|
2016-09-20 20:04:06 +00:00
|
|
|
f.write(BASE_CONFIG)
|
|
|
|
f.write("tub.port = %s\n" % port)
|
|
|
|
f.write("tub.location = %s\n" % location)
|
2018-02-27 22:00:31 +00:00
|
|
|
|
2018-03-04 21:29:17 +00:00
|
|
|
config = client.read_config(basedir, "client.port")
|
2018-01-28 08:27:25 +00:00
|
|
|
i2p_provider = mock.Mock()
|
|
|
|
tor_provider = mock.Mock()
|
2018-01-31 20:02:30 +00:00
|
|
|
dfh, fch = create_connection_handlers(None, config, i2p_provider, tor_provider)
|
2018-01-28 08:27:25 +00:00
|
|
|
tub_options = create_tub_options(config)
|
2016-09-20 20:04:06 +00:00
|
|
|
t = FakeTub()
|
2018-01-28 08:27:25 +00:00
|
|
|
|
2016-09-20 20:04:06 +00:00
|
|
|
with mock.patch("allmydata.node.Tub", return_value=t):
|
2018-01-31 20:02:30 +00:00
|
|
|
create_main_tub(config, tub_options, dfh, fch, i2p_provider, tor_provider)
|
2016-09-20 20:04:06 +00:00
|
|
|
self.assertEqual(t.listening_ports,
|
|
|
|
["tcp:%d:interface=127.0.0.1" % port1,
|
|
|
|
"tcp:%d:interface=127.0.0.1" % port2])
|
|
|
|
|
2017-07-19 17:24:24 +00:00
|
|
|
def test_tor_i2p_listeners(self):
|
2018-02-27 22:00:31 +00:00
|
|
|
basedir = self.mktemp()
|
|
|
|
config_fname = os.path.join(basedir, "tahoe.cfg")
|
|
|
|
os.mkdir(basedir)
|
|
|
|
os.mkdir(os.path.join(basedir, "private"))
|
|
|
|
with open(config_fname, "w") as f:
|
2017-07-19 17:24:24 +00:00
|
|
|
f.write(BASE_CONFIG)
|
|
|
|
f.write("tub.port = listen:i2p,listen:tor\n")
|
|
|
|
f.write("tub.location = tcp:example.org:1234\n")
|
2018-03-04 21:29:17 +00:00
|
|
|
config = client.read_config(basedir, "client.port")
|
2018-01-28 08:27:25 +00:00
|
|
|
tub_options = create_tub_options(config)
|
|
|
|
t = FakeTub()
|
|
|
|
|
2018-03-04 21:29:17 +00:00
|
|
|
i2p_provider = mock.Mock()
|
|
|
|
tor_provider = mock.Mock()
|
2018-01-31 20:02:30 +00:00
|
|
|
dfh, fch = create_connection_handlers(None, config, i2p_provider, tor_provider)
|
2018-01-28 08:27:25 +00:00
|
|
|
|
|
|
|
with mock.patch("allmydata.node.Tub", return_value=t):
|
2018-01-31 20:02:30 +00:00
|
|
|
create_main_tub(config, tub_options, dfh, fch, i2p_provider, tor_provider)
|
2018-01-28 08:27:25 +00:00
|
|
|
|
|
|
|
self.assertEqual(i2p_provider.get_listener.mock_calls, [mock.call()])
|
|
|
|
self.assertEqual(tor_provider.get_listener.mock_calls, [mock.call()])
|
2018-03-04 21:29:17 +00:00
|
|
|
## self.assertEqual(t.listening_ports, [i2p_ep, tor_ep])
|
2018-01-28 08:27:25 +00:00
|
|
|
|
2017-07-19 17:24:24 +00:00
|
|
|
|
2016-09-01 00:16:23 +00:00
|
|
|
class ClientNotListening(unittest.TestCase):
|
2018-01-28 08:27:25 +00:00
|
|
|
|
|
|
|
@defer.inlineCallbacks
|
2016-09-01 00:16:23 +00:00
|
|
|
def test_disabled(self):
|
|
|
|
basedir = "test_node/test_disabled"
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "testing")
|
2016-08-30 01:49:20 +00:00
|
|
|
f = open(os.path.join(basedir, 'tahoe.cfg'), 'wt')
|
2016-09-01 00:16:23 +00:00
|
|
|
f.write(BASE_CONFIG)
|
|
|
|
f.write(NOLISTEN)
|
|
|
|
f.write(DISABLE_STORAGE)
|
2016-08-30 01:49:20 +00:00
|
|
|
f.close()
|
2018-01-28 08:27:25 +00:00
|
|
|
n = yield client.create_client(basedir)
|
2016-08-30 01:49:20 +00:00
|
|
|
self.assertEqual(n.tub.getListeners(), [])
|
|
|
|
|
2018-09-04 23:13:16 +00:00
|
|
|
@defer.inlineCallbacks
|
2016-09-01 00:16:23 +00:00
|
|
|
def test_disabled_but_storage(self):
|
|
|
|
basedir = "test_node/test_disabled_but_storage"
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "testing")
|
2016-08-30 01:49:20 +00:00
|
|
|
f = open(os.path.join(basedir, 'tahoe.cfg'), 'wt')
|
2016-09-01 00:16:23 +00:00
|
|
|
f.write(BASE_CONFIG)
|
|
|
|
f.write(NOLISTEN)
|
|
|
|
f.write(ENABLE_STORAGE)
|
2016-08-30 01:49:20 +00:00
|
|
|
f.close()
|
2018-09-04 23:13:16 +00:00
|
|
|
with self.assertRaises(ValueError) as ctx:
|
|
|
|
yield client.create_client(basedir)
|
|
|
|
self.assertIn(
|
|
|
|
"storage is enabled, but tub is not listening",
|
|
|
|
str(ctx.exception),
|
|
|
|
)
|
2016-08-30 01:49:20 +00:00
|
|
|
|
2018-09-04 23:13:16 +00:00
|
|
|
@defer.inlineCallbacks
|
2016-09-01 00:16:23 +00:00
|
|
|
def test_disabled_but_helper(self):
|
|
|
|
basedir = "test_node/test_disabled_but_helper"
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "testing")
|
2016-08-30 01:49:20 +00:00
|
|
|
f = open(os.path.join(basedir, 'tahoe.cfg'), 'wt')
|
2016-09-01 00:16:23 +00:00
|
|
|
f.write(BASE_CONFIG)
|
|
|
|
f.write(NOLISTEN)
|
|
|
|
f.write(DISABLE_STORAGE)
|
|
|
|
f.write(ENABLE_HELPER)
|
2016-08-30 01:49:20 +00:00
|
|
|
f.close()
|
2018-09-04 23:13:16 +00:00
|
|
|
with self.assertRaises(ValueError) as ctx:
|
|
|
|
yield client.create_client(basedir)
|
|
|
|
self.assertIn(
|
|
|
|
"helper is enabled, but tub is not listening",
|
|
|
|
str(ctx.exception),
|
|
|
|
)
|
2016-08-30 01:49:20 +00:00
|
|
|
|
|
|
|
class IntroducerNotListening(unittest.TestCase):
|
2018-09-04 23:13:16 +00:00
|
|
|
|
|
|
|
@defer.inlineCallbacks
|
2016-08-30 01:49:20 +00:00
|
|
|
def test_port_none_introducer(self):
|
|
|
|
basedir = "test_node/test_port_none_introducer"
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "testing")
|
|
|
|
with open(os.path.join(basedir, 'tahoe.cfg'), 'wt') as f:
|
|
|
|
f.write("[node]\n")
|
|
|
|
f.write("tub.port = disabled\n")
|
|
|
|
f.write("tub.location = disabled\n")
|
2018-09-04 23:13:16 +00:00
|
|
|
with self.assertRaises(ValueError) as ctx:
|
|
|
|
yield create_introducer(basedir)
|
|
|
|
self.assertIn(
|
|
|
|
"we are Introducer, but tub is not listening",
|
|
|
|
str(ctx.exception),
|
|
|
|
)
|
2018-05-29 23:11:28 +00:00
|
|
|
|
|
|
|
class Configuration(unittest.TestCase):
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.basedir = self.mktemp()
|
|
|
|
fileutil.make_dirs(self.basedir)
|
|
|
|
|
|
|
|
def test_read_invalid_config(self):
|
|
|
|
with open(os.path.join(self.basedir, 'tahoe.cfg'), 'w') as f:
|
|
|
|
f.write(
|
|
|
|
'[invalid section]\n'
|
|
|
|
'foo = bar\n'
|
|
|
|
)
|
|
|
|
with self.assertRaises(UnknownConfigError) as ctx:
|
|
|
|
read_config(
|
|
|
|
self.basedir,
|
|
|
|
"client.port",
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIn(
|
|
|
|
"invalid section",
|
|
|
|
str(ctx.exception),
|
|
|
|
)
|
|
|
|
|
2018-09-04 23:13:16 +00:00
|
|
|
@defer.inlineCallbacks
|
2018-05-29 23:11:28 +00:00
|
|
|
def test_create_client_invalid_config(self):
|
|
|
|
with open(os.path.join(self.basedir, 'tahoe.cfg'), 'w') as f:
|
|
|
|
f.write(
|
|
|
|
'[invalid section]\n'
|
|
|
|
'foo = bar\n'
|
|
|
|
)
|
|
|
|
with self.assertRaises(UnknownConfigError) as ctx:
|
2018-09-04 23:13:16 +00:00
|
|
|
yield client.create_client(self.basedir)
|
2018-05-29 23:11:28 +00:00
|
|
|
|
|
|
|
self.assertIn(
|
|
|
|
"invalid section",
|
|
|
|
str(ctx.exception),
|
|
|
|
)
|