commit 2170254997d5a3e44bc12898a0c3acb94f70f7c7
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun May 21 19:26:52 2017 -0700
Merge remaining test.util into base test module
Now that we got this down to a small size we can merge what remains into
test/__init__.py.
---
run_tests.py | 7 +-
test/__init__.py | 145 ++++++++++++++++++++++++-
test/arguments.py | 17 ++-
test/integ/connection/authentication.py | 7 +-
test/integ/control/controller.py | 19 ++--
test/integ/descriptor/extrainfo_descriptor.py | 5 +-
test/integ/descriptor/microdescriptor.py | 5 +-
test/integ/descriptor/networkstatus.py | 11 +-
test/integ/descriptor/server_descriptor.py | 5 +-
test/integ/installation.py | 14 +--
test/integ/interpreter.py | 6 +-
test/integ/manual.py | 3 +-
test/integ/response/protocolinfo.py | 9 +-
test/integ/socket/control_socket.py | 5 +-
test/require.py | 8 +-
test/runner.py | 14 +--
test/settings.cfg | 3 +-
test/task.py | 15 ++-
test/unit/__init__.py | 4 +-
test/unit/connection/authentication.py | 4 +-
test/unit/doctest.py | 4 +-
test/unit/installation.py | 14 +--
test/unit/util/proc.py | 4 +-
test/util.py | 146 --------------------------
24 files changed, 229 insertions(+), 245 deletions(-)
diff --git a/run_tests.py b/run_tests.py
index 6beb659..725dd5a 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -26,15 +26,14 @@ import stem.util.system
import stem.util.test_tools
import stem.version
+import test
import test.arguments
import test.integ.installation
import test.output
import test.runner
import test.task
-import test.util
from test.output import STATUS, SUCCESS, ERROR, NO_NL, STDERR, println
-from test.util import STEM_BASE
CONFIG = stem.util.conf.config_dict('test', {
'test.unit_tests': '',
@@ -158,7 +157,7 @@ def main():
sys.exit(1)
test_config = stem.util.conf.get_config('test')
- test_config.load(os.path.join(STEM_BASE, 'test', 'settings.cfg'))
+ test_config.load(os.path.join(test.STEM_BASE, 'test', 'settings.cfg'))
try:
args = test.arguments.parse(sys.argv[1:])
@@ -377,7 +376,7 @@ def main():
println('TESTING PASSED %s\n' % runtime_label, SUCCESS)
- new_capabilities = test.util.get_new_capabilities()
+ new_capabilities = test.get_new_capabilities()
if new_capabilities:
println(NEW_CAPABILITIES_FOUND, ERROR)
diff --git a/test/__init__.py b/test/__init__.py
index 8ea70d2..355497c 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -2,7 +2,15 @@
# See LICENSE for licensing information
"""
-Unit and integration tests for the stem library.
+Unit and integration tests for the stem library. Helpers include...
+
+::
+
+ get_new_capabilities - missing capabilities found while testing
+ register_new_capability - note that tor feature stem lacks
+
+ get_all_combinations - provides all combinations of attributes
+ tor_version - provides the version of tor we're testing against
"""
__all__ = [
@@ -10,5 +18,138 @@ __all__ = [
'output',
'prompt',
'runner',
- 'util',
]
+
+import itertools
+import os
+
+import stem.util.enum
+import stem.version
+
+# Integration targets fall into two categories:
+#
+# * Run Targets (like RUN_COOKIE and RUN_PTRACE) which customize our torrc.
+# We do an integration test run for each run target we get.
+#
+# * Attribute Target (like CHROOT and ONLINE) which indicates
+# non-configuration changes to your test runs. These are applied to all
+# integration runs that we perform.
+
+Target = stem.util.enum.UppercaseEnum(
+ 'ONLINE',
+ 'RELATIVE',
+ 'CHROOT',
+ 'RUN_NONE',
+ 'RUN_OPEN',
+ 'RUN_PASSWORD',
+ 'RUN_COOKIE',
+ 'RUN_MULTIPLE',
+ 'RUN_SOCKET',
+ 'RUN_SCOOKIE',
+ 'RUN_PTRACE',
+ 'RUN_ALL',
+)
+
+TOR_VERSION = None
+
+# We make some paths relative to stem's base directory (the one above us)
+# rather than the process' cwd. This doesn't end with a slash.
+
+STEM_BASE = os.path.sep.join(__file__.split(os.path.sep)[:-2])
+
+# Store new capabilities (events, descriptor entries, etc.)
+
+NEW_CAPABILITIES = []
+NEW_CAPABILITIES_SUPPRESSION_TOKENS = set()
+
+# File extensions of contents that should be ignored.
+
+IGNORED_FILE_TYPES = []
+
+with open(os.path.join(STEM_BASE, '.gitignore')) as ignore_file:
+ for line in ignore_file:
+ if line.startswith('*.'):
+ IGNORED_FILE_TYPES.append(line[2:].strip())
+
+
+def get_new_capabilities():
+ """
+ Provides a list of capabilities tor supports but stem doesn't, as discovered
+ while running our tests.
+
+ :returns: **list** of (type, message) tuples for the capabilities
+ """
+
+ return NEW_CAPABILITIES
+
+
+def register_new_capability(capability_type, msg, suppression_token = None):
+ """
+ Register new capability found during the tests.
+
+ :param str capability_type: type of capability this is
+ :param str msg: description of what we found
+ :param str suppression_token: skip registration if this token's already been
+ provided
+ """
+
+ if suppression_token not in NEW_CAPABILITIES_SUPPRESSION_TOKENS:
+ NEW_CAPABILITIES.append((capability_type, msg))
+
+ if suppression_token:
+ NEW_CAPABILITIES_SUPPRESSION_TOKENS.add(suppression_token)
+
+
+def get_all_combinations(attr, include_empty = False):
+ """
+ Provides an iterator for all combinations of a set of attributes. For
+ instance...
+
+ ::
+
+ >>> list(test.get_all_combinations(['a', 'b', 'c']))
+ [('a',), ('b',), ('c',), ('a', 'b'), ('a', 'c'), ('b', 'c'), ('a', 'b', 'c')]
+
+ :param list attr: attributes to provide combinations for
+ :param bool include_empty: includes an entry with zero items if True
+ :returns: iterator for all combinations
+ """
+
+ # Makes an itertools.product() call for 'i' copies of attr...
+ #
+ # * itertools.product(attr) => all one-element combinations
+ # * itertools.product(attr, attr) => all two-element combinations
+ # * ... etc
+
+ if include_empty:
+ yield ()
+
+ seen = set()
+ for index in range(1, len(attr) + 1):
+ product_arg = [attr for _ in range(index)]
+
+ for item in itertools.product(*product_arg):
+ # deduplicate, sort, and only provide if we haven't seen it yet
+ item = tuple(sorted(set(item)))
+
+ if item not in seen:
+ seen.add(item)
+ yield item
+
+
+def tor_version(tor_path = None):
+ """
+ Provides the version of tor we're testing against.
+
+ :param str tor_path: location of tor executable to cehck the version of
+
+ :returns: :class:`~stem.version.Version` of tor invoked by our integration
+ tests
+ """
+
+ global TOR_VERSION
+
+ if TOR_VERSION is None or tor_path:
+ TOR_VERSION = stem.version.get_system_tor_version(tor_path)
+
+ return TOR_VERSION
diff --git a/test/arguments.py b/test/arguments.py
index 4ecd3bb..83197a7 100644
--- a/test/arguments.py
+++ b/test/arguments.py
@@ -10,8 +10,7 @@ import getopt
import stem.util.conf
import stem.util.log
-
-from test.util import Target
+import test
LOG_TYPE_ERROR = """\
'%s' isn't a logging runlevel, use one of the following instead:
@@ -30,7 +29,7 @@ DEFAULT_ARGS = {
'specific_test': None,
'logging_runlevel': None,
'tor_path': 'tor',
- 'run_targets': [Target.RUN_OPEN],
+ 'run_targets': [test.Target.RUN_OPEN],
'attribute_targets': [],
'quiet': False,
'verbose': False,
@@ -75,7 +74,7 @@ def parse(argv):
run_targets, attribute_targets = [], []
integ_targets = arg.split(',')
- all_run_targets = [t for t in Target if CONFIG['target.torrc'].get(t) is not None]
+ all_run_targets = [t for t in test.Target if CONFIG['target.torrc'].get(t) is not None]
# validates the targets and split them into run and attribute targets
@@ -83,7 +82,7 @@ def parse(argv):
raise ValueError('No targets provided')
for target in integ_targets:
- if target not in Target:
+ if target not in test.Target:
raise ValueError('Invalid integration target: %s' % target)
elif target in all_run_targets:
run_targets.append(target)
@@ -92,8 +91,8 @@ def parse(argv):
# check if we were told to use all run targets
- if Target.RUN_ALL in attribute_targets:
- attribute_targets.remove(Target.RUN_ALL)
+ if test.Target.RUN_ALL in attribute_targets:
+ attribute_targets.remove(test.Target.RUN_ALL)
run_targets = all_run_targets
# if no RUN_* targets are provided then keep the default (otherwise we
@@ -138,10 +137,10 @@ def get_help():
help_msg = CONFIG['msg.help']
# gets the longest target length so we can show the entries in columns
- target_name_length = max(map(len, Target))
+ target_name_length = max(map(len, test.Target))
description_format = '\n %%-%is - %%s' % target_name_length
- for target in Target:
+ for target in test.Target:
help_msg += description_format % (target, CONFIG['target.description'].get(target, ''))
help_msg += '\n'
diff --git a/test/integ/connection/authentication.py b/test/integ/connection/authentication.py
index f43a61d..3a2fcb0 100644
--- a/test/integ/connection/authentication.py
+++ b/test/integ/connection/authentication.py
@@ -9,11 +9,10 @@ import unittest
import stem.connection
import stem.socket
import stem.version
+import test
import test.require
import test.runner
-from test.util import tor_version
-
# Responses given by tor for various authentication failures. These may change
# in the future and if they do then this test should be updated.
@@ -44,7 +43,7 @@ def _can_authenticate(auth_type):
tor_options = runner.get_options()
password_auth = test.runner.Torrc.PASSWORD in tor_options
cookie_auth = test.runner.Torrc.COOKIE in tor_options
- safecookie_auth = cookie_auth and tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE
+ safecookie_auth = cookie_auth and test.tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE
if not password_auth and not cookie_auth:
# open socket, anything but safecookie will work
@@ -104,7 +103,7 @@ class TestAuthenticate(unittest.TestCase):
def setUp(self):
self.cookie_auth_methods = [stem.connection.AuthMethod.COOKIE]
- if tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE:
+ if test.tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE:
self.cookie_auth_methods.append(stem.connection.AuthMethod.SAFECOOKIE)
@test.require.controller
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py
index 2125242..1e4e8e8 100644
--- a/test/integ/control/controller.py
+++ b/test/integ/control/controller.py
@@ -18,6 +18,7 @@ import stem.response.protocolinfo
import stem.socket
import stem.util.str_tools
import stem.version
+import test
import test.network
import test.require
import test.runner
@@ -27,8 +28,6 @@ from stem.control import EventType, Listener, State
from stem.exit_policy import ExitPolicy
from stem.version import Requirement
-from test.util import register_new_capability, tor_version
-
# Router status entry for a relay with a nickname other than 'Unnamed'. This is
# used for a few tests that need to look up a relay.
@@ -47,17 +46,17 @@ class TestController(unittest.TestCase):
with test.runner.get_runner().get_tor_controller() as controller:
for event in controller.get_info('events/names').split():
if event not in EventType:
- register_new_capability('Event', event)
+ test.register_new_capability('Event', event)
for signal in controller.get_info('signal/names').split():
if signal not in Signal:
- register_new_capability('Signal', signal)
+ test.register_new_capability('Signal', signal)
# new features should simply be added to enable_feature()'s docs
for feature in controller.get_info('features/names').split():
if feature not in ('EXTENDED_EVENTS', 'VERBOSE_NAMES'):
- register_new_capability('Feature', feature)
+ test.register_new_capability('Feature', feature)
def test_from_port(self):
"""
@@ -266,7 +265,7 @@ class TestController(unittest.TestCase):
with runner.get_tor_controller() as controller:
version = controller.get_version()
self.assertTrue(isinstance(version, stem.version.Version))
- self.assertEqual(version, tor_version())
+ self.assertEqual(version, test.tor_version())
@test.require.controller
def test_get_exit_policy(self):
@@ -342,7 +341,7 @@ class TestController(unittest.TestCase):
if test.runner.Torrc.COOKIE in tor_options:
auth_methods.append(stem.response.protocolinfo.AuthMethod.COOKIE)
- if tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE:
+ if test.tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE:
auth_methods.append(stem.response.protocolinfo.AuthMethod.SAFECOOKIE)
if test.runner.Torrc.PASSWORD in tor_options:
@@ -1139,7 +1138,7 @@ class TestController(unittest.TestCase):
runner = test.runner.get_runner()
- if tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT:
+ if test.tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT:
self.skipTest('(requires server descriptors)')
return
@@ -1169,7 +1168,7 @@ class TestController(unittest.TestCase):
runner = test.runner.get_runner()
- if tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT:
+ if test.tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT:
self.skipTest('(requires server descriptors)')
return
@@ -1229,7 +1228,7 @@ class TestController(unittest.TestCase):
self.assertTrue(desc.nickname is not None)
for line in desc.get_unrecognized_lines():
- register_new_capability('Consensus Line', line)
+ test.register_new_capability('Consensus Line', line)
count += 1
if count > 10:
diff --git a/test/integ/descriptor/extrainfo_descriptor.py b/test/integ/descriptor/extrainfo_descriptor.py
index 205b917..eada1d7 100644
--- a/test/integ/descriptor/extrainfo_descriptor.py
+++ b/test/integ/descriptor/extrainfo_descriptor.py
@@ -6,11 +6,10 @@ import os
import unittest
import stem.descriptor
+import test
import test.require
import test.runner
-from test.util import register_new_capability
-
class TestExtraInfoDescriptor(unittest.TestCase):
@test.require.only_run_once
@@ -30,7 +29,7 @@ class TestExtraInfoDescriptor(unittest.TestCase):
with open(descriptor_path, 'rb') as descriptor_file:
for desc in stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0', validate = True):
for line in desc.get_unrecognized_lines():
- register_new_capability('Extra-info Line', line)
+ test.register_new_capability('Extra-info Line', line)
if desc.dir_v2_responses_unknown:
self.fail('Unrecognized statuses on dirreq-v2-resp lines: %s' % desc.dir_v2_responses_unknown)
diff --git a/test/integ/descriptor/microdescriptor.py b/test/integ/descriptor/microdescriptor.py
index c6fa80e..a38917a 100644
--- a/test/integ/descriptor/microdescriptor.py
+++ b/test/integ/descriptor/microdescriptor.py
@@ -6,11 +6,10 @@ import os
import unittest
import stem.descriptor
+import test
import test.require
import test.runner
-from test.util import register_new_capability
-
class TestMicrodescriptor(unittest.TestCase):
@test.require.only_run_once
@@ -30,4 +29,4 @@ class TestMicrodescriptor(unittest.TestCase):
with open(descriptor_path, 'rb') as descriptor_file:
for desc in stem.descriptor.parse_file(descriptor_file, 'microdescriptor 1.0', validate = True):
for line in desc.get_unrecognized_lines():
- register_new_capability('Microdescriptor Line', line)
+ test.register_new_capability('Microdescriptor Line', line)
diff --git a/test/integ/descriptor/networkstatus.py b/test/integ/descriptor/networkstatus.py
index 96fec77..83383fd 100644
--- a/test/integ/descriptor/networkstatus.py
+++ b/test/integ/descriptor/networkstatus.py
@@ -9,11 +9,10 @@ import stem
import stem.descriptor
import stem.descriptor.remote
import stem.version
+import test
import test.require
import test.runner
-from test.util import register_new_capability
-
class TestNetworkStatus(unittest.TestCase):
@test.require.only_run_once
@@ -53,11 +52,11 @@ class TestNetworkStatus(unittest.TestCase):
for flag in router.flags:
if flag not in stem.Flag and flag not in reported_flags:
- register_new_capability('Flag', flag)
+ test.register_new_capability('Flag', flag)
reported_flags.append(flag)
for line in router.get_unrecognized_lines():
- register_new_capability('Consensus Line', line, suppression_token = line.split()[0])
+ test.register_new_capability('Consensus Line', line, suppression_token = line.split()[0])
# Sanity test that there's at least a hundred relays. If that's not the
# case then this probably isn't a real, complete tor consensus.
@@ -87,10 +86,10 @@ class TestNetworkStatus(unittest.TestCase):
for flag in router.flags:
if flag not in stem.Flag:
- register_new_capability('Flag (microdescriptor)', flag)
+ test.register_new_capability('Flag (microdescriptor)', flag)
reported_flags.append(flag)
for line in router.get_unrecognized_lines():
- register_new_capability('Microdescriptor Consensus Line', line, suppression_token = line.split()[0])
+ test.register_new_capability('Microdescriptor Consensus Line', line, suppression_token = line.split()[0])
self.assertTrue(count > 100)
diff --git a/test/integ/descriptor/server_descriptor.py b/test/integ/descriptor/server_descriptor.py
index 2a3d897..7a234e3 100644
--- a/test/integ/descriptor/server_descriptor.py
+++ b/test/integ/descriptor/server_descriptor.py
@@ -6,11 +6,10 @@ import os
import unittest
import stem.descriptor
+import test
import test.require
import test.runner
-from test.util import register_new_capability
-
class TestServerDescriptor(unittest.TestCase):
@test.require.only_run_once
@@ -36,4 +35,4 @@ class TestServerDescriptor(unittest.TestCase):
self.assertEqual(None, desc.socks_port)
for line in desc.get_unrecognized_lines():
- register_new_capability('Server Descriptor Line', line)
+ test.register_new_capability('Server Descriptor Line', line)
diff --git a/test/integ/installation.py b/test/integ/installation.py
index 3f37df3..1cb9471 100644
--- a/test/integ/installation.py
+++ b/test/integ/installation.py
@@ -12,13 +12,13 @@ import unittest
import stem
import stem.util.system
+import test
import test.require
-import test.util
INSTALL_MISMATCH_MSG = "Running 'python setup.py sdist' doesn't match our git contents in the following way. The manifest in our setup.py may need to be updated...\n\n"
BASE_INSTALL_PATH = '/tmp/stem_test'
-DIST_PATH = os.path.join(test.util.STEM_BASE, 'dist')
+DIST_PATH = os.path.join(test.STEM_BASE, 'dist')
SETUP_THREAD, INSTALL_FAILURE, INSTALL_PATH, SDIST_FAILURE = None, None, None, None
@@ -35,10 +35,10 @@ def setup():
original_cwd = os.getcwd()
try:
- os.chdir(test.util.STEM_BASE)
+ os.chdir(test.STEM_BASE)
try:
- os.chdir(test.util.STEM_BASE)
+ os.chdir(test.STEM_BASE)
stem.util.system.call('%s setup.py install --prefix %s' % (sys.executable, BASE_INSTALL_PATH), timeout = 60)
stem.util.system.call('%s setup.py clean --all' % sys.executable, timeout = 60) # tidy up the build directory
site_packages_paths = glob.glob('%s/lib*/*/site-packages' % BASE_INSTALL_PATH)
@@ -86,12 +86,12 @@ def _assert_has_all_files(path):
expected, installed = set(), set()
- for root, dirnames, filenames in os.walk(os.path.join(test.util.STEM_BASE, 'stem')):
+ for root, dirnames, filenames in os.walk(os.path.join(test.STEM_BASE, 'stem')):
for filename in filenames:
file_format = filename.split('.')[-1]
- if file_format not in test.util.IGNORED_FILE_TYPES:
- expected.add(os.path.join(root, filename)[len(test.util.STEM_BASE) + 1:])
+ if file_format not in test.IGNORED_FILE_TYPES:
+ expected.add(os.path.join(root, filename)[len(test.STEM_BASE) + 1:])
for root, dirnames, filenames in os.walk(path):
for filename in filenames:
diff --git a/test/integ/interpreter.py b/test/integ/interpreter.py
index 42dd01a..5cef051 100644
--- a/test/integ/interpreter.py
+++ b/test/integ/interpreter.py
@@ -7,11 +7,11 @@ import tempfile
import unittest
import stem.util.system
+import test
import test.require
import test.runner
-import test.util
-PROMPT_CMD = os.path.join(test.util.STEM_BASE, 'tor-prompt')
+PROMPT_CMD = os.path.join(test.STEM_BASE, 'tor-prompt')
def _run_prompt(*args):
@@ -44,7 +44,7 @@ class TestInterpreter(unittest.TestCase):
'250-config-file=%s' % test.runner.get_runner().get_torrc_path(),
'250 OK',
'',
- '250-version=%s' % test.util.tor_version(),
+ '250-version=%s' % test.tor_version(),
'250 OK',
]
diff --git a/test/integ/manual.py b/test/integ/manual.py
index 5c73914..846b1b6 100644
--- a/test/integ/manual.py
+++ b/test/integ/manual.py
@@ -10,6 +10,7 @@ import unittest
import stem.manual
import stem.util.system
+import test
import test.runner
from stem.manual import Category
@@ -96,7 +97,7 @@ class TestManual(unittest.TestCase):
if stem.util.system.is_windows():
self.skip_reason = '(unavailable on windows)'
- elif test.runner.Target.ONLINE not in test.runner.get_runner().attribute_targets:
+ elif test.Target.ONLINE not in test.runner.get_runner().attribute_targets:
self.skip_reason = '(requires online target)'
elif not stem.util.system.is_available('a2x'):
self.skip_reason = '(requires asciidoc)'
diff --git a/test/integ/response/protocolinfo.py b/test/integ/response/protocolinfo.py
index 1a00671..5d8c74f 100644
--- a/test/integ/response/protocolinfo.py
+++ b/test/integ/response/protocolinfo.py
@@ -9,12 +9,11 @@ import stem.connection
import stem.socket
import stem.util.system
import stem.version
+import test
+import test.integ.util.system
import test.require
import test.runner
-from test.integ.util.system import filter_system_call
-from test.util import tor_version
-
try:
# added in python 3.3
from unittest.mock import Mock, patch
@@ -76,7 +75,7 @@ class TestProtocolInfo(unittest.TestCase):
control_socket = stem.socket.ControlSocketFile(test.runner.CONTROL_SOCKET_PATH)
- call_replacement = filter_system_call(lookup_prefixes)
+ call_replacement = test.integ.util.system.filter_system_call(lookup_prefixes)
with patch('stem.util.system.call') as call_mock:
call_mock.side_effect = call_replacement
@@ -132,7 +131,7 @@ class TestProtocolInfo(unittest.TestCase):
if test.runner.Torrc.COOKIE in tor_options:
auth_methods.append(stem.response.protocolinfo.AuthMethod.COOKIE)
- if tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE:
+ if test.tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE:
auth_methods.append(stem.response.protocolinfo.AuthMethod.SAFECOOKIE)
chroot_path = runner.get_chroot()
diff --git a/test/integ/socket/control_socket.py b/test/integ/socket/control_socket.py
index 8e2658a..f479892 100644
--- a/test/integ/socket/control_socket.py
+++ b/test/integ/socket/control_socket.py
@@ -14,11 +14,10 @@ import unittest
import stem.connection
import stem.control
import stem.socket
+import test
import test.require
import test.runner
-from test.util import tor_version
-
class TestControlSocket(unittest.TestCase):
@test.require.controller
@@ -69,7 +68,7 @@ class TestControlSocket(unittest.TestCase):
for _ in range(100):
response = control_socket.recv()
- self.assertTrue(str(response).startswith('version=%s' % tor_version()))
+ self.assertTrue(str(response).startswith('version=%s' % test.tor_version()))
self.assertTrue(str(response).endswith('\nOK'))
@test.require.controller
diff --git a/test/require.py b/test/require.py
index a0735d8..774e5f4 100644
--- a/test/require.py
+++ b/test/require.py
@@ -24,8 +24,8 @@ run.
import stem.util.system
import stem.version
+import test
import test.runner
-import test.util
RAN_TESTS = []
@@ -72,12 +72,12 @@ def _can_ptrace():
# If we're running a tor version where ptrace is disabled and we didn't
# set 'DisableDebuggerAttachment=1' then we can infer that it's disabled.
- has_option = test.util.tor_version() >= stem.version.Requirement.TORRC_DISABLE_DEBUGGER_ATTACHMENT
+ has_option = test.tor_version() >= stem.version.Requirement.TORRC_DISABLE_DEBUGGER_ATTACHMENT
return not has_option or test.runner.Torrc.PTRACE in test.runner.get_runner().get_options()
def _is_online():
- return test.util.Target.ONLINE in test.runner.get_runner().attribute_targets
+ return test.Target.ONLINE in test.runner.get_runner().attribute_targets
def command(cmd):
@@ -95,7 +95,7 @@ def version(req_version):
:param stem.version.Version req_version: required tor version for the test
"""
- return needs(lambda: test.util.tor_version() >= req_version, 'requires %s' % req_version)
+ return needs(lambda: test.tor_version() >= req_version, 'requires %s' % req_version)
cryptography = needs(stem.prereq.is_crypto_available, 'requires cryptography')
diff --git a/test/runner.py b/test/runner.py
index 0f5a1d0..5686b4c 100644
--- a/test/runner.py
+++ b/test/runner.py
@@ -47,9 +47,9 @@ import stem.process
import stem.socket
import stem.util.conf
import stem.util.enum
+import test
from test.output import println, STATUS, ERROR, SUBSTATUS, NO_NL
-from test.util import Target, STEM_BASE
CONFIG = stem.util.conf.config_dict('test', {
'integ.test_directory': './test/data',
@@ -192,13 +192,13 @@ class Runner(object):
config_test_dir = CONFIG['integ.test_directory']
if config_test_dir:
- self._test_dir = stem.util.system.expand_path(config_test_dir, STEM_BASE)
+ self._test_dir = stem.util.system.expand_path(config_test_dir, test.STEM_BASE)
else:
self._test_dir = tempfile.mktemp('-stem-integ')
original_cwd, data_dir_path = os.getcwd(), self._test_dir
- if Target.RELATIVE in self.attribute_targets:
+ if test.Target.RELATIVE in self.attribute_targets:
tor_cwd = os.path.dirname(self._test_dir)
if not os.path.exists(tor_cwd):
@@ -222,7 +222,7 @@ class Runner(object):
# strip the testing directory from recv_message responses if we're
# simulating a chroot setup
- if Target.CHROOT in self.attribute_targets and not self._original_recv_message:
+ if test.Target.CHROOT in self.attribute_targets and not self._original_recv_message:
# TODO: when we have a function for telling stem the chroot we'll
# need to set that too
@@ -235,7 +235,7 @@ class Runner(object):
stem.socket.recv_message = _chroot_recv_message
# revert our cwd back to normal
- if Target.RELATIVE in self.attribute_targets:
+ if test.Target.RELATIVE in self.attribute_targets:
os.chdir(original_cwd)
except OSError as exc:
raise exc
@@ -523,7 +523,7 @@ class Runner(object):
logging_path = CONFIG['integ.log']
if logging_path:
- logging_path = stem.util.system.expand_path(logging_path, STEM_BASE)
+ logging_path = stem.util.system.expand_path(logging_path, test.STEM_BASE)
println(' configuring logger (%s)... ' % logging_path, STATUS, NO_NL)
# delete the old log
@@ -578,7 +578,7 @@ class Runner(object):
self._tor_process = stem.process.launch_tor(
tor_cmd = tor_cmd,
torrc_path = os.path.join(self._test_dir, 'torrc'),
- completion_percent = 100 if Target.ONLINE in self.attribute_targets else 5,
+ completion_percent = 100 if test.Target.ONLINE in self.attribute_targets else 5,
init_msg_handler = lambda line: println(' %s' % line, SUBSTATUS),
take_ownership = True,
)
diff --git a/test/settings.cfg b/test/settings.cfg
index 2b5fafc..b65ee37 100644
--- a/test/settings.cfg
+++ b/test/settings.cfg
@@ -135,7 +135,6 @@ pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.n
pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.microdescriptor
pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.tordnsel
pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.hidden_service_descriptor
-pycodestyle.ignore test/util.py => E402: import test.runner
# False positives from pyflakes. These are mappings between the path and the
# issue.
@@ -163,7 +162,7 @@ pyflakes.ignore stem/util/test_tools.py => 'pyflakes' imported but unused
pyflakes.ignore stem/util/test_tools.py => 'pycodestyle' imported but unused
pyflakes.ignore test/unit/response/events.py => 'from stem import *' used; unable to detect undefined names
pyflakes.ignore test/unit/response/events.py => *may be undefined, or defined from star imports: stem
-pyflakes.ignore test/util.py => undefined name 'test'
+pyflakes.ignore test/__init__.py => undefined name 'test'
# Test modules we want to run. Modules are roughly ordered by the dependencies
# so the lowest level tests come first. This is because a problem in say,
diff --git a/test/task.py b/test/task.py
index b2c8ba8..1089cba 100644
--- a/test/task.py
+++ b/test/task.py
@@ -32,9 +32,8 @@ import stem.util.conf
import stem.util.system
import stem.util.test_tools
import stem.version
-
+import test
import test.output
-import test.util
from test.output import STATUS, ERROR, NO_NL, println
@@ -44,7 +43,7 @@ CONFIG = stem.util.conf.config_dict('test', {
'test.integ_tests': '',
})
-SRC_PATHS = [os.path.join(test.util.STEM_BASE, path) for path in (
+SRC_PATHS = [os.path.join(test.STEM_BASE, path) for path in (
'stem',
'test',
'run_tests.py',
@@ -58,7 +57,7 @@ SRC_PATHS = [os.path.join(test.util.STEM_BASE, path) for path in (
def _check_tor_version(tor_path):
- return str(test.util.tor_version(tor_path)).split()[0]
+ return str(test.tor_version(tor_path)).split()[0]
def _clean_orphaned_pyc(paths):
@@ -98,7 +97,7 @@ def _check_for_unused_tests(paths):
if test_match:
class_name = test_match.groups()[0]
- module_name = py_path.replace(os.path.sep, '.')[len(test.util.STEM_BASE) + 1:-3] + '.' + class_name
+ module_name = py_path.replace(os.path.sep, '.')[len(test.STEM_BASE) + 1:-3] + '.' + class_name
if not (module_name in CONFIG['test.unit_tests'] or module_name in CONFIG['test.integ_tests']):
unused_tests.append(module_name)
@@ -109,7 +108,7 @@ def _check_for_unused_tests(paths):
def run(category, *tasks):
"""
- Runs a series of :class:`test.util.Task` instances. This simply prints 'done'
+ Runs a series of :class:`test.Task` instances. This simply prints 'done'
or 'failed' for each unless we fail one that is marked as being required. If
that happens then we print its error message and call sys.exit().
@@ -215,8 +214,8 @@ PYCODESTYLE_VERSION = ModuleVersion('checking pycodestyle version', ['pycodestyl
CLEAN_PYC = Task('checking for orphaned .pyc files', _clean_orphaned_pyc, (SRC_PATHS,))
UNUSED_TESTS = Task('checking for unused tests', _check_for_unused_tests, [(
- os.path.join(test.util.STEM_BASE, 'test', 'unit'),
- os.path.join(test.util.STEM_BASE, 'test', 'integ'),
+ os.path.join(test.STEM_BASE, 'test', 'unit'),
+ os.path.join(test.STEM_BASE, 'test', 'integ'),
)])
PYFLAKES_TASK = Task(
diff --git a/test/unit/__init__.py b/test/unit/__init__.py
index 94cd059..6cdbe98 100644
--- a/test/unit/__init__.py
+++ b/test/unit/__init__.py
@@ -3,7 +3,7 @@ Unit tests for the stem library.
"""
import os
-import test.util
+import test
__all__ = [
'connection',
@@ -17,7 +17,7 @@ __all__ = [
def exec_documentation_example(filename):
- path = os.path.join(test.util.STEM_BASE, 'docs', '_static', 'example', filename)
+ path = os.path.join(test.STEM_BASE, 'docs', '_static', 'example', filename)
with open(path) as f:
code = compile(f.read(), path, 'exec')
diff --git a/test/unit/connection/authentication.py b/test/unit/connection/authentication.py
index b50f97b..117b39d 100644
--- a/test/unit/connection/authentication.py
+++ b/test/unit/connection/authentication.py
@@ -12,7 +12,7 @@ various error conditions, and make sure that the right exception is raised.
import unittest
import stem.connection
-import test.util
+import test
from stem.response import ControlMessage
from stem.util import log
@@ -86,7 +86,7 @@ class TestAuthenticate(unittest.TestCase):
stem.connection.AuthChallengeFailed(None, None),
stem.ControllerError(None))
- auth_method_combinations = test.util.get_all_combinations([
+ auth_method_combinations = test.get_all_combinations([
stem.connection.AuthMethod.NONE,
stem.connection.AuthMethod.PASSWORD,
stem.connection.AuthMethod.COOKIE,
diff --git a/test/unit/doctest.py b/test/unit/doctest.py
index 1240324..fb74d92 100644
--- a/test/unit/doctest.py
+++ b/test/unit/doctest.py
@@ -13,7 +13,7 @@ import stem.util.connection
import stem.util.str_tools
import stem.util.system
import stem.version
-import test.util
+import test
from stem.response import ControlMessage
@@ -37,7 +37,7 @@ ADD_ONION_RESPONSE = """\
class TestDocumentation(unittest.TestCase):
def test_examples(self):
- stem_dir = os.path.join(test.util.STEM_BASE, 'stem')
+ stem_dir = os.path.join(test.STEM_BASE, 'stem')
is_failed = False
for path in stem.util.system.files_with_suffix(stem_dir, '.py'):
diff --git a/test/unit/installation.py b/test/unit/installation.py
index 73881de..15d9fe8 100644
--- a/test/unit/installation.py
+++ b/test/unit/installation.py
@@ -3,7 +3,7 @@ import os
import re
import unittest
-import test.util
+import test
class TestInstallation(unittest.TestCase):
@@ -12,7 +12,7 @@ class TestInstallation(unittest.TestCase):
@classmethod
def setUpClass(self):
- setup_path = os.path.join(test.util.STEM_BASE, 'setup.py')
+ setup_path = os.path.join(test.STEM_BASE, 'setup.py')
self.skip_reason = None
self.setup_contents = False
@@ -32,13 +32,13 @@ class TestInstallation(unittest.TestCase):
# packages = ['stem', 'stem.descriptor', 'stem.util'],
modules = json.loads(re.search('packages = (\[.*\])', self.setup_contents).group(1).replace("'", '"'))
- module_paths = dict([(m, os.path.join(test.util.STEM_BASE, m.replace('.', os.path.sep))) for m in modules])
+ module_paths = dict([(m, os.path.join(test.STEM_BASE, m.replace('.', os.path.sep))) for m in modules])
for module, path in module_paths.items():
if not os.path.exists(path):
self.fail("setup.py's module %s doesn't exist at %s" % (module, path))
- for entry in os.walk(os.path.join(test.util.STEM_BASE, 'stem')):
+ for entry in os.walk(os.path.join(test.STEM_BASE, 'stem')):
directory = entry[0]
if directory.endswith('__pycache__'):
@@ -72,13 +72,13 @@ class TestInstallation(unittest.TestCase):
for module, files in package_data.items():
for module_file in files:
- data_files.append(os.path.join(test.util.STEM_BASE, module.replace('.', os.path.sep), module_file))
+ data_files.append(os.path.join(test.STEM_BASE, module.replace('.', os.path.sep), module_file))
for path in data_files:
if not os.path.exists(path):
self.fail("setup.py installs a data file that doesn't exist: %s" % path)
- for entry in os.walk(os.path.join(test.util.STEM_BASE, 'stem')):
+ for entry in os.walk(os.path.join(test.STEM_BASE, 'stem')):
directory = entry[0]
if directory.endswith('__pycache__'):
@@ -88,7 +88,7 @@ class TestInstallation(unittest.TestCase):
path = os.path.join(directory, filename)
file_type = path.split('.')[-1]
- if file_type in (['py'] + test.util.IGNORED_FILE_TYPES):
+ if file_type in (['py'] + test.IGNORED_FILE_TYPES):
continue
elif path not in data_files:
self.fail("setup.py doesn't install %s" % path)
diff --git a/test/unit/util/proc.py b/test/unit/util/proc.py
index 00f2af0..b4e3aab 100644
--- a/test/unit/util/proc.py
+++ b/test/unit/util/proc.py
@@ -6,7 +6,7 @@ import io
import re
import unittest
-import test.util
+import test
from stem.util import proc
from stem.util.connection import Connection
@@ -106,7 +106,7 @@ class TestProc(unittest.TestCase):
"""
# list of all combinations of args with respective return values
- stat_combinations = test.util.get_all_combinations([
+ stat_combinations = test.get_all_combinations([
('command', 'test_program'),
('utime', '0.13'),
('stime', '0.14'),
diff --git a/test/util.py b/test/util.py
deleted file mode 100644
index 3decb89..0000000
--- a/test/util.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# Copyright 2012-2017, Damian Johnson and The Tor Project
-# See LICENSE for licensing information
-
-"""
-Helper functions for our test framework.
-
-::
-
- get_all_combinations - provides all combinations of attributes
- tor_version - provides the version of tor we're testing against
-"""
-
-import itertools
-import os
-
-import stem
-import stem.util.enum
-import stem.version
-
-# Integration targets fall into two categories:
-#
-# * Run Targets (like RUN_COOKIE and RUN_PTRACE) which customize our torrc.
-# We do an integration test run for each run target we get.
-#
-# * Attribute Target (like CHROOT and ONLINE) which indicates
-# non-configuration changes to your test runs. These are applied to all
-# integration runs that we perform.
-
-Target = stem.util.enum.UppercaseEnum(
- 'ONLINE',
- 'RELATIVE',
- 'CHROOT',
- 'RUN_NONE',
- 'RUN_OPEN',
- 'RUN_PASSWORD',
- 'RUN_COOKIE',
- 'RUN_MULTIPLE',
- 'RUN_SOCKET',
- 'RUN_SCOOKIE',
- 'RUN_PTRACE',
- 'RUN_ALL',
-)
-
-TOR_VERSION = None
-
-# We make some paths relative to stem's base directory (the one above us)
-# rather than the process' cwd. This doesn't end with a slash.
-
-STEM_BASE = os.path.sep.join(__file__.split(os.path.sep)[:-2])
-
-# Store new capabilities (events, descriptor entries, etc.)
-
-NEW_CAPABILITIES = []
-NEW_CAPABILITIES_SUPPRESSION_TOKENS = set()
-
-# File extensions of contents that should be ignored.
-
-IGNORED_FILE_TYPES = []
-
-with open(os.path.join(STEM_BASE, '.gitignore')) as ignore_file:
- for line in ignore_file:
- if line.startswith('*.'):
- IGNORED_FILE_TYPES.append(line[2:].strip())
-
-
-def get_new_capabilities():
- """
- Provides a list of capabilities tor supports but stem doesn't, as discovered
- while running our tests.
-
- :returns: **list** of (type, message) tuples for the capabilities
- """
-
- return NEW_CAPABILITIES
-
-
-def register_new_capability(capability_type, msg, suppression_token = None):
- """
- Register new capability found during the tests.
-
- :param str capability_type: type of capability this is
- :param str msg: description of what we found
- :param str suppression_token: skip registration if this token's already been
- provided
- """
-
- if suppression_token not in NEW_CAPABILITIES_SUPPRESSION_TOKENS:
- NEW_CAPABILITIES.append((capability_type, msg))
-
- if suppression_token:
- NEW_CAPABILITIES_SUPPRESSION_TOKENS.add(suppression_token)
-
-
-def get_all_combinations(attr, include_empty = False):
- """
- Provides an iterator for all combinations of a set of attributes. For
- instance...
-
- ::
-
- >>> list(test.util.get_all_combinations(['a', 'b', 'c']))
- [('a',), ('b',), ('c',), ('a', 'b'), ('a', 'c'), ('b', 'c'), ('a', 'b', 'c')]
-
- :param list attr: attributes to provide combinations for
- :param bool include_empty: includes an entry with zero items if True
- :returns: iterator for all combinations
- """
-
- # Makes an itertools.product() call for 'i' copies of attr...
- #
- # * itertools.product(attr) => all one-element combinations
- # * itertools.product(attr, attr) => all two-element combinations
- # * ... etc
-
- if include_empty:
- yield ()
-
- seen = set()
- for index in range(1, len(attr) + 1):
- product_arg = [attr for _ in range(index)]
-
- for item in itertools.product(*product_arg):
- # deduplicate, sort, and only provide if we haven't seen it yet
- item = tuple(sorted(set(item)))
-
- if item not in seen:
- seen.add(item)
- yield item
-
-
-def tor_version(tor_path = None):
- """
- Provides the version of tor we're testing against.
-
- :param str tor_path: location of tor executable to cehck the version of
-
- :returns: :class:`~stem.version.Version` of tor invoked by our integration
- tests
- """
-
- global TOR_VERSION
-
- if TOR_VERSION is None or tor_path:
- TOR_VERSION = stem.version.get_system_tor_version(tor_path)
-
- return TOR_VERSION