commit a29627184ea7d50dc4072dfc4115e68372c52d5f Author: Damian Johnson atagar@torproject.org Date: Thu May 18 15:35:32 2017 -0700
Move test requirements to its own module
Moving the @require_* annotations to its own dedicated module. Besides the obvious breakup of test.util this provides namespacing so we can truncate the function names and use a standard import. --- test/integ/connection/authentication.py | 25 ++-- test/integ/connection/connect.py | 9 +- test/integ/control/base_controller.py | 20 ++- test/integ/control/controller.py | 153 +++++++++++----------- test/integ/descriptor/extrainfo_descriptor.py | 8 +- test/integ/descriptor/microdescriptor.py | 8 +- test/integ/descriptor/networkstatus.py | 18 +-- test/integ/descriptor/remote.py | 46 +++---- test/integ/descriptor/server_descriptor.py | 9 +- test/integ/installation.py | 8 +- test/integ/interpreter.py | 8 +- test/integ/process.py | 37 +++--- test/integ/response/protocolinfo.py | 11 +- test/integ/socket/control_message.py | 21 ++- test/integ/socket/control_socket.py | 17 +-- test/integ/util/connection.py | 4 +- test/integ/util/proc.py | 20 ++- test/integ/util/system.py | 64 ++++----- test/integ/version.py | 10 +- test/require.py | 106 +++++++++++++++ test/unit/descriptor/certificate.py | 8 +- test/unit/descriptor/hidden_service_descriptor.py | 7 +- test/unit/manual.py | 9 +- test/util.py | 101 +------------- 24 files changed, 341 insertions(+), 386 deletions(-)
diff --git a/test/integ/connection/authentication.py b/test/integ/connection/authentication.py index 007042f..f43a61d 100644 --- a/test/integ/connection/authentication.py +++ b/test/integ/connection/authentication.py @@ -9,9 +9,10 @@ import unittest import stem.connection import stem.socket import stem.version +import test.require import test.runner
-from test.util import require_controller, tor_version +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. @@ -106,7 +107,7 @@ class TestAuthenticate(unittest.TestCase): if tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE: self.cookie_auth_methods.append(stem.connection.AuthMethod.SAFECOOKIE)
- @require_controller + @test.require.controller def test_authenticate_general_socket(self): """ Tests that the authenticate function can authenticate to our socket. @@ -118,7 +119,7 @@ class TestAuthenticate(unittest.TestCase): stem.connection.authenticate(control_socket, test.runner.CONTROL_PASSWORD, runner.get_chroot()) test.runner.exercise_controller(self, control_socket)
- @require_controller + @test.require.controller def test_authenticate_general_controller(self): """ Tests that the authenticate function can authenticate via a Controller. @@ -130,7 +131,7 @@ class TestAuthenticate(unittest.TestCase): stem.connection.authenticate(controller, test.runner.CONTROL_PASSWORD, runner.get_chroot()) test.runner.exercise_controller(self, controller)
- @require_controller + @test.require.controller def test_authenticate_general_example(self): """ Tests the authenticate function with something like its pydoc example. @@ -166,7 +167,7 @@ class TestAuthenticate(unittest.TestCase): finally: control_socket.close()
- @require_controller + @test.require.controller def test_authenticate_general_password(self): """ Tests the authenticate function's password argument. @@ -201,7 +202,7 @@ class TestAuthenticate(unittest.TestCase): stem.connection.authenticate(control_socket, test.runner.CONTROL_PASSWORD, runner.get_chroot()) test.runner.exercise_controller(self, control_socket)
- @require_controller + @test.require.controller def test_authenticate_general_cookie(self): """ Tests the authenticate function with only cookie authentication methods. @@ -226,7 +227,7 @@ class TestAuthenticate(unittest.TestCase): protocolinfo_response.auth_methods = (method, ) stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot(), protocolinfo_response = protocolinfo_response)
- @require_controller + @test.require.controller def test_authenticate_none(self): """ Tests the authenticate_none function. @@ -239,7 +240,7 @@ class TestAuthenticate(unittest.TestCase): else: self.assertRaises(stem.connection.OpenAuthRejected, self._check_auth, auth_type)
- @require_controller + @test.require.controller def test_authenticate_password(self): """ Tests the authenticate_password function. @@ -267,7 +268,7 @@ class TestAuthenticate(unittest.TestCase):
self.assertRaises(exc_type, self._check_auth, auth_type, auth_value)
- @require_controller + @test.require.controller def test_authenticate_cookie(self): """ Tests the authenticate_cookie function. @@ -289,7 +290,7 @@ class TestAuthenticate(unittest.TestCase): else: self.assertRaises(stem.connection.CookieAuthRejected, self._check_auth, auth_type, auth_value, False)
- @require_controller + @test.require.controller def test_authenticate_cookie_invalid(self): """ Tests the authenticate_cookie function with a properly sized but incorrect @@ -326,7 +327,7 @@ class TestAuthenticate(unittest.TestCase):
os.remove(auth_value)
- @require_controller + @test.require.controller def test_authenticate_cookie_missing(self): """ Tests the authenticate_cookie function with a path that really, really @@ -337,7 +338,7 @@ class TestAuthenticate(unittest.TestCase): auth_value = "/if/this/exists/then/they're/asking/for/a/failure" self.assertRaises(stem.connection.UnreadableCookieFile, self._check_auth, auth_type, auth_value, False)
- @require_controller + @test.require.controller def test_authenticate_cookie_wrong_size(self): """ Tests the authenticate_cookie function with our torrc as an auth cookie. diff --git a/test/integ/connection/connect.py b/test/integ/connection/connect.py index d50b3af..fd08742 100644 --- a/test/integ/connection/connect.py +++ b/test/integ/connection/connect.py @@ -11,10 +11,9 @@ except ImportError: from io import StringIO
import stem.connection +import test.require import test.runner
-from test.util import require_controller -
class TestConnect(unittest.TestCase): def setUp(self): @@ -25,7 +24,7 @@ class TestConnect(unittest.TestCase): def tearDown(self): sys.stdout = self.original_stdout
- @require_controller + @test.require.controller def test_connect(self): """ Basic sanity checks for the connect function. @@ -42,7 +41,7 @@ class TestConnect(unittest.TestCase):
test.runner.exercise_controller(self, control_socket)
- @require_controller + @test.require.controller def test_connect_port(self): """ Basic sanity checks for the connect_port function. @@ -62,7 +61,7 @@ class TestConnect(unittest.TestCase): else: self.assertEqual(control_socket, None)
- @require_controller + @test.require.controller def test_connect_socket_file(self): """ Basic sanity checks for the connect_socket_file function. diff --git a/test/integ/control/base_controller.py b/test/integ/control/base_controller.py index 1e64445..4c618e3 100644 --- a/test/integ/control/base_controller.py +++ b/test/integ/control/base_controller.py @@ -10,12 +10,10 @@ import unittest import stem.control import stem.socket import stem.util.system - +import test.require import test.runner import test.util
-from test.util import require_controller -
class StateObserver(object): """ @@ -39,7 +37,7 @@ class StateObserver(object):
class TestBaseController(unittest.TestCase): - @require_controller + @test.require.controller def test_connect_repeatedly(self): """ Connects and closes the socket repeatedly. This is a simple attempt to @@ -57,7 +55,7 @@ class TestBaseController(unittest.TestCase): controller.connect() controller.close()
- @require_controller + @test.require.controller def test_msg(self): """ Tests a basic query with the msg() method. @@ -67,7 +65,7 @@ class TestBaseController(unittest.TestCase): controller = stem.control.BaseController(control_socket) test.runner.exercise_controller(self, controller)
- @require_controller + @test.require.controller def test_msg_invalid(self): """ Tests the msg() method against an invalid controller command. @@ -78,7 +76,7 @@ class TestBaseController(unittest.TestCase): response = controller.msg('invalid') self.assertEqual('Unrecognized command "invalid"', str(response))
- @require_controller + @test.require.controller def test_msg_invalid_getinfo(self): """ Tests the msg() method against a non-existant GETINFO option. @@ -89,7 +87,7 @@ class TestBaseController(unittest.TestCase): response = controller.msg('GETINFO blarg') self.assertEqual('Unrecognized key "blarg"', str(response))
- @require_controller + @test.require.controller def test_msg_repeatedly(self): """ Connects, sends a burst of messages, and closes the socket repeatedly. This @@ -127,7 +125,7 @@ class TestBaseController(unittest.TestCase): for msg_thread in message_threads: msg_thread.join()
- @require_controller + @test.require.controller def test_asynchronous_event_handling(self): """ Check that we can both receive asynchronous events while hammering our @@ -181,7 +179,7 @@ class TestBaseController(unittest.TestCase): self.assertTrue(conf_changed_event.raw_content().startswith('650-CONF_CHANGED\r\n650-NodeFamily=')) self.assertEqual(('650', '-'), conf_changed_event.content()[0][:2])
- @require_controller + @test.require.controller def test_get_latest_heartbeat(self): """ Basic check for get_latest_heartbeat(). @@ -193,7 +191,7 @@ class TestBaseController(unittest.TestCase): controller.msg('GETINFO version') self.assertTrue((time.time() - controller.get_latest_heartbeat()) < 5)
- @require_controller + @test.require.controller def test_status_notifications(self): """ Checks basic functionality of the add_status_listener() and diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py index 2445221..32ce047 100644 --- a/test/integ/control/controller.py +++ b/test/integ/control/controller.py @@ -19,6 +19,7 @@ import stem.socket import stem.util.str_tools import stem.version import test.network +import test.require import test.runner
from stem import Flag, Signal @@ -26,15 +27,7 @@ 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, - random_fingerprint, - tor_version, - only_run_once, - require_controller, - require_version, - require_online, -) +from test.util import register_new_capability, random_fingerprint, 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. @@ -43,8 +36,8 @@ TEST_ROUTER_STATUS_ENTRY = None
class TestController(unittest.TestCase): - @only_run_once - @require_controller + @test.require.only_run_once + @test.require.controller def test_missing_capabilities(self): """ Check to see if tor supports any events, signals, or features that we @@ -88,8 +81,8 @@ class TestController(unittest.TestCase): else: self.assertRaises(stem.SocketError, stem.control.Controller.from_socket_file, test.runner.CONTROL_SOCKET_PATH)
- @require_controller - @require_version(Requirement.EVENT_SIGNAL) + @test.require.controller + @test.require.version(Requirement.EVENT_SIGNAL) def test_reset_notification(self): """ Checks that a notificiation listener is... well, notified of SIGHUPs. @@ -125,7 +118,7 @@ class TestController(unittest.TestCase):
controller.reset_conf('__OwningControllerProcess')
- @require_controller + @test.require.controller def test_event_handling(self): """ Add a couple listeners for various events and make sure that they receive @@ -183,7 +176,7 @@ class TestController(unittest.TestCase):
controller.reset_conf('NodeFamily')
- @require_controller + @test.require.controller def test_reattaching_listeners(self): """ Checks that event listeners are re-attached when a controller disconnects @@ -224,7 +217,7 @@ class TestController(unittest.TestCase):
controller.reset_conf('NodeFamily')
- @require_controller + @test.require.controller def test_getinfo(self): """ Exercises GETINFO with valid and invalid queries. @@ -262,7 +255,7 @@ class TestController(unittest.TestCase): self.assertEqual({}, controller.get_info([])) self.assertEqual({}, controller.get_info([], {}))
- @require_controller + @test.require.controller def test_get_version(self): """ Test that the convenient method get_version() works. @@ -275,7 +268,7 @@ class TestController(unittest.TestCase): self.assertTrue(isinstance(version, stem.version.Version)) self.assertEqual(version, tor_version())
- @require_controller + @test.require.controller def test_get_exit_policy(self): """ Sanity test for get_exit_policy(). We have the default policy (no @@ -318,7 +311,7 @@ class TestController(unittest.TestCase): policy_str = policy_str[:public_addr_start] + policy_str[public_addr_end:] self.assertEqual(str(expected), policy_str)
- @require_controller + @test.require.controller def test_authenticate(self): """ Test that the convenient method authenticate() works. @@ -330,7 +323,7 @@ class TestController(unittest.TestCase): controller.authenticate(test.runner.CONTROL_PASSWORD) test.runner.exercise_controller(self, controller)
- @require_controller + @test.require.controller def test_protocolinfo(self): """ Test that the convenient method protocolinfo() works. @@ -360,7 +353,7 @@ class TestController(unittest.TestCase):
self.assertEqual(tuple(auth_methods), protocolinfo.auth_methods)
- @require_controller + @test.require.controller def test_getconf(self): """ Exercises GETCONF with valid and invalid queries. @@ -423,7 +416,7 @@ class TestController(unittest.TestCase): self.assertEqual({}, controller.get_conf_map('', 'la-di-dah')) self.assertEqual({}, controller.get_conf_map([], 'la-di-dah'))
- @require_controller + @test.require.controller def test_is_set(self): """ Exercises our is_set() method. @@ -450,7 +443,7 @@ class TestController(unittest.TestCase): controller.reset_conf('ConnLimit') self.assertFalse(controller.is_set('ConnLimit'))
- @require_controller + @test.require.controller def test_hidden_services_conf(self): """ Exercises the hidden service family of methods (get_hidden_service_conf, @@ -557,8 +550,8 @@ class TestController(unittest.TestCase): except: pass
- @require_controller - @require_version(Requirement.ADD_ONION) + @test.require.controller + @test.require.version(Requirement.ADD_ONION) def test_without_ephemeral_hidden_services(self): """ Exercises ephemeral hidden service methods when none are present. @@ -569,8 +562,8 @@ class TestController(unittest.TestCase): self.assertEqual([], controller.list_ephemeral_hidden_services(detached = True)) self.assertEqual(False, controller.remove_ephemeral_hidden_service('gfzprpioee3hoppz'))
- @require_controller - @require_version(Requirement.ADD_ONION) + @test.require.controller + @test.require.version(Requirement.ADD_ONION) def test_with_ephemeral_hidden_services(self): """ Exercises creating ephemeral hidden services and methods when they're @@ -620,8 +613,8 @@ class TestController(unittest.TestCase): self.assertEqual(2, len(controller.list_ephemeral_hidden_services())) self.assertEqual(0, len(second_controller.list_ephemeral_hidden_services()))
- @require_controller - @require_version(Requirement.ADD_ONION_BASIC_AUTH) + @test.require.controller + @test.require.version(Requirement.ADD_ONION_BASIC_AUTH) def test_with_ephemeral_hidden_services_basic_auth(self): """ Exercises creating ephemeral hidden services that uses basic authentication. @@ -640,8 +633,8 @@ class TestController(unittest.TestCase): self.assertEqual(True, controller.remove_ephemeral_hidden_service(response.service_id)) self.assertEqual([], controller.list_ephemeral_hidden_services())
- @require_controller - @require_version(Requirement.ADD_ONION_BASIC_AUTH) + @test.require.controller + @test.require.version(Requirement.ADD_ONION_BASIC_AUTH) def test_with_ephemeral_hidden_services_basic_auth_no_credentials(self): """ Exercises creating ephemeral hidden services when attempting to use basic @@ -654,8 +647,8 @@ class TestController(unittest.TestCase): exc_msg = "ADD_ONION response didn't have an OK status: No auth clients specified" self.assertRaisesRegexp(stem.ProtocolError, exc_msg, controller.create_ephemeral_hidden_service, 4567, basic_auth = {})
- @require_controller - @require_version(Requirement.ADD_ONION) + @test.require.controller + @test.require.version(Requirement.ADD_ONION) def test_with_detached_ephemeral_hidden_services(self): """ Exercises creating detached ephemeral hidden services and methods when @@ -690,7 +683,7 @@ class TestController(unittest.TestCase): self.assertEqual([response.service_id], controller.list_ephemeral_hidden_services(detached = True)) controller.remove_ephemeral_hidden_service(response.service_id)
- @require_controller + @test.require.controller def test_set_conf(self): """ Exercises set_conf(), reset_conf(), and set_options() methods with valid @@ -763,8 +756,8 @@ class TestController(unittest.TestCase):
shutil.rmtree(tmpdir)
- @require_controller - @require_version(Requirement.LOADCONF) + @test.require.controller + @test.require.version(Requirement.LOADCONF) def test_loadconf(self): """ Exercises Controller.load_conf with valid and invalid requests. @@ -801,7 +794,7 @@ class TestController(unittest.TestCase): controller.load_conf(oldconf) controller.reset_conf('__OwningControllerProcess')
- @require_controller + @test.require.controller def test_saveconf(self): runner = test.runner.get_runner()
@@ -821,7 +814,7 @@ class TestController(unittest.TestCase): controller.save_conf() controller.reset_conf('__OwningControllerProcess')
- @require_controller + @test.require.controller def test_get_ports(self): """ Test Controller.get_ports against a running tor instance. @@ -842,7 +835,7 @@ class TestController(unittest.TestCase): else: self.assertEqual([], controller.get_ports(Listener.CONTROL))
- @require_controller + @test.require.controller def test_get_listeners(self): """ Test Controller.get_listeners against a running tor instance. @@ -863,7 +856,7 @@ class TestController(unittest.TestCase): else: self.assertEqual([], controller.get_listeners(Listener.CONTROL))
- @require_controller + @test.require.controller def test_get_socks_listeners(self): """ Test Controller.get_socks_listeners against a running tor instance. @@ -872,9 +865,9 @@ class TestController(unittest.TestCase): with test.runner.get_runner().get_tor_controller() as controller: self.assertEqual([('127.0.0.1', 1112)], controller.get_socks_listeners())
- @require_controller - @require_online - @require_version(stem.version.Version('0.1.2.2-alpha')) + @test.require.controller + @test.require.online + @test.require.version(stem.version.Version('0.1.2.2-alpha')) def test_enable_feature(self): """ Test Controller.enable_feature with valid and invalid inputs. @@ -895,7 +888,7 @@ class TestController(unittest.TestCase): else: self.fail()
- @require_controller + @test.require.controller def test_signal(self): """ Test controller.signal with valid and invalid signals. @@ -908,7 +901,7 @@ class TestController(unittest.TestCase): # invalid signals self.assertRaises(stem.InvalidArguments, controller.signal, 'FOOBAR')
- @require_controller + @test.require.controller def test_newnym_availability(self): """ Test the is_newnym_available and get_newnym_wait methods. @@ -923,9 +916,9 @@ class TestController(unittest.TestCase): self.assertEqual(False, controller.is_newnym_available()) self.assertTrue(controller.get_newnym_wait() > 9.0)
- @require_controller - @require_online - @require_version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) + @test.require.controller + @test.require.online + @test.require.version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) def test_extendcircuit(self): with test.runner.get_runner().get_tor_controller() as controller: circuit_id = controller.extend_circuit('0') @@ -939,9 +932,9 @@ class TestController(unittest.TestCase): self.assertRaises(stem.InvalidRequest, controller.extend_circuit, '0', 'thisroutershouldntexistbecausestemexists!@##$%#') self.assertRaises(stem.InvalidRequest, controller.extend_circuit, '0', 'thisroutershouldntexistbecausestemexists!@##$%#', 'foo')
- @require_controller - @require_online - @require_version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) + @test.require.controller + @test.require.online + @test.require.version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) def test_repurpose_circuit(self): """ Tests Controller.repurpose_circuit with valid and invalid input. @@ -962,9 +955,9 @@ class TestController(unittest.TestCase): self.assertRaises(stem.InvalidRequest, controller.repurpose_circuit, 'f934h9f3h4', 'fooo') self.assertRaises(stem.InvalidRequest, controller.repurpose_circuit, '4', 'fooo')
- @require_controller - @require_online - @require_version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) + @test.require.controller + @test.require.online + @test.require.version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) def test_close_circuit(self): """ Tests Controller.close_circuit with valid and invalid input. @@ -989,8 +982,8 @@ class TestController(unittest.TestCase): self.assertRaises(stem.InvalidArguments, controller.close_circuit, circuit_id + '1024') self.assertRaises(stem.InvalidRequest, controller.close_circuit, '')
- @require_controller - @require_online + @test.require.controller + @test.require.online def test_get_streams(self): """ Tests Controller.get_streams(). @@ -1014,8 +1007,8 @@ class TestController(unittest.TestCase):
self.assertTrue('%s:%s' % (host, port) in [stream.target for stream in streams])
- @require_controller - @require_online + @test.require.controller + @test.require.online def test_close_stream(self): """ Tests Controller.close_stream with valid and invalid input. @@ -1053,8 +1046,8 @@ class TestController(unittest.TestCase):
self.assertRaises(stem.InvalidArguments, controller.close_stream, 'blarg')
- @require_controller - @require_online + @test.require.controller + @test.require.online def test_mapaddress(self): runner = test.runner.get_runner()
@@ -1091,9 +1084,9 @@ class TestController(unittest.TestCase): ip_addr = response[response.find(b'\r\n\r\n'):].strip() self.assertTrue(stem.util.connection.is_valid_ipv4_address(stem.util.str_tools._to_unicode(ip_addr)), "'%s' isn't an address" % ip_addr)
- @require_controller - @require_online - @require_version(Requirement.MICRODESCRIPTOR_IS_DEFAULT) + @test.require.controller + @test.require.online + @test.require.version(Requirement.MICRODESCRIPTOR_IS_DEFAULT) def test_get_microdescriptor(self): """ Basic checks for get_microdescriptor(). @@ -1116,7 +1109,7 @@ class TestController(unittest.TestCase):
self.assertEqual(md_by_fingerprint, md_by_nickname)
- @require_controller + @test.require.controller def test_get_microdescriptors(self): """ Fetches a few descriptors via the get_microdescriptors() method. @@ -1138,7 +1131,7 @@ class TestController(unittest.TestCase): if count > 10: break
- @require_controller + @test.require.controller def test_get_server_descriptor(self): """ Basic checks for get_server_descriptor(). @@ -1168,7 +1161,7 @@ class TestController(unittest.TestCase):
self.assertEqual(desc_by_fingerprint, desc_by_nickname)
- @require_controller + @test.require.controller def test_get_server_descriptors(self): """ Fetches a few descriptors via the get_server_descriptors() method. @@ -1195,8 +1188,8 @@ class TestController(unittest.TestCase): if count > 10: break
- @require_controller - @require_online + @test.require.controller + @test.require.online def test_get_network_status(self): """ Basic checks for get_network_status(). @@ -1219,8 +1212,8 @@ class TestController(unittest.TestCase):
self.assertEqual(desc_by_fingerprint, desc_by_nickname)
- @require_controller - @require_online + @test.require.controller + @test.require.online def test_get_network_statuses(self): """ Fetches a few descriptors via the get_network_statuses() method. @@ -1242,9 +1235,9 @@ class TestController(unittest.TestCase): if count > 10: break
- @require_controller - @require_online - @require_version(Requirement.HSFETCH) + @test.require.controller + @test.require.online + @test.require.version(Requirement.HSFETCH) def test_get_hidden_service_descriptor(self): """ Fetches a few descriptors via the get_hidden_service_descriptor() method. @@ -1268,9 +1261,9 @@ class TestController(unittest.TestCase): self.assertEqual('pop goes the weasel', controller.get_hidden_service_descriptor('m4cfuk6qp4lpu2g5', 'pop goes the weasel')) self.assertEqual(None, controller.get_hidden_service_descriptor('m4cfuk6qp4lpu2g5', await_result = False))
- @require_controller - @require_online - @require_version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) + @test.require.controller + @test.require.online + @test.require.version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) def test_attachstream(self): host = socket.gethostbyname('www.torproject.org') port = 80 @@ -1309,9 +1302,9 @@ class TestController(unittest.TestCase):
self.assertEqual(our_stream.circ_id, circuit_id)
- @require_controller - @require_online - @require_version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) + @test.require.controller + @test.require.online + @test.require.version(Requirement.EXTENDCIRCUIT_PATH_OPTIONAL) def test_get_circuits(self): """ Fetches circuits via the get_circuits() method. @@ -1322,7 +1315,7 @@ class TestController(unittest.TestCase): circuits = controller.get_circuits() self.assertTrue(new_circ in [circ.id for circ in circuits])
- @require_controller + @test.require.controller def test_transition_to_relay(self): """ Transitions Tor to turn into a relay, then back to a client. This helps to diff --git a/test/integ/descriptor/extrainfo_descriptor.py b/test/integ/descriptor/extrainfo_descriptor.py index 6ea2b16..205b917 100644 --- a/test/integ/descriptor/extrainfo_descriptor.py +++ b/test/integ/descriptor/extrainfo_descriptor.py @@ -6,16 +6,14 @@ import os import unittest
import stem.descriptor +import test.require import test.runner
-from test.util import ( - register_new_capability, - only_run_once, -) +from test.util import register_new_capability
class TestExtraInfoDescriptor(unittest.TestCase): - @only_run_once + @test.require.only_run_once def test_cached_descriptor(self): """ Parses the cached descriptor file in our data directory, checking that it diff --git a/test/integ/descriptor/microdescriptor.py b/test/integ/descriptor/microdescriptor.py index 97127d6..c6fa80e 100644 --- a/test/integ/descriptor/microdescriptor.py +++ b/test/integ/descriptor/microdescriptor.py @@ -6,16 +6,14 @@ import os import unittest
import stem.descriptor +import test.require import test.runner
-from test.util import ( - register_new_capability, - only_run_once, -) +from test.util import register_new_capability
class TestMicrodescriptor(unittest.TestCase): - @only_run_once + @test.require.only_run_once def test_cached_microdescriptors(self): """ Parses the cached microdescriptor file in our data directory, checking that diff --git a/test/integ/descriptor/networkstatus.py b/test/integ/descriptor/networkstatus.py index 59dca00..96fec77 100644 --- a/test/integ/descriptor/networkstatus.py +++ b/test/integ/descriptor/networkstatus.py @@ -9,20 +9,16 @@ import stem import stem.descriptor import stem.descriptor.remote import stem.version +import test.require import test.runner
-from test.util import ( - register_new_capability, - only_run_once, - require_cryptography, - require_online, -) +from test.util import register_new_capability
class TestNetworkStatus(unittest.TestCase): - @require_online - @require_cryptography - @only_run_once + @test.require.only_run_once + @test.require.online + @test.require.cryptography def test_signature_validation(self): """ The full consensus is pretty sizable so rather than storing a copy of it @@ -31,7 +27,7 @@ class TestNetworkStatus(unittest.TestCase):
stem.descriptor.remote.get_consensus(document_handler = stem.descriptor.DocumentHandler.DOCUMENT, validate = True).run()
- @only_run_once + @test.require.only_run_once def test_cached_consensus(self): """ Parses the cached-consensus file in our data directory. @@ -68,7 +64,7 @@ class TestNetworkStatus(unittest.TestCase):
self.assertTrue(count > 100)
- @only_run_once + @test.require.only_run_once def test_cached_microdesc_consensus(self): """ Parses the cached-microdesc-consensus file in our data directory. diff --git a/test/integ/descriptor/remote.py b/test/integ/descriptor/remote.py index b873b96..3123ef0 100644 --- a/test/integ/descriptor/remote.py +++ b/test/integ/descriptor/remote.py @@ -10,16 +10,12 @@ import stem.descriptor.networkstatus import stem.descriptor.remote import stem.descriptor.router_status_entry import stem.descriptor.server_descriptor - -from test.util import ( - only_run_once, - require_online, -) +import test.require
class TestDescriptorDownloader(unittest.TestCase): - @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_shorthand_aliases(self): """ Quick sanity test that we can call our shorthand aliases for getting @@ -35,8 +31,8 @@ class TestDescriptorDownloader(unittest.TestCase): consensus = list(stem.descriptor.remote.get_consensus()) self.assertTrue(len(consensus) > 50)
- @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_authorities_are_up_to_date(self): """ Check that our hardcoded directory authority data matches the present @@ -62,8 +58,8 @@ class TestDescriptorDownloader(unittest.TestCase): if getattr(auth, attr) != getattr(stem_auth, attr): self.fail('%s has %s %s, but we expected %s' % (auth.nickname, attr, getattr(auth, attr), getattr(stem_auth, attr)))
- @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_using_authorities(self): """ Fetches a descriptor from each of the directory authorities. This is @@ -94,8 +90,8 @@ class TestDescriptorDownloader(unittest.TestCase): self.assertEqual(1, len(descriptors)) self.assertEqual('moria1', descriptors[0].nickname)
- @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_use_directory_mirrors(self): """ Checks that we can fetch and use a list of directory mirrors. @@ -105,8 +101,8 @@ class TestDescriptorDownloader(unittest.TestCase): downloader.use_directory_mirrors() self.assertTrue(len(downloader._endpoints) > 50)
- @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_get_server_descriptors(self): """ Exercises the downloader's get_server_descriptors() method. @@ -138,8 +134,8 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual(2, len(list(multiple_query)))
- @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_get_extrainfo_descriptors(self): """ Exercises the downloader's get_extrainfo_descriptors() method. @@ -164,8 +160,8 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual(2, len(list(multiple_query)))
- @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_get_consensus(self): """ Exercises the downloader's get_consensus() method. @@ -180,8 +176,8 @@ class TestDescriptorDownloader(unittest.TestCase): self.assertTrue(len(consensus) > 50) self.assertTrue(isinstance(consensus[0], stem.descriptor.router_status_entry.RouterStatusEntryV3))
- @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_get_microdescriptor_consensus(self): """ Exercises the downloader's get_consensus() method for fetching a @@ -197,8 +193,8 @@ class TestDescriptorDownloader(unittest.TestCase): self.assertTrue(len(consensus) > 50) self.assertTrue(isinstance(consensus[0], stem.descriptor.router_status_entry.RouterStatusEntryMicroV3))
- @require_online - @only_run_once + @test.require.only_run_once + @test.require.online def test_get_key_certificates(self): """ Exercises the downloader's get_key_certificates() method. @@ -223,7 +219,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual(2, len(list(multiple_query)))
- @require_online + @test.require.online def test_that_cache_is_up_to_date(self): """ Check if the cached fallback directories bundled with Stem are up to date @@ -236,7 +232,7 @@ class TestDescriptorDownloader(unittest.TestCase): if cached_fallback_directories != latest_fallback_directories: self.fail("Stem's cached fallback directories are out of date. Please run 'cache_fallback_directories.py'...\n\n%s" % stem.descriptor.remote._fallback_directory_differences(cached_fallback_directories, latest_fallback_directories))
- @require_online + @test.require.online def test_fallback_directory_reachability(self): """ Fetch information from each fallback directory to confirm that it's diff --git a/test/integ/descriptor/server_descriptor.py b/test/integ/descriptor/server_descriptor.py index bd61e70..2a3d897 100644 --- a/test/integ/descriptor/server_descriptor.py +++ b/test/integ/descriptor/server_descriptor.py @@ -6,17 +6,14 @@ import os import unittest
import stem.descriptor - +import test.require import test.runner
-from test.util import ( - register_new_capability, - only_run_once, -) +from test.util import register_new_capability
class TestServerDescriptor(unittest.TestCase): - @only_run_once + @test.require.only_run_once def test_cached_descriptor(self): """ Parses the cached descriptor file in our data directory, checking that it diff --git a/test/integ/installation.py b/test/integ/installation.py index 4d68988..3f37df3 100644 --- a/test/integ/installation.py +++ b/test/integ/installation.py @@ -12,11 +12,9 @@ import unittest
import stem import stem.util.system - +import test.require import test.util
-from test.util import 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' @@ -110,7 +108,7 @@ def _assert_has_all_files(path):
class TestInstallation(unittest.TestCase): - @only_run_once + @test.require.only_run_once def test_install(self): """ Installs with 'python setup.py install' and checks we can use what we @@ -126,7 +124,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)
- @only_run_once + @test.require.only_run_once def test_sdist(self): """ Creates a source distribution tarball with 'python setup.py sdist' and diff --git a/test/integ/interpreter.py b/test/integ/interpreter.py index 5e7c94b..42dd01a 100644 --- a/test/integ/interpreter.py +++ b/test/integ/interpreter.py @@ -7,12 +7,10 @@ import tempfile import unittest
import stem.util.system - +import test.require import test.runner import test.util
-from test.util import require_controller - PROMPT_CMD = os.path.join(test.util.STEM_BASE, 'tor-prompt')
@@ -24,7 +22,7 @@ def _run_prompt(*args):
class TestInterpreter(unittest.TestCase): - @require_controller + @test.require.controller def test_running_command(self): # We'd need to provide the password to stdin. Fine test to add later but # not gonna hassle for now. @@ -36,7 +34,7 @@ class TestInterpreter(unittest.TestCase): expected = ['250-config-file=%s' % test.runner.get_runner().get_torrc_path(), '250 OK'] self.assertEqual(expected, _run_prompt('--run', 'GETINFO config-file'))
- @require_controller + @test.require.controller def test_running_file(self): if test.runner.Torrc.PASSWORD in test.runner.get_runner().get_options(): self.skipTest('password auth unsupported') diff --git a/test/integ/process.py b/test/integ/process.py index 79797ac..1ca0f70 100644 --- a/test/integ/process.py +++ b/test/integ/process.py @@ -20,16 +20,9 @@ import stem.util.str_tools import stem.util.system import stem.util.tor_tools import stem.version +import test.require import test.runner
-from test.util import ( - require_command, - require_controller, - require_version, -) - -from test.util import only_run_once - try: # added in python 3.3 from unittest.mock import patch, Mock @@ -53,7 +46,7 @@ class TestProcess(unittest.TestCase): def tearDown(self): shutil.rmtree(self.data_directory)
- @require_controller + @test.require.controller def test_version_argument(self): """ Check that 'tor --version' matches 'GETINFO version'. @@ -199,7 +192,7 @@ class TestProcess(unittest.TestCase): self.assertTrue('UseBridges' in output) self.assertTrue('SocksPort' in output)
- @require_command('sleep') + @test.require.command('sleep') @patch('re.compile', Mock(side_effect = KeyboardInterrupt('nope'))) def test_no_orphaned_process(self): """ @@ -255,7 +248,7 @@ class TestProcess(unittest.TestCase):
self.assertEqual(expected, result)
- @require_version(stem.version.Requirement.TORRC_VIA_STDIN) + @test.require.version(stem.version.Requirement.TORRC_VIA_STDIN) def test_torrc_arguments_via_stdin(self): """ Pass configuration options via stdin. @@ -278,7 +271,7 @@ class TestProcess(unittest.TestCase): self.assertTrue('[notice] Configuration file "/path/that/really/shouldnt/exist" not present, using reasonable defaults.' in output) self.assertTrue('Configuration was valid' in output)
- @only_run_once + @test.require.only_run_once def test_can_run_multithreaded(self): """ Our launch_tor() function uses signal to support its timeout argument. @@ -321,7 +314,7 @@ class TestProcess(unittest.TestCase): self.assertEqual(None, launch_async_with_timeout(None)) self.assertEqual(None, launch_async_with_timeout(stem.process.DEFAULT_INIT_TIMEOUT))
- @only_run_once + @test.require.only_run_once @patch('stem.version.get_system_tor_version', Mock(return_value = stem.version.Version('0.0.0.1'))) def test_launch_tor_with_config_via_file(self): """ @@ -359,8 +352,8 @@ class TestProcess(unittest.TestCase): tor_process.kill() tor_process.wait()
- @only_run_once - @require_version(stem.version.Requirement.TORRC_VIA_STDIN) + @test.require.only_run_once + @test.require.version(stem.version.Requirement.TORRC_VIA_STDIN) def test_launch_tor_with_config_via_stdin(self): """ Exercises launch_tor_with_config when we provide our torrc via stdin. @@ -394,7 +387,7 @@ class TestProcess(unittest.TestCase): tor_process.kill() tor_process.wait()
- @only_run_once + @test.require.only_run_once def test_with_invalid_config(self): """ Spawn a tor process with a configuration that should make it dead on arrival. @@ -417,7 +410,7 @@ class TestProcess(unittest.TestCase): }, )
- @only_run_once + @test.require.only_run_once def test_launch_tor_with_timeout(self): """ Runs launch_tor where it times out before completing. @@ -432,9 +425,9 @@ class TestProcess(unittest.TestCase): if not (runtime > 0.05 and runtime < 1): self.fail('Test should have taken 0.05-1 seconds, took %0.1f instead' % runtime)
- @require_command('sleep') - @require_version(stem.version.Requirement.TAKEOWNERSHIP) - @only_run_once + @test.require.only_run_once + @test.require.command('sleep') + @test.require.version(stem.version.Requirement.TAKEOWNERSHIP) @patch('os.getpid') def test_take_ownership_via_pid(self, getpid_mock): """ @@ -476,8 +469,8 @@ class TestProcess(unittest.TestCase):
self.fail("tor didn't quit after the process that owned it terminated")
- @require_version(stem.version.Requirement.TAKEOWNERSHIP) - @only_run_once + @test.require.only_run_once + @test.require.version(stem.version.Requirement.TAKEOWNERSHIP) def test_take_ownership_via_controller(self): """ Checks that the tor process quits after the controller that owns it diff --git a/test/integ/response/protocolinfo.py b/test/integ/response/protocolinfo.py index 8563cf0..1a00671 100644 --- a/test/integ/response/protocolinfo.py +++ b/test/integ/response/protocolinfo.py @@ -9,10 +9,11 @@ import stem.connection import stem.socket import stem.util.system import stem.version +import test.require import test.runner
from test.integ.util.system import filter_system_call -from test.util import require_controller, tor_version +from test.util import tor_version
try: # added in python 3.3 @@ -22,7 +23,7 @@ except ImportError:
class TestProtocolInfo(unittest.TestCase): - @require_controller + @test.require.controller def test_parsing(self): """ Makes a PROTOCOLINFO query and processes the response for our control @@ -44,7 +45,7 @@ class TestProtocolInfo(unittest.TestCase):
self.assert_matches_test_config(protocolinfo_response)
- @require_controller + @test.require.controller @patch('stem.util.proc.is_available', Mock(return_value = False)) @patch('stem.util.system.is_available', Mock(return_value = True)) def test_get_protocolinfo_path_expansion(self): @@ -87,7 +88,7 @@ class TestProtocolInfo(unittest.TestCase): self.assertTrue(control_socket.is_alive()) control_socket.close()
- @require_controller + @test.require.controller def test_multiple_protocolinfo_calls(self): """ Tests making repeated PROTOCOLINFO queries. This use case is interesting @@ -100,7 +101,7 @@ class TestProtocolInfo(unittest.TestCase): protocolinfo_response = stem.connection.get_protocolinfo(control_socket) self.assert_matches_test_config(protocolinfo_response)
- @require_controller + @test.require.controller def test_pre_disconnected_query(self): """ Tests making a PROTOCOLINFO query when previous use of the socket had diff --git a/test/integ/socket/control_message.py b/test/integ/socket/control_message.py index 646f732..6d16f48 100644 --- a/test/integ/socket/control_message.py +++ b/test/integ/socket/control_message.py @@ -7,17 +7,14 @@ import unittest
import stem.socket import stem.version +import test.require import test.runner
-from test.util import ( - require_controller, - require_version, - random_fingerprint, -) +from test.util import random_fingerprint
class TestControlMessage(unittest.TestCase): - @require_controller + @test.require.controller def test_unestablished_socket(self): """ Checks message parsing when we have a valid but unauthenticated socket. @@ -58,7 +55,7 @@ class TestControlMessage(unittest.TestCase): self.assertRaises(stem.SocketClosed, control_socket.send, 'GETINFO version') self.assertRaises(stem.SocketClosed, control_socket.recv)
- @require_controller + @test.require.controller def test_invalid_command(self): """ Parses the response for a command which doesn't exist. @@ -72,7 +69,7 @@ class TestControlMessage(unittest.TestCase): self.assertEqual('510 Unrecognized command "blarg"\r\n', unrecognized_command_response.raw_content()) self.assertEqual([('510', ' ', 'Unrecognized command "blarg"')], unrecognized_command_response.content())
- @require_controller + @test.require.controller def test_invalid_getinfo(self): """ Parses the response for a GETINFO query which doesn't exist. @@ -86,7 +83,7 @@ class TestControlMessage(unittest.TestCase): self.assertEqual('552 Unrecognized key "blarg"\r\n', unrecognized_key_response.raw_content()) self.assertEqual([('552', ' ', 'Unrecognized key "blarg"')], unrecognized_key_response.content())
- @require_controller + @test.require.controller def test_getinfo_config_file(self): """ Parses the 'GETINFO config-file' response. @@ -103,8 +100,8 @@ class TestControlMessage(unittest.TestCase): self.assertEqual('250-config-file=%s\r\n250 OK\r\n' % torrc_dst, config_file_response.raw_content()) self.assertEqual([('250', '-', 'config-file=%s' % torrc_dst), ('250', ' ', 'OK')], config_file_response.content())
- @require_controller - @require_version(stem.version.Requirement.GETINFO_CONFIG_TEXT) + @test.require.controller + @test.require.version(stem.version.Requirement.GETINFO_CONFIG_TEXT) def test_getinfo_config_text(self): """ Parses the 'GETINFO config-text' response. @@ -145,7 +142,7 @@ class TestControlMessage(unittest.TestCase): self.assertTrue('%s\r\n' % torrc_entry in config_text_response.raw_content()) self.assertTrue('%s' % torrc_entry in config_text_response.content()[0][2])
- @require_controller + @test.require.controller def test_setconf_event(self): """ Issues 'SETEVENTS CONF_CHANGED' and parses an events. diff --git a/test/integ/socket/control_socket.py b/test/integ/socket/control_socket.py index a4da321..8e2658a 100644 --- a/test/integ/socket/control_socket.py +++ b/test/integ/socket/control_socket.py @@ -14,13 +14,14 @@ import unittest import stem.connection import stem.control import stem.socket +import test.require import test.runner
-from test.util import require_controller, tor_version +from test.util import tor_version
class TestControlSocket(unittest.TestCase): - @require_controller + @test.require.controller def test_connection_time(self): """ Checks that our connection_time method tracks when our state's changed. @@ -54,7 +55,7 @@ class TestControlSocket(unittest.TestCase): reconnection_time = control_socket.connection_time() self.assertTrue(disconnection_time < reconnection_time <= time.time())
- @require_controller + @test.require.controller def test_send_buffered(self): """ Sends multiple requests before receiving back any of the replies. @@ -71,7 +72,7 @@ class TestControlSocket(unittest.TestCase): self.assertTrue(str(response).startswith('version=%s' % tor_version())) self.assertTrue(str(response).endswith('\nOK'))
- @require_controller + @test.require.controller def test_send_closed(self): """ Sends a message after we've closed the connection. @@ -84,7 +85,7 @@ class TestControlSocket(unittest.TestCase):
self.assertRaises(stem.SocketClosed, control_socket.send, 'blarg')
- @require_controller + @test.require.controller def test_send_disconnected(self): """ Sends a message to a socket that has been disconnected by the other end. @@ -110,7 +111,7 @@ class TestControlSocket(unittest.TestCase): self.assertRaises(stem.SocketClosed, control_socket.send, 'blarg') self.assertFalse(control_socket.is_alive())
- @require_controller + @test.require.controller def test_recv_closed(self): """ Receives a message after we've closed the connection. @@ -123,7 +124,7 @@ class TestControlSocket(unittest.TestCase):
self.assertRaises(stem.SocketClosed, control_socket.recv)
- @require_controller + @test.require.controller def test_recv_disconnected(self): """ Receives a message from a socket that has been disconnected by the other @@ -142,7 +143,7 @@ class TestControlSocket(unittest.TestCase): self.assertRaises(stem.SocketClosed, control_socket.recv) self.assertFalse(control_socket.is_alive())
- @require_controller + @test.require.controller def test_connect_repeatedly(self): """ Checks that we can reconnect, use, and disconnect a socket repeatedly. diff --git a/test/integ/util/connection.py b/test/integ/util/connection.py index f641a37..1fc08c4 100644 --- a/test/integ/util/connection.py +++ b/test/integ/util/connection.py @@ -5,14 +5,14 @@ that we're running.
import unittest
+import test.require import test.runner
from stem.util.connection import Resolver, get_connections, system_resolvers -from test.util import require_ptrace
class TestConnection(unittest.TestCase): - @require_ptrace + @test.require.ptrace def check_resolver(self, resolver): runner = test.runner.get_runner()
diff --git a/test/integ/util/proc.py b/test/integ/util/proc.py index ef3a7c0..da4d6ef 100644 --- a/test/integ/util/proc.py +++ b/test/integ/util/proc.py @@ -6,19 +6,15 @@ we're running. import os import unittest
+import test.require import test.runner
from stem.util import proc
-from test.util import ( - require_proc, - require_ptrace, -) -
class TestProc(unittest.TestCase): - @require_proc - @require_ptrace + @test.require.proc + @test.require.ptrace def test_cwd(self): """ Checks that stem.util.proc.cwd matches our tor instance's cwd. @@ -28,7 +24,7 @@ class TestProc(unittest.TestCase): runner_pid, tor_cwd = runner.get_pid(), runner.get_tor_cwd() self.assertEqual(tor_cwd, proc.cwd(runner_pid))
- @require_proc + @test.require.proc def test_uid(self): """ Checks that stem.util.proc.uid matches our tor instance's uid. @@ -37,7 +33,7 @@ class TestProc(unittest.TestCase): tor_pid = test.runner.get_runner().get_pid() self.assertEqual(os.geteuid(), proc.uid(tor_pid))
- @require_proc + @test.require.proc def test_memory_usage(self): """ Checks that stem.util.proc.memory_usage looks somewhat reasonable. @@ -50,7 +46,7 @@ class TestProc(unittest.TestCase): self.assertTrue(res_size > 1024) self.assertTrue(vir_size > 1024)
- @require_proc + @test.require.proc def test_stats(self): """ Checks that stem.util.proc.stats looks somewhat reasonable. @@ -65,8 +61,8 @@ class TestProc(unittest.TestCase): self.assertTrue(float(stime) >= 0) self.assertTrue(float(start_time) > proc.system_start_time())
- @require_proc - @require_ptrace + @test.require.proc + @test.require.ptrace def test_connections(self): """ Checks for our control port in the stem.util.proc.connections output if diff --git a/test/integ/util/system.py b/test/integ/util/system.py index 88a5529..912251b 100644 --- a/test/integ/util/system.py +++ b/test/integ/util/system.py @@ -10,15 +10,9 @@ import unittest
import stem.util.proc import stem.util.system +import test.require import test.runner
-from test.util import ( - require, - require_command, - require_proc, - require_ptrace, -) - try: # added in python 3.3 from unittest.mock import Mock, patch @@ -68,10 +62,10 @@ def _has_port(): return test.runner.Torrc.PORT in test.runner.get_runner().get_options()
-require_single_tor_instance = require(_is_single_tor_running, 'multiple tor instances') -require_control_port = require(_has_port, 'test instance has no port') -require_linux = require(_is_linux, 'linux only') -require_bsd = require(stem.util.system.is_bsd, 'bsd only') +require_single_tor_instance = test.require.needs(_is_single_tor_running, 'multiple tor instances') +require_control_port = test.require.needs(_has_port, 'test instance has no port') +require_linux = test.require.needs(_is_linux, 'linux only') +require_bsd = test.require.needs(stem.util.system.is_bsd, 'bsd only')
class TestSystem(unittest.TestCase): @@ -91,7 +85,7 @@ class TestSystem(unittest.TestCase):
self.assertFalse(stem.util.system.is_available('blarg_and_stuff'))
- @require_command('ps') + @test.require.command('ps') def test_is_running(self): """ Checks the stem.util.system.is_running function. @@ -117,8 +111,8 @@ class TestSystem(unittest.TestCase): self.assertEqual(tor_pid, stem.util.system.pid_by_name(tor_cmd)) self.assertEqual(None, stem.util.system.pid_by_name('blarg_and_stuff'))
- @require_command('pgrep') @require_single_tor_instance + @test.require.command('pgrep') def test_pid_by_name_pgrep(self): """ Tests the pid_by_name function with a pgrep response. @@ -134,8 +128,8 @@ class TestSystem(unittest.TestCase): tor_cmd = test.runner.get_runner().get_tor_command(True) self.assertEqual(tor_pid, stem.util.system.pid_by_name(tor_cmd))
- @require_command('pidof') @require_single_tor_instance + @test.require.command('pidof') def test_pid_by_name_pidof(self): """ Tests the pid_by_name function with a pidof response. @@ -152,8 +146,8 @@ class TestSystem(unittest.TestCase): self.assertEqual(tor_pid, stem.util.system.pid_by_name(tor_cmd))
@require_linux - @require_command('ps') @require_single_tor_instance + @test.require.command('ps') def test_pid_by_name_ps_linux(self): """ Tests the pid_by_name function with the linux variant of ps. @@ -170,8 +164,8 @@ class TestSystem(unittest.TestCase): self.assertEqual(tor_pid, stem.util.system.pid_by_name(tor_cmd))
@require_bsd - @require_command('ps') @require_single_tor_instance + @test.require.command('ps') def test_pid_by_name_ps_bsd(self): """ Tests the pid_by_name function with the bsd variant of ps. @@ -187,9 +181,9 @@ class TestSystem(unittest.TestCase): tor_cmd = test.runner.get_runner().get_tor_command(True) self.assertEqual(tor_pid, stem.util.system.pid_by_name(tor_cmd))
- @require_ptrace - @require_command('lsof') @require_single_tor_instance + @test.require.ptrace + @test.require.command('lsof') def test_pid_by_name_lsof(self): """ Tests the pid_by_name function with a lsof response. @@ -208,8 +202,8 @@ class TestSystem(unittest.TestCase): if len(all_tor_pids) == 1: self.assertEqual(our_tor_pid, all_tor_pids[0])
- @require_command('tasklist') @require_single_tor_instance + @test.require.command('tasklist') def test_pid_by_name_tasklist(self): """ Tests the pid_by_name function with a tasklist response. @@ -218,8 +212,8 @@ class TestSystem(unittest.TestCase): runner = test.runner.get_runner() self.assertEqual(runner.get_pid(), stem.util.system.pid_by_name(runner.get_tor_command(True)))
- @require_ptrace @require_control_port + @test.require.ptrace def test_pid_by_port(self): """ Checks general usage of the stem.util.system.pid_by_port function. @@ -243,9 +237,9 @@ class TestSystem(unittest.TestCase): self.assertEqual(None, stem.util.system.pid_by_port(99999))
@require_linux - @require_ptrace @require_control_port - @require_command('netstat') + @test.require.ptrace + @test.require.command('netstat') def test_pid_by_port_netstat(self): """ Tests the pid_by_port function with a netstat response. @@ -266,9 +260,9 @@ class TestSystem(unittest.TestCase): self.assertEqual(tor_pid, stem.util.system.pid_by_port(test.runner.CONTROL_PORT))
@require_bsd - @require_ptrace @require_control_port - @require_command('sockstat') + @test.require.ptrace + @test.require.command('sockstat') def test_pid_by_port_sockstat(self): """ Tests the pid_by_port function with a sockstat response. @@ -283,9 +277,9 @@ class TestSystem(unittest.TestCase): tor_pid = test.runner.get_runner().get_pid() self.assertEqual(tor_pid, stem.util.system.pid_by_port(test.runner.CONTROL_PORT))
- @require_ptrace @require_control_port - @require_command('lsof') + @test.require.ptrace + @test.require.command('lsof') def test_pid_by_port_lsof(self): """ Tests the pid_by_port function with a lsof response. @@ -328,7 +322,7 @@ class TestSystem(unittest.TestCase): pids = stem.util.system.pids_by_user(getpass.getuser()) self.assertTrue(os.getpid() in pids)
- @require_ptrace + @test.require.ptrace def test_cwd(self): """ Checks general usage of the stem.util.system.cwd function. @@ -343,8 +337,8 @@ class TestSystem(unittest.TestCase): self.assertEqual(tor_cwd, stem.util.system.cwd(runner_pid)) self.assertEqual(None, stem.util.system.cwd(99999))
- @require_ptrace - @require_command('pwdx') + @test.require.ptrace + @test.require.command('pwdx') def test_cwd_pwdx(self): """ Tests the pid_by_cwd function with a pwdx response. @@ -363,8 +357,8 @@ class TestSystem(unittest.TestCase): runner_pid, tor_cwd = runner.get_pid(), runner.get_tor_cwd() self.assertEqual(tor_cwd, stem.util.system.cwd(runner_pid))
- @require_ptrace - @require_command('lsof') + @test.require.ptrace + @test.require.command('lsof') def test_cwd_lsof(self): """ Tests the pid_by_cwd function with a lsof response. @@ -392,7 +386,7 @@ class TestSystem(unittest.TestCase): self.assertEqual(None, stem.util.system.user(-5)) self.assertEqual(None, stem.util.system.start_time(98765))
- @require_proc + @test.require.proc def test_user_proc(self): """ Tests the user function with a proc response. @@ -408,7 +402,7 @@ class TestSystem(unittest.TestCase): pid = test.runner.get_runner().get_pid() self.assertTrue(getpass.getuser(), stem.util.system.user(pid))
- @require_command('ps') + @test.require.command('ps') @patch('stem.util.proc.is_available', Mock(return_value = False)) def test_user_ps(self): """ @@ -427,7 +421,7 @@ class TestSystem(unittest.TestCase): self.assertEqual(None, stem.util.system.start_time(-5)) self.assertEqual(None, stem.util.system.start_time(98765))
- @require_proc + @test.require.proc def test_start_time_proc(self): """ Tests the start_time function with a proc response. @@ -441,7 +435,7 @@ class TestSystem(unittest.TestCase): pid = test.runner.get_runner().get_pid() self.assertTrue(stem.util.system.start_time(pid) >= 0)
- @require_command('ps') + @test.require.command('ps') @patch('stem.util.proc.is_available', Mock(return_value = False)) def test_start_time_ps(self): """ diff --git a/test/integ/version.py b/test/integ/version.py index 3cef9b2..b28ee86 100644 --- a/test/integ/version.py +++ b/test/integ/version.py @@ -7,16 +7,12 @@ import unittest
import stem.prereq import stem.version +import test.require import test.runner
-from test.util import ( - require_command, - require_controller, -) -
class TestVersion(unittest.TestCase): - @require_command('tor') + @test.require.command('tor') def test_get_system_tor_version(self): """ Basic verification checks for the get_system_tor_version() function. @@ -34,7 +30,7 @@ class TestVersion(unittest.TestCase): # try running against a command that doesn't exist self.assertRaises(IOError, stem.version.get_system_tor_version, 'blarg')
- @require_controller + @test.require.controller def test_getinfo_version_parsing(self): """ Issues a 'GETINFO version' query to our test instance and makes sure that diff --git a/test/require.py b/test/require.py new file mode 100644 index 0000000..a0735d8 --- /dev/null +++ b/test/require.py @@ -0,0 +1,106 @@ +# Copyright 2012-2017, Damian Johnson and The Tor Project +# See LICENSE for licensing information + +""" +Testing requirements. This provides annotations to skip tests that shouldn't be +run. + +:: + + Test Requirements + |- only_run_once - skip test if it has been ran before + |- needs - skips the test unless a requirement is met + | + |- cryptography - skips test unless the cryptography module is present + |- pynacl - skips test unless the pynacl module is present + |- command - requires a command to be on the path + |- proc - requires the platform to have recognized /proc contents + | + |- controller - skips test unless tor provides a controller endpoint + |- version - skips test unless we meet a tor version requirement + |- ptrace - requires 'DisableDebuggerAttachment' to be set + +- online - skips unless targets allow for online tests +""" + +import stem.util.system +import stem.version +import test.runner +import test.util + +RAN_TESTS = [] + + +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: + self.skipTest('(already ran)') + + return wrapped + + +def needs(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: + self.skipTest('(%s)' % message) + + return wrapped + + return decorator + + +def _can_access_controller(): + return test.runner.get_runner().is_accessible() + + +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 + 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 + + +def command(cmd): + """ + Skips the test unless a command is available on the path. + """ + + return needs(lambda: stem.util.system.is_available(cmd), '%s unavailable' % cmd) + + +def 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 needs(lambda: test.util.tor_version() >= req_version, 'requires %s' % req_version) + + +cryptography = needs(stem.prereq.is_crypto_available, 'requires cryptography') +pynacl = needs(stem.prereq._is_pynacl_available, 'requires pynacl module') +proc = needs(stem.util.proc.is_available, 'proc unavailable') +controller = needs(_can_access_controller, 'no connection') +ptrace = needs(_can_ptrace, 'DisableDebuggerAttachment is set') +online = needs(_is_online, 'requires online target') diff --git a/test/unit/descriptor/certificate.py b/test/unit/descriptor/certificate.py index 0cef45a..19d7c64 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.require
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,7 +147,7 @@ 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 + @test.require.pynacl def test_validation_with_descriptor_key(self): """ Validate a descriptor signature using the ed25519 master key within the @@ -159,7 +159,7 @@ class TestEd25519Certificate(unittest.TestCase):
desc.certificate.validate(desc)
- @require_pynacl + @test.require.pynacl def test_validation_with_embedded_key(self): """ Validate a descriptor signature using the signing key within the ed25519 @@ -172,7 +172,7 @@ class TestEd25519Certificate(unittest.TestCase): desc.ed25519_master_key = None desc.certificate.validate(desc)
- @require_pynacl + @test.require.pynacl def test_validation_with_invalid_descriptor(self): """ Validate a descriptor without a valid signature. diff --git a/test/unit/descriptor/hidden_service_descriptor.py b/test/unit/descriptor/hidden_service_descriptor.py index 48f1d29..2f8427f 100644 --- a/test/unit/descriptor/hidden_service_descriptor.py +++ b/test/unit/descriptor/hidden_service_descriptor.py @@ -8,8 +8,7 @@ import unittest
import stem.descriptor import stem.prereq - -from test.util import require_cryptography +import test.require
from stem.descriptor.hidden_service_descriptor import ( REQUIRED_FIELDS, @@ -274,7 +273,7 @@ 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 + @test.require.cryptography def test_with_basic_auth(self): """ Parse a descriptor with introduction-points encrypted with basic auth. @@ -321,7 +320,7 @@ class TestHiddenServiceDescriptor(unittest.TestCase): self.assertTrue('MIGJAoGBAM7B/cymp' in point.service_key) self.assertEqual([], point.intro_authentication)
- @require_cryptography + @test.require.cryptography def test_with_stealth_auth(self): """ Parse a descriptor with introduction-points encrypted with stealth auth. diff --git a/test/unit/manual.py b/test/unit/manual.py index 6bfcbe7..28a8a8b 100644 --- a/test/unit/manual.py +++ b/test/unit/manual.py @@ -11,8 +11,7 @@ import unittest import stem.prereq import stem.manual import stem.util.system - -from test.util import require_command +import test.require
try: # account for urllib's change between python 2.x and 3.x @@ -138,7 +137,7 @@ class TestManual(unittest.TestCase): self.assertEqual('', blank.summary) self.assertEqual('', blank.description)
- @require_command('man') + @test.require.command('man') def test_parsing_with_example(self): """ Read a trimmed copy of tor's man page. This gives a good exercise of our @@ -160,7 +159,7 @@ class TestManual(unittest.TestCase): self.assertEqual(EXPECTED_FILES, manual.files) self.assertEqual(EXPECTED_CONFIG_OPTIONS, manual.config_options)
- @require_command('man') + @test.require.command('man') def test_parsing_with_unknown_options(self): """ Check that we can read a local mock man page that contains unrecognized @@ -189,7 +188,7 @@ class TestManual(unittest.TestCase): self.assertEqual('', option.summary) self.assertEqual('Description of this new option.', option.description)
- @require_command('man') + @test.require.command('man') def test_saving_manual(self): """ Check that we can save and reload manuals. diff --git a/test/util.py b/test/util.py index e8af8e1..47d90fd 100644 --- a/test/util.py +++ b/test/util.py @@ -12,24 +12,6 @@ Helper functions for our test framework. get_prereq - provides the tor version required to run the given target get_torrc_entries - provides the torrc entries for a given target
-This module also provides generally useful test helpers... - -:: - - Test Requirements - |- 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_command - requires a command to be on the path - |- require_proc - requires the platform to have recognized /proc contents - | - |- require_controller - skips test unless tor provides a controller endpoint - |- require_version - skips test unless we meet a tor version requirement - |- require_ptrace - requires 'DisableDebuggerAttachment' to be set - +- require_online - skips unless targets allow for online tests - get_message - provides a ControlMessage instance get_protocolinfo_response - provides a ProtocolInfoResponse instance get_all_combinations - provides all combinations of attributes @@ -43,14 +25,10 @@ import re import os
import stem -import stem.prereq import stem.util.conf -import stem.util.system -import stem.util.test_tools +import stem.util.enum import stem.version
-import test.output - CONFIG = stem.util.conf.config_dict('test', { 'target.prereq': {}, 'target.torrc': {}, @@ -83,7 +61,6 @@ Target = stem.util.enum.UppercaseEnum( 'RUN_ALL', )
-RAN_TESTS = [] TOR_VERSION = None
# We make some paths relative to stem's base directory (the one above us) @@ -211,82 +188,6 @@ def get_new_capabilities(): return NEW_CAPABILITIES
-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: - self.skipTest('(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: - self.skipTest('(%s)' % message) - - return wrapped - - return decorator - - -def _can_access_controller(): - return test.runner.get_runner().is_accessible() - - -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 = 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 Target.ONLINE in test.runner.get_runner().attribute_targets - - -require_cryptography = require(stem.prereq.is_crypto_available, 'requires cryptography') -require_pynacl = require(stem.prereq._is_pynacl_available, 'requires pynacl module') -require_proc = require(stem.util.proc.is_available, 'proc unavailable') -require_controller = require(_can_access_controller, 'no connection') -require_ptrace = require(_can_ptrace, 'DisableDebuggerAttachment is set') -require_online = require(_is_online, 'requires online target') - - -def require_command(cmd): - """ - Skips the test unless a command is available on the path. - """ - - return require(lambda: stem.util.system.is_available(cmd), '%s unavailable' % cmd) - - -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 register_new_capability(capability_type, msg, suppression_token = None): """ Register new capability found during the tests.