commit 6ce38d57adfaef16e8c8de75676207c4dd090fb2 Author: Damian Johnson atagar@torproject.org Date: Tue Apr 4 10:32:24 2017 -0700
Move test requirement functions to util
Moving the require* functions to test.util and adding a few for simple prereqs. Planning to add some more so we can use annotations for more common requirements. --- test/integ/connection/authentication.py | 3 +- test/integ/connection/connect.py | 2 +- test/integ/control/base_controller.py | 9 +- test/integ/control/controller.py | 17 ++-- test/integ/descriptor/extrainfo_descriptor.py | 9 +- test/integ/descriptor/microdescriptor.py | 9 +- test/integ/descriptor/networkstatus.py | 15 +-- test/integ/descriptor/remote.py | 9 +- test/integ/descriptor/server_descriptor.py | 9 +- test/integ/installation.py | 12 ++- test/integ/manual.py | 3 +- test/integ/process.py | 10 +- test/integ/response/protocolinfo.py | 3 +- test/integ/socket/control_message.py | 2 +- test/integ/socket/control_socket.py | 3 +- test/integ/util/connection.py | 7 +- test/integ/util/proc.py | 19 ++-- test/integ/util/system.py | 95 ++++++++++--------- test/integ/version.py | 7 +- test/runner.py | 88 +---------------- test/unit/descriptor/certificate.py | 17 +--- test/unit/descriptor/export.py | 6 +- test/unit/descriptor/hidden_service_descriptor.py | 11 +-- test/unit/descriptor/reader.py | 12 +-- test/unit/installation.py | 7 +- test/unit/manual.py | 12 +-- test/unit/tutorial_examples.py | 6 +- test/util.py | 109 ++++++++++++++++++++++ 28 files changed, 275 insertions(+), 236 deletions(-)
diff --git a/test/integ/connection/authentication.py b/test/integ/connection/authentication.py index 4289fac..007042f 100644 --- a/test/integ/connection/authentication.py +++ b/test/integ/connection/authentication.py @@ -11,8 +11,7 @@ import stem.socket import stem.version import test.runner
-from test.runner import require_controller -from test.util import tor_version +from test.util import require_controller, 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. diff --git a/test/integ/connection/connect.py b/test/integ/connection/connect.py index b50fdfc..d50b3af 100644 --- a/test/integ/connection/connect.py +++ b/test/integ/connection/connect.py @@ -13,7 +13,7 @@ except ImportError: import stem.connection import test.runner
-from test.runner import require_controller +from test.util import require_controller
class TestConnect(unittest.TestCase): diff --git a/test/integ/control/base_controller.py b/test/integ/control/base_controller.py index dc2e478..78e6e3e 100644 --- a/test/integ/control/base_controller.py +++ b/test/integ/control/base_controller.py @@ -14,7 +14,10 @@ import stem.util.system import test.mocking import test.runner
-from test.runner import require_controller +from test.util import ( + skip, + require_controller, +)
class StateObserver(object): @@ -47,7 +50,7 @@ class TestBaseController(unittest.TestCase): """
if stem.util.system.is_mac(): - test.runner.skip(self, '(ticket #6235)') + skip(self, '(ticket #6235)') return
with test.runner.get_runner().get_tor_socket() as control_socket: @@ -97,7 +100,7 @@ class TestBaseController(unittest.TestCase): """
if stem.util.system.is_mac(): - test.runner.skip(self, '(ticket #6235)') + skip(self, '(ticket #6235)') return
with test.runner.get_runner().get_tor_socket() as control_socket: diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py index a0f9b99..877c40b 100644 --- a/test/integ/control/controller.py +++ b/test/integ/control/controller.py @@ -27,13 +27,14 @@ 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 - -from test.runner import ( +from test.util import ( + register_new_capability, + tor_version, + skip, + only_run_once, require_controller, require_version, require_online, - only_run_once, )
# Router status entry for a relay with a nickname other than 'Unnamed'. This is @@ -1125,7 +1126,7 @@ class TestController(unittest.TestCase): runner = test.runner.get_runner()
if not os.path.exists(runner.get_test_dir('cached-descriptors')): - test.runner.skip(self, '(no cached microdescriptors)') + skip(self, '(no cached microdescriptors)') return
with runner.get_tor_controller() as controller: @@ -1147,7 +1148,7 @@ class TestController(unittest.TestCase): runner = test.runner.get_runner()
if tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT: - test.runner.skip(self, '(requires server descriptors)') + skip(self, '(requires server descriptors)') return
with runner.get_tor_controller() as controller: @@ -1177,7 +1178,7 @@ class TestController(unittest.TestCase): runner = test.runner.get_runner()
if tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT: - test.runner.skip(self, '(requires server descriptors)') + skip(self, '(requires server descriptors)') return
with runner.get_tor_controller() as controller: @@ -1357,7 +1358,7 @@ class TestController(unittest.TestCase):
if TEST_ROUTER_STATUS_ENTRY is None: # this is only likely to occure if we can't get descriptors - test.runner.skip(self, '(no named relays)') + skip(self, '(no named relays)') return
return TEST_ROUTER_STATUS_ENTRY diff --git a/test/integ/descriptor/extrainfo_descriptor.py b/test/integ/descriptor/extrainfo_descriptor.py index 740ac59..2ac44fe 100644 --- a/test/integ/descriptor/extrainfo_descriptor.py +++ b/test/integ/descriptor/extrainfo_descriptor.py @@ -8,8 +8,11 @@ import unittest import stem.descriptor import test.runner
-from test.runner import only_run_once -from test.util import register_new_capability +from test.util import ( + register_new_capability, + skip, + only_run_once, +)
class TestExtraInfoDescriptor(unittest.TestCase): @@ -24,7 +27,7 @@ class TestExtraInfoDescriptor(unittest.TestCase): descriptor_path = test.runner.get_runner().get_test_dir('cached-extrainfo')
if not os.path.exists(descriptor_path): - test.runner.skip(self, '(no cached descriptors)') + skip(self, '(no cached descriptors)') return
with open(descriptor_path, 'rb') as descriptor_file: diff --git a/test/integ/descriptor/microdescriptor.py b/test/integ/descriptor/microdescriptor.py index fad7ef8..b1796c2 100644 --- a/test/integ/descriptor/microdescriptor.py +++ b/test/integ/descriptor/microdescriptor.py @@ -8,8 +8,11 @@ import unittest import stem.descriptor import test.runner
-from test.runner import only_run_once -from test.util import register_new_capability +from test.util import ( + register_new_capability, + skip, + only_run_once, +)
class TestMicrodescriptor(unittest.TestCase): @@ -24,7 +27,7 @@ class TestMicrodescriptor(unittest.TestCase): descriptor_path = test.runner.get_runner().get_test_dir('cached-microdescs')
if not os.path.exists(descriptor_path): - test.runner.skip(self, '(no cached microdescriptors)') + skip(self, '(no cached microdescriptors)') return
with open(descriptor_path, 'rb') as descriptor_file: diff --git a/test/integ/descriptor/networkstatus.py b/test/integ/descriptor/networkstatus.py index f4de8f5..e6bdce2 100644 --- a/test/integ/descriptor/networkstatus.py +++ b/test/integ/descriptor/networkstatus.py @@ -11,8 +11,11 @@ import stem.descriptor.networkstatus import stem.version import test.runner
-from test.runner import only_run_once -from test.util import register_new_capability +from test.util import ( + register_new_capability, + skip, + only_run_once, +)
class TestNetworkStatus(unittest.TestCase): @@ -25,13 +28,13 @@ class TestNetworkStatus(unittest.TestCase): consensus_path = test.runner.get_runner().get_test_dir('cached-consensus')
if not os.path.exists(consensus_path): - test.runner.skip(self, '(no cached-consensus)') + skip(self, '(no cached-consensus)') return elif stem.util.system.is_windows(): # Unable to check memory usage on windows, so can't prevent hanging the # system if things go bad.
- test.runner.skip(self, '(unavailable on windows)') + skip(self, '(unavailable on windows)') return
count, reported_flags = 0, [] @@ -62,10 +65,10 @@ class TestNetworkStatus(unittest.TestCase): consensus_path = test.runner.get_runner().get_test_dir('cached-microdesc-consensus')
if not os.path.exists(consensus_path): - test.runner.skip(self, '(no cached-microdesc-consensus)') + skip(self, '(no cached-microdesc-consensus)') return elif stem.util.system.is_windows(): - test.runner.skip(self, '(unavailable on windows)') + skip(self, '(unavailable on windows)') return
count, reported_flags = 0, [] diff --git a/test/integ/descriptor/remote.py b/test/integ/descriptor/remote.py index 889f3d8..cd18187 100644 --- a/test/integ/descriptor/remote.py +++ b/test/integ/descriptor/remote.py @@ -11,11 +11,10 @@ import stem.descriptor.remote import stem.descriptor.router_status_entry import stem.descriptor.server_descriptor
-import test.runner - -from test.runner import ( - require_online, +from test.util import ( + skip, only_run_once, + require_online, )
@@ -248,7 +247,7 @@ class TestDescriptorDownloader(unittest.TestCase): # Don't run this test by default. Once upon a time it was fine, but tor has # added so many fallbacks now that this takes a looong time. :(
- test.runner.skip(self, '(skipped by default)') + skip(self, '(skipped by default)') return
unsuccessful = {} diff --git a/test/integ/descriptor/server_descriptor.py b/test/integ/descriptor/server_descriptor.py index 86e4942..302cef1 100644 --- a/test/integ/descriptor/server_descriptor.py +++ b/test/integ/descriptor/server_descriptor.py @@ -9,8 +9,11 @@ import stem.descriptor
import test.runner
-from test.runner import only_run_once -from test.util import register_new_capability +from test.util import ( + register_new_capability, + skip, + only_run_once, +)
class TestServerDescriptor(unittest.TestCase): @@ -25,7 +28,7 @@ class TestServerDescriptor(unittest.TestCase): descriptor_path = test.runner.get_runner().get_test_dir('cached-descriptors')
if not os.path.exists(descriptor_path): - test.runner.skip(self, '(no cached descriptors)') + skip(self, '(no cached descriptors)') return
with open(descriptor_path, 'rb') as descriptor_file: diff --git a/test/integ/installation.py b/test/integ/installation.py index 2048ea3..72f2df4 100644 --- a/test/integ/installation.py +++ b/test/integ/installation.py @@ -9,9 +9,13 @@ import unittest import stem import stem.util.system
-import test.runner import test.util
+from test.util import ( + skip, + only_run_once, +) + 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' @@ -105,7 +109,7 @@ def _assert_has_all_files(path):
class TestInstallation(unittest.TestCase): - @test.runner.only_run_once + @only_run_once def test_install(self): """ Installs with 'python setup.py install' and checks we can use what we @@ -121,7 +125,7 @@ class TestInstallation(unittest.TestCase): self.assertEqual(stem.__version__, stem.util.system.call([sys.executable, '-c', "import sys;sys.path.insert(0, '%s');import stem;print(stem.__version__)" % INSTALL_PATH])[0]) _assert_has_all_files(INSTALL_PATH)
- @test.runner.only_run_once + @only_run_once def test_sdist(self): """ Creates a source distribution tarball with 'python setup.py sdist' and @@ -130,7 +134,7 @@ class TestInstallation(unittest.TestCase): """
if not stem.util.system.is_available('git'): - test.runner.skip(self, '(git unavailable)') + skip(self, '(git unavailable)') return
setup().join() diff --git a/test/integ/manual.py b/test/integ/manual.py index e3ab3df..187cde9 100644 --- a/test/integ/manual.py +++ b/test/integ/manual.py @@ -13,6 +13,7 @@ import stem.util.system import test.runner
from stem.manual import Category +from test.util import skip
EXPECTED_CATEGORIES = set([ 'NAME', @@ -119,7 +120,7 @@ class TestManual(unittest.TestCase):
def requires_downloaded_manual(self): if self.skip_reason: - test.runner.skip(self, self.skip_reason) + skip(self, self.skip_reason) return True elif self.download_error: self.fail(self.download_error) diff --git a/test/integ/process.py b/test/integ/process.py index 66f2018..4cc79e3 100644 --- a/test/integ/process.py +++ b/test/integ/process.py @@ -22,12 +22,14 @@ import stem.util.tor_tools import stem.version import test.runner
-from test.runner import ( +from test.util import ( + skip, require_controller, require_version, - only_run_once, )
+from test.util import only_run_once + try: # added in python 3.3 from unittest.mock import patch, Mock @@ -340,6 +342,7 @@ class TestProcess(unittest.TestCase): )
control_socket = None + try: control_socket = stem.socket.ControlPort(port = 2778) stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot()) @@ -374,6 +377,7 @@ class TestProcess(unittest.TestCase): )
control_socket = None + try: control_socket = stem.socket.ControlPort(port = 2778) stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot()) @@ -437,7 +441,7 @@ class TestProcess(unittest.TestCase): """
if not stem.util.system.is_available('sleep'): - test.runner.skip(self, "('sleep' command is unavailable)") + skip(self, "('sleep' command is unavailable)") return
sleep_process = subprocess.Popen(['sleep', '60']) diff --git a/test/integ/response/protocolinfo.py b/test/integ/response/protocolinfo.py index 5c2c092..8563cf0 100644 --- a/test/integ/response/protocolinfo.py +++ b/test/integ/response/protocolinfo.py @@ -12,8 +12,7 @@ import stem.version import test.runner
from test.integ.util.system import filter_system_call -from test.runner import require_controller -from test.util import tor_version +from test.util import require_controller, tor_version
try: # added in python 3.3 diff --git a/test/integ/socket/control_message.py b/test/integ/socket/control_message.py index 5f6ff42..13075ca 100644 --- a/test/integ/socket/control_message.py +++ b/test/integ/socket/control_message.py @@ -10,7 +10,7 @@ import stem.version import test.mocking import test.runner
-from test.runner import ( +from test.util import ( require_controller, require_version, ) diff --git a/test/integ/socket/control_socket.py b/test/integ/socket/control_socket.py index 1a8b50a..a4da321 100644 --- a/test/integ/socket/control_socket.py +++ b/test/integ/socket/control_socket.py @@ -16,8 +16,7 @@ import stem.control import stem.socket import test.runner
-from test.runner import require_controller -from test.util import tor_version +from test.util import require_controller, tor_version
class TestControlSocket(unittest.TestCase): diff --git a/test/integ/util/connection.py b/test/integ/util/connection.py index c6ca04a..1145169 100644 --- a/test/integ/util/connection.py +++ b/test/integ/util/connection.py @@ -8,6 +8,7 @@ import unittest import test.runner
from stem.util.connection import Resolver, get_connections, system_resolvers +from test.util import skip
class TestConnection(unittest.TestCase): @@ -15,13 +16,13 @@ class TestConnection(unittest.TestCase): runner = test.runner.get_runner()
if test.runner.Torrc.PORT not in runner.get_options(): - test.runner.skip(self, '(no control port)') + skip(self, '(no control port)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment set)') + skip(self, '(DisableDebuggerAttachment set)') return elif resolver not in system_resolvers(): - test.runner.skip(self, '(resolver unavailable on this platform)') + skip(self, '(resolver unavailable on this platform)') return
with runner.get_tor_socket(): diff --git a/test/integ/util/proc.py b/test/integ/util/proc.py index 79da938..4671b3d 100644 --- a/test/integ/util/proc.py +++ b/test/integ/util/proc.py @@ -9,6 +9,7 @@ import unittest import test.runner
from stem.util import proc +from test.util import skip
class TestProc(unittest.TestCase): @@ -18,10 +19,10 @@ class TestProc(unittest.TestCase): """
if not proc.is_available(): - test.runner.skip(self, '(proc unavailable)') + skip(self, '(proc unavailable)') return elif not test.runner.get_runner().is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return
runner = test.runner.get_runner() @@ -34,7 +35,7 @@ class TestProc(unittest.TestCase): """
if not proc.is_available(): - test.runner.skip(self, '(proc unavailable)') + skip(self, '(proc unavailable)') return
tor_pid = test.runner.get_runner().get_pid() @@ -46,7 +47,7 @@ class TestProc(unittest.TestCase): """
if not proc.is_available(): - test.runner.skip(self, '(proc unavailable)') + skip(self, '(proc unavailable)') return
tor_pid = test.runner.get_runner().get_pid() @@ -62,7 +63,7 @@ class TestProc(unittest.TestCase): """
if not proc.is_available(): - test.runner.skip(self, '(proc unavailable)') + skip(self, '(proc unavailable)') return
tor_cmd = test.runner.get_runner().get_tor_command(True) @@ -83,16 +84,16 @@ class TestProc(unittest.TestCase): runner = test.runner.get_runner()
if not proc.is_available(): - test.runner.skip(self, '(proc unavailable)') + skip(self, '(proc unavailable)') return elif test.runner.Torrc.PORT not in runner.get_options(): - test.runner.skip(self, '(no control port)') + skip(self, '(no control port)') return elif not test.runner.get_runner().is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return elif not os.access('/proc/net/tcp', os.R_OK) or not os.access('/proc/net/udp', os.R_OK): - test.runner.skip(self, '(proc lacks read permissions)') + skip(self, '(proc lacks read permissions)') return
# making a controller connection so that we have something to query for diff --git a/test/integ/util/system.py b/test/integ/util/system.py index be04393..eee2ccb 100644 --- a/test/integ/util/system.py +++ b/test/integ/util/system.py @@ -12,6 +12,8 @@ import stem.util.proc import stem.util.system import test.runner
+from test.util import skip + try: # added in python 3.3 from unittest.mock import Mock, patch @@ -67,7 +69,7 @@ class TestSystem(unittest.TestCase): """
if not stem.util.system.is_available('ps'): - test.runner.skip(self, '(ps unavailable)') + skip(self, '(ps unavailable)') return
# Check to see if the command we started tor with is running. The process @@ -85,7 +87,7 @@ class TestSystem(unittest.TestCase): """
if self._is_extra_tor_running(): - test.runner.skip(self, '(multiple tor instances)') + skip(self, '(multiple tor instances)') return
tor_pid = test.runner.get_runner().get_pid() @@ -99,10 +101,10 @@ class TestSystem(unittest.TestCase): """
if self._is_extra_tor_running(): - test.runner.skip(self, '(multiple tor instances)') + skip(self, '(multiple tor instances)') return elif not stem.util.system.is_available('pgrep'): - test.runner.skip(self, '(pgrep unavailable)') + skip(self, '(pgrep unavailable)') return
pgrep_prefix = stem.util.system.GET_PID_BY_NAME_PGREP % '' @@ -122,10 +124,10 @@ class TestSystem(unittest.TestCase): """
if self._is_extra_tor_running(): - test.runner.skip(self, '(multiple tor instances)') + skip(self, '(multiple tor instances)') return elif not stem.util.system.is_available('pidof'): - test.runner.skip(self, '(pidof unavailable)') + skip(self, '(pidof unavailable)') return
pidof_prefix = stem.util.system.GET_PID_BY_NAME_PIDOF % '' @@ -145,13 +147,13 @@ class TestSystem(unittest.TestCase): """
if self._is_extra_tor_running(): - test.runner.skip(self, '(multiple tor instances)') + skip(self, '(multiple tor instances)') return elif not stem.util.system.is_available('ps'): - test.runner.skip(self, '(ps unavailable)') + skip(self, '(ps unavailable)') return elif stem.util.system.is_bsd(): - test.runner.skip(self, '(linux only)') + skip(self, '(linux only)') return
ps_prefix = stem.util.system.GET_PID_BY_NAME_PS_LINUX % '' @@ -171,13 +173,13 @@ class TestSystem(unittest.TestCase): """
if self._is_extra_tor_running(): - test.runner.skip(self, '(multiple tor instances)') + skip(self, '(multiple tor instances)') return elif not stem.util.system.is_available('ps'): - test.runner.skip(self, '(ps unavailable)') + skip(self, '(ps unavailable)') return elif not stem.util.system.is_bsd(): - test.runner.skip(self, '(bsd only)') + skip(self, '(bsd only)') return
ps_prefix = stem.util.system.GET_PID_BY_NAME_PS_BSD @@ -198,13 +200,13 @@ class TestSystem(unittest.TestCase):
runner = test.runner.get_runner() if self._is_extra_tor_running(): - test.runner.skip(self, '(multiple tor instances)') + skip(self, '(multiple tor instances)') return elif not stem.util.system.is_available('lsof'): - test.runner.skip(self, '(lsof unavailable)') + skip(self, '(lsof unavailable)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return
lsof_prefix = stem.util.system.GET_PID_BY_NAME_LSOF % '' @@ -227,10 +229,10 @@ class TestSystem(unittest.TestCase): """
if self._is_extra_tor_running(): - test.runner.skip(self, '(multiple tor instances)') + skip(self, '(multiple tor instances)') return elif not stem.util.system.is_available('tasklist'): - test.runner.skip(self, '(tasklist unavailable)') + skip(self, '(tasklist unavailable)') return
runner = test.runner.get_runner() @@ -240,23 +242,24 @@ class TestSystem(unittest.TestCase): """ Checks general usage of the stem.util.system.pid_by_port function. """ + runner = test.runner.get_runner() if stem.util.system.is_windows(): - test.runner.skip(self, '(unavailable on windows)') + skip(self, '(unavailable on windows)') return elif not _has_port(): - test.runner.skip(self, '(test instance has no port)') + skip(self, '(test instance has no port)') return elif stem.util.system.is_mac() or stem.util.system.is_gentoo(): - test.runner.skip(self, '(resolvers unavailable)') + skip(self, '(resolvers unavailable)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return elif not (stem.util.system.is_available('netstat') or stem.util.system.is_available('sockstat') or stem.util.system.is_available('lsof')): - test.runner.skip(self, '(connection resolvers unavailable)') + skip(self, '(connection resolvers unavailable)') return
tor_pid, tor_port = runner.get_pid(), test.runner.CONTROL_PORT @@ -270,19 +273,19 @@ class TestSystem(unittest.TestCase):
runner = test.runner.get_runner() if not _has_port(): - test.runner.skip(self, '(test instance has no port)') + skip(self, '(test instance has no port)') return elif not stem.util.system.is_available('netstat'): - test.runner.skip(self, '(netstat unavailable)') + skip(self, '(netstat unavailable)') return elif stem.util.system.is_bsd() or stem.util.system.is_windows(): - test.runner.skip(self, '(linux only)') + skip(self, '(linux only)') return elif stem.util.system.is_gentoo(): - test.runner.skip(self, '(unavailable on gentoo)') + skip(self, '(unavailable on gentoo)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return
netstat_prefix = stem.util.system.GET_PID_BY_PORT_NETSTAT @@ -302,16 +305,16 @@ class TestSystem(unittest.TestCase):
runner = test.runner.get_runner() if not _has_port(): - test.runner.skip(self, '(test instance has no port)') + skip(self, '(test instance has no port)') return elif not stem.util.system.is_available('sockstat'): - test.runner.skip(self, '(sockstat unavailable)') + skip(self, '(sockstat unavailable)') return elif not stem.util.system.is_bsd(): - test.runner.skip(self, '(bsd only)') + skip(self, '(bsd only)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return
sockstat_prefix = stem.util.system.GET_PID_BY_PORT_SOCKSTAT % '' @@ -331,16 +334,16 @@ class TestSystem(unittest.TestCase):
runner = test.runner.get_runner() if not _has_port(): - test.runner.skip(self, '(test instance has no port)') + skip(self, '(test instance has no port)') return elif not stem.util.system.is_available('lsof'): - test.runner.skip(self, '(lsof unavailable)') + skip(self, '(lsof unavailable)') return elif stem.util.system.is_mac() or stem.util.system.is_gentoo(): - test.runner.skip(self, '(resolvers unavailable)') + skip(self, '(resolvers unavailable)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return
lsof_prefix = stem.util.system.GET_PID_BY_PORT_LSOF @@ -384,10 +387,10 @@ class TestSystem(unittest.TestCase): runner = test.runner.get_runner()
if stem.util.system.is_windows(): - test.runner.skip(self, '(unavailable on windows)') + skip(self, '(unavailable on windows)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return
runner_pid, tor_cwd = runner.get_pid(), runner.get_tor_cwd() @@ -402,10 +405,10 @@ class TestSystem(unittest.TestCase): runner = test.runner.get_runner()
if not stem.util.system.is_available('pwdx'): - test.runner.skip(self, '(pwdx unavailable)') + skip(self, '(pwdx unavailable)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return
# filter the call function to only allow this command @@ -428,10 +431,10 @@ class TestSystem(unittest.TestCase): runner = test.runner.get_runner()
if not stem.util.system.is_available('lsof'): - test.runner.skip(self, '(lsof unavailable)') + skip(self, '(lsof unavailable)') return elif not runner.is_ptraceable(): - test.runner.skip(self, '(DisableDebuggerAttachment is set)') + skip(self, '(DisableDebuggerAttachment is set)') return
# filter the call function to only allow this command @@ -461,7 +464,7 @@ class TestSystem(unittest.TestCase): """
if not stem.util.proc.is_available(): - test.runner.skip(self, '(proc unavailable)') + skip(self, '(proc unavailable)') return
call_replacement = filter_system_call(['ps ']) @@ -481,7 +484,7 @@ class TestSystem(unittest.TestCase): """
if not stem.util.system.is_available('ps'): - test.runner.skip(self, '(ps unavailable)') + skip(self, '(ps unavailable)') return
pid = test.runner.get_runner().get_pid() @@ -502,7 +505,7 @@ class TestSystem(unittest.TestCase): """
if not stem.util.proc.is_available(): - test.runner.skip(self, '(proc unavailable)') + skip(self, '(proc unavailable)') return
call_replacement = filter_system_call(['ps ']) @@ -520,7 +523,7 @@ class TestSystem(unittest.TestCase): """
if not stem.util.system.is_available('ps'): - test.runner.skip(self, '(ps unavailable)') + skip(self, '(ps unavailable)') return
pid = test.runner.get_runner().get_pid() @@ -550,7 +553,7 @@ class TestSystem(unittest.TestCase): # '/root'
if getpass.getuser() == 'root': - test.runner.skip(self, '(running as root)') + skip(self, '(running as root)') return
self.assertEqual(os.getcwd(), stem.util.system.expand_path('.')) diff --git a/test/integ/version.py b/test/integ/version.py index 57e469c..06837c7 100644 --- a/test/integ/version.py +++ b/test/integ/version.py @@ -9,7 +9,10 @@ import stem.prereq import stem.version import test.runner
-from test.runner import require_controller +from test.util import ( + skip, + require_controller, +)
class TestVersion(unittest.TestCase): @@ -19,7 +22,7 @@ class TestVersion(unittest.TestCase): """
if not stem.util.system.is_available('tor'): - test.runner.skip(self, "(tor isn't in our path)") + skip(self, "(tor isn't in our path)") return
# Since tor is in our path we should expect to be able to get the version diff --git a/test/runner.py b/test/runner.py index 7c98d58..a494b65 100644 --- a/test/runner.py +++ b/test/runner.py @@ -11,14 +11,9 @@ about the tor test instance they're running against. RunnerStopped - Runner doesn't have an active tor instance TorInaccessable - Tor can't be queried for the information
- skip - skips the current test if we can - require_controller - skips the test unless tor provides a controller endpoint - require_version - skips the test unless we meet a tor version requirement - require_online - skips unless targets allow for online tests - only_run_once - skip the test if it has been ran before exercise_controller - basic sanity check that a controller connection can be used - get_runner - Singleton for fetching our runtime context. + Runner - Runtime context for our integration tests. |- start - prepares and starts a tor instance for our tests to run against |- stop - stops our tor instance and cleans up any temporary files @@ -90,8 +85,6 @@ Torrc = stem.util.enum.Enum( ('PTRACE', 'DisableDebuggerAttachment 0'), )
-RAN_TESTS = [] -
class RunnerStopped(Exception): "Raised when we try to use a Runner that doesn't have an active tor instance" @@ -101,85 +94,6 @@ class TorInaccessable(Exception): 'Raised when information is needed from tor but the instance we have is inaccessible'
-def skip(test_case, message): - """ - Skips the test if we can. The capability for skipping tests was added in - python 2.7 so callers should return after this, so they report 'success' if - this method is unavailable. - - :param unittest.TestCase test_case: test being ran - :param str message: message to skip the test with - """ - - if not stem.prereq._is_python_26(): - test_case.skipTest(message) - - -def require_controller(func): - """ - Skips the test unless tor provides an endpoint for controllers to attach to. - """ - - def wrapped(self, *args, **kwargs): - if get_runner().is_accessible(): - return func(self, *args, **kwargs) - else: - skip(self, '(no connection)') - - return wrapped - - -def require_version(req_version): - """ - Skips the test unless we meet the required version. - - :param stem.version.Version req_version: required tor version for the test - """ - - def decorator(func): - def wrapped(self, *args, **kwargs): - if tor_version() >= req_version: - return func(self, *args, **kwargs) - else: - skip(self, '(requires %s)' % req_version) - - return wrapped - - return decorator - - -def require_online(func): - """ - Skips the test if we weren't started with the ONLINE target, which indicates - that tests requiring network connectivity should run. - """ - - def wrapped(self, *args, **kwargs): - if Target.ONLINE in get_runner().attribute_targets: - return func(self, *args, **kwargs) - else: - skip(self, '(requires online target)') - - return wrapped - - -def only_run_once(func): - """ - Skips the test if it has ran before. If it hasn't then flags it as being ran. - This is useful to prevent lengthy tests that are independent of integ targets - from being run repeatedly with ``RUN_ALL``. - """ - - def wrapped(self, *args, **kwargs): - if self.id() not in RAN_TESTS: - RAN_TESTS.append(self.id()) - return func(self, *args, **kwargs) - else: - skip(self, '(already ran)') - - return wrapped - - def exercise_controller(test_case, controller): """ Checks that we can now use the socket by issuing a 'GETINFO config-file' diff --git a/test/unit/descriptor/certificate.py b/test/unit/descriptor/certificate.py index 669d9ad..0cef45a 100644 --- a/test/unit/descriptor/certificate.py +++ b/test/unit/descriptor/certificate.py @@ -10,10 +10,10 @@ import unittest import stem.descriptor.certificate import stem.util.str_tools import stem.prereq -import test.runner
from stem.descriptor.certificate import ED25519_SIGNATURE_LENGTH, CertType, ExtensionType, ExtensionFlag, Ed25519Certificate, Ed25519CertificateV1, Ed25519Extension from test.unit.descriptor import get_resource +from test.util import require_pynacl
ED25519_CERT = """ AQQABhtZAaW2GoBED1IjY3A6f6GNqBEl5A83fD2Za9upGke51JGqAQAgBABnprVR @@ -147,46 +147,37 @@ class TestEd25519Certificate(unittest.TestCase):
self.assert_raises(certificate(extension_data = [b'\x00\x02\x04\x07\11\12']), "Ed25519 HAS_SIGNING_KEY extension must be 32 bytes, but was 2.")
+ @require_pynacl def test_validation_with_descriptor_key(self): """ Validate a descriptor signature using the ed25519 master key within the descriptor. """
- if not stem.prereq._is_pynacl_available(): - test.runner.skip(self, '(requires pynacl module)') - return - with open(get_resource('server_descriptor_with_ed25519'), 'rb') as descriptor_file: desc = next(stem.descriptor.parse_file(descriptor_file, validate = False))
desc.certificate.validate(desc)
+ @require_pynacl def test_validation_with_embedded_key(self): """ Validate a descriptor signature using the signing key within the ed25519 certificate. """
- if not stem.prereq._is_pynacl_available(): - test.runner.skip(self, '(requires pynacl module)') - return - with open(get_resource('server_descriptor_with_ed25519'), 'rb') as descriptor_file: desc = next(stem.descriptor.parse_file(descriptor_file, validate = False))
desc.ed25519_master_key = None desc.certificate.validate(desc)
+ @require_pynacl def test_validation_with_invalid_descriptor(self): """ Validate a descriptor without a valid signature. """
- if not stem.prereq._is_pynacl_available(): - test.runner.skip(self, '(requires pynacl module)') - return - with open(get_resource('server_descriptor_with_ed25519'), 'rb') as descriptor_file: desc = next(stem.descriptor.parse_file(descriptor_file, validate = False))
diff --git a/test/unit/descriptor/export.py b/test/unit/descriptor/export.py index 31537c5..ae7e4a0 100644 --- a/test/unit/descriptor/export.py +++ b/test/unit/descriptor/export.py @@ -10,9 +10,9 @@ except ImportError: from io import StringIO
import stem.prereq -import test.runner
from stem.descriptor.export import export_csv, export_csv_file +from test.util import skip
from test.mocking import ( get_relay_server_descriptor, @@ -27,7 +27,7 @@ class TestExport(unittest.TestCase): """
if stem.prereq._is_python_26(): - test.runner.skip(self, '(header added in python 2.7)') + skip(self, '(header added in python 2.7)') return
desc = get_relay_server_descriptor() @@ -76,7 +76,7 @@ class TestExport(unittest.TestCase): """
if stem.prereq._is_python_26(): - test.runner.skip(self, '(header added in python 2.7)') + skip(self, '(header added in python 2.7)') return
desc = get_relay_server_descriptor() diff --git a/test/unit/descriptor/hidden_service_descriptor.py b/test/unit/descriptor/hidden_service_descriptor.py index 74a0974..6f9fb26 100644 --- a/test/unit/descriptor/hidden_service_descriptor.py +++ b/test/unit/descriptor/hidden_service_descriptor.py @@ -8,10 +8,9 @@ import unittest import stem.descriptor import stem.prereq
-import test.runner - from test.mocking import CRYPTO_BLOB, get_hidden_service_descriptor from test.unit.descriptor import get_resource +from test.util import require_cryptography
from stem.descriptor.hidden_service_descriptor import ( REQUIRED_FIELDS, @@ -267,14 +266,12 @@ class TestHiddenServiceDescriptor(unittest.TestCase): self.assertEqual(datetime.datetime(2014, 10, 31, 23, 0, 0), desc.published) self.assertEqual([2, 3], desc.protocol_versions)
+ @require_cryptography def test_with_basic_auth(self): """ Parse a descriptor with introduction-points encrypted with basic auth. """
- if not stem.prereq.is_crypto_available(): - return test.runner.skip(self, 'requires cryptography') - descriptor_file = open(get_resource('hidden_service_basic_auth'), 'rb')
desc = next(stem.descriptor.parse_file(descriptor_file, 'hidden-service-descriptor 1.0', validate = True)) @@ -316,14 +313,12 @@ class TestHiddenServiceDescriptor(unittest.TestCase): self.assertTrue('MIGJAoGBAM7B/cymp' in point.service_key) self.assertEqual([], point.intro_authentication)
+ @require_cryptography def test_with_stealth_auth(self): """ Parse a descriptor with introduction-points encrypted with stealth auth. """
- if not stem.prereq.is_crypto_available(): - return test.runner.skip(self, 'requires cryptography') - descriptor_file = open(get_resource('hidden_service_stealth_auth'), 'rb')
desc = next(stem.descriptor.parse_file(descriptor_file, 'hidden-service-descriptor 1.0', validate = True)) diff --git a/test/unit/descriptor/reader.py b/test/unit/descriptor/reader.py index 51043e2..ac7fd83 100644 --- a/test/unit/descriptor/reader.py +++ b/test/unit/descriptor/reader.py @@ -14,10 +14,10 @@ import time import unittest
import stem.descriptor.reader -import test.runner import test.unit.descriptor
from stem.util import str_type, system +from test.util import skip
try: # added in python 3.3 @@ -191,7 +191,7 @@ class TestDescriptorReader(unittest.TestCase): # test relies on being unable to read a file
if getpass.getuser() == 'root': - test.runner.skip(self, '(running as root)') + skip(self, '(running as root)') return
# Skip the test on windows, since you can only set the file's @@ -199,7 +199,7 @@ class TestDescriptorReader(unittest.TestCase): # http://docs.python.org/library/os.html#os.chmod
if system.is_windows(): - test.runner.skip(self, '(chmod not functional)') + skip(self, '(chmod not functional)')
test_listing_path = self._make_processed_files_listing(BASIC_LISTING) os.chmod(test_listing_path, 0o077) # remove read permissions @@ -413,7 +413,7 @@ class TestDescriptorReader(unittest.TestCase): # Skip on windows since SIGALRM is unavailable
if system.is_windows(): - test.runner.skip(self, '(SIGALRM unavailable)') + skip(self, '(SIGALRM unavailable)')
is_test_running = True reader = stem.descriptor.reader.DescriptorReader('/usr') @@ -550,10 +550,10 @@ class TestDescriptorReader(unittest.TestCase): # test relies on being unable to read a file
if getpass.getuser() == 'root': - test.runner.skip(self, '(running as root)') + skip(self, '(running as root)') return elif system.is_windows(): - test.runner.skip(self, '(chmod not functional)') + skip(self, '(chmod not functional)') return
test_path = os.path.join(self.temp_directory, 'secret_file') diff --git a/test/unit/installation.py b/test/unit/installation.py index 773e0f1..83d560a 100644 --- a/test/unit/installation.py +++ b/test/unit/installation.py @@ -3,9 +3,10 @@ import os import re import unittest
-import test.runner import test.util
+from test.util import skip +
class TestInstallation(unittest.TestCase): # TODO: remove when dropping support for python 2.6 @@ -25,7 +26,7 @@ class TestInstallation(unittest.TestCase):
def test_installs_all_modules(self): if self.skip_reason: - test.runner.skip(self, self.skip_reason) + skip(self, self.skip_reason) return True
# Modules cited my our setup.py looks like... @@ -49,7 +50,7 @@ class TestInstallation(unittest.TestCase):
def test_installs_all_data_files(self): if self.skip_reason: - test.runner.skip(self, self.skip_reason) + skip(self, self.skip_reason) return True
# Checking that we have all non-source files. Data looks like... diff --git a/test/unit/manual.py b/test/unit/manual.py index becefd5..deded2d 100644 --- a/test/unit/manual.py +++ b/test/unit/manual.py @@ -12,7 +12,7 @@ import stem.prereq import stem.manual import stem.util.system
-import test.runner +from test.util import skip
try: # account for urllib's change between python 2.x and 3.x @@ -160,10 +160,10 @@ class TestManual(unittest.TestCase): """
if not stem.util.system.is_available('man'): - test.runner.skip(self, '(require man command)') + skip(self, '(require man command)') return elif stem.util.system.is_mac(): - test.runner.skip(self, '(man lacks --encoding arg on OSX, #18660)') + skip(self, '(man lacks --encoding arg on OSX, #18660)') return
manual = stem.manual.Manual.from_man(EXAMPLE_MAN_PATH) @@ -183,10 +183,10 @@ class TestManual(unittest.TestCase): """
if not stem.util.system.is_available('man'): - test.runner.skip(self, '(require man command)') + skip(self, '(require man command)') return elif stem.util.system.is_mac(): - test.runner.skip(self, '(man lacks --encoding arg on OSX, #18660)') + skip(self, '(man lacks --encoding arg on OSX, #18660)') return
manual = stem.manual.Manual.from_man(UNKNOWN_OPTIONS_MAN_PATH) @@ -213,7 +213,7 @@ class TestManual(unittest.TestCase): """
if not stem.util.system.is_available('man'): - test.runner.skip(self, '(require man command)') + skip(self, '(require man command)') return
manual = stem.manual.Manual.from_man(EXAMPLE_MAN_PATH) diff --git a/test/unit/tutorial_examples.py b/test/unit/tutorial_examples.py index e316766..bf313ce 100644 --- a/test/unit/tutorial_examples.py +++ b/test/unit/tutorial_examples.py @@ -15,14 +15,14 @@ import stem.response import stem.descriptor.remote import stem.prereq
-import test.runner - from stem.control import Controller from stem.util import str_type from stem.descriptor.remote import DIRECTORY_AUTHORITIES
from test import mocking from test.unit import exec_documentation_example +from test.util import skip + from test.mocking import ( get_relay_server_descriptor, get_router_status_entry_v3, @@ -247,7 +247,7 @@ class TestTutorialExamples(unittest.TestCase): # example imports OrderedDict from collections which doesn't work under # python 2.6
- test.runner.skip(self, "(example doesn't support python 2.6)") + skip(self, "(example doesn't support python 2.6)") return
get_authorities_mock().items.return_value = [('moria1', DIRECTORY_AUTHORITIES['moria1']), ('maatuska', DIRECTORY_AUTHORITIES['maatuska'])] diff --git a/test/util.py b/test/util.py index 2a58e2f..75ea50e 100644 --- a/test/util.py +++ b/test/util.py @@ -18,6 +18,18 @@ Tasks are...
::
+ Test Skipping + |- skip - skips the current test if we can + |- only_run_once - skip test if it has been ran before + |- require - skips the test unless a requirement is met + | + |- require_cryptography - skips test unless the cryptography module is present + |- require_pynacl - skips test unless the pynacl module is present + | + |- require_controller - skips test unless tor provides a controller endpoint + |- require_version - skips test unless we meet a tor version requirement + +- require_online - skips unless targets allow for online tests + Initialization |- check_stem_version - checks our version of stem |- check_tor_version - checks our version of tor @@ -28,6 +40,8 @@ Tasks are... |- check_pycodestyle_version - checks our version of pycodestyle |- clean_orphaned_pyc - removes any *.pyc without a corresponding *.py +- check_for_unused_tests - checks to see if any tests are missing from our settings + + tor_version - provides the version of tor we're testing against """
import re @@ -79,6 +93,7 @@ Target = stem.util.enum.UppercaseEnum( )
TOR_VERSION = None +RAN_TESTS = []
# 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. @@ -205,6 +220,97 @@ def get_new_capabilities(): return NEW_CAPABILITIES
+def skip(test_case, message): + """ + Skips the test if we can. The capability for skipping tests was added in + python 2.7 so callers should return after this, so they report 'success' if + this method is unavailable. + + :param unittest.TestCase test_case: test being ran + :param str message: message to skip the test with + """ + + if not stem.prereq._is_python_26(): + test_case.skipTest(message) + + +def only_run_once(func): + """ + Skips the test if it has ran before. If it hasn't then flags it as being ran. + This is useful to prevent lengthy tests that are independent of integ targets + from being run repeatedly with ``RUN_ALL``. + """ + + def wrapped(self, *args, **kwargs): + if self.id() not in RAN_TESTS: + RAN_TESTS.append(self.id()) + return func(self, *args, **kwargs) + else: + skip(self, '(already ran)') + + return wrapped + + +def require(condition, message): + """ + Skips teh test unless the conditional evaluates to 'true'. + """ + + def decorator(func): + def wrapped(self, *args, **kwargs): + if condition(): + return func(self, *args, **kwargs) + else: + skip(self, '(%s)' % message) + + return wrapped + + return decorator + + +require_cryptography = require(stem.prereq.is_crypto_available, 'requires cryptography') +require_pynacl = require(stem.prereq._is_pynacl_available, 'requires pynacl module') + + +def require_controller(func): + """ + Skips the test unless tor provides an endpoint for controllers to attach to. + """ + + def wrapped(self, *args, **kwargs): + if test.runner.get_runner().is_accessible(): + return func(self, *args, **kwargs) + else: + skip(self, '(no connection)') + + return wrapped + + +def require_version(req_version): + """ + Skips the test unless we meet the required version. + + :param stem.version.Version req_version: required tor version for the test + """ + + return require(lambda: tor_version() >= req_version, 'requires %s' % req_version) + + +def require_online(func): + """ + Skips the test if we weren't started with the ONLINE target, which indicates + that tests requiring network connectivity should run. + """ + + def wrapped(self, *args, **kwargs): + if Target.ONLINE in test.runner.get_runner().attribute_targets: + return func(self, *args, **kwargs) + else: + skip(self, '(requires online target)') + + return wrapped + + def check_stem_version(): return stem.__version__
@@ -432,3 +538,6 @@ class Task(object):
println(output_msg, ERROR) self.error = exc + + +import test.runner # needs to be imported at the end to avoid a circular dependency