commit 0071fadd8b69eda81cdd9826719037fafdebbb74 Author: Damian Johnson atagar@torproject.org Date: Fri Jan 13 08:28:32 2012 -0800
Making explicit checks for tor accessibility
Several 'test/runner.py' functions query against our tor instance. However, in some integ tests we don't have any method for doing that. Rather than returning a default value I'm raising in those cases, and adding an is_accessible method to make our tests more readable. --- test/integ/socket/control_message.py | 30 +++++++++-------- test/runner.py | 57 +++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 29 deletions(-)
diff --git a/test/integ/socket/control_message.py b/test/integ/socket/control_message.py index d0c44dc..33a54bf 100644 --- a/test/integ/socket/control_message.py +++ b/test/integ/socket/control_message.py @@ -20,13 +20,14 @@ class TestControlMessage(unittest.TestCase): Checks message parsing when we have a valid but unauthenticated socket. """
- control_socket = test.runner.get_runner().get_tor_socket(False) - if not control_socket: self.skipTest("(no control socket)") + runner = test.runner.get_runner() + if not runner.is_accessible(): self.skipTest("(no control socket)")
# If an unauthenticated connection gets a message besides AUTHENTICATE or # PROTOCOLINFO then tor will give an 'Authentication required.' message and # hang up.
+ control_socket = runner.get_tor_socket(False) control_socket.send("GETINFO version")
auth_required_response = control_socket.recv() @@ -66,8 +67,9 @@ class TestControlMessage(unittest.TestCase): Parses the response for a command which doesn't exist. """
- control_socket = test.runner.get_runner().get_tor_socket() - if not control_socket: self.skipTest("(no control socket)") + runner = test.runner.get_runner() + if not runner.is_accessible(): self.skipTest("(no control socket)") + control_socket = runner.get_tor_socket()
control_socket.send("blarg") unrecognized_command_response = control_socket.recv() @@ -83,8 +85,9 @@ class TestControlMessage(unittest.TestCase): Parses the response for a GETINFO query which doesn't exist. """
- control_socket = test.runner.get_runner().get_tor_socket() - if not control_socket: self.skipTest("(no control socket)") + runner = test.runner.get_runner() + if not runner.is_accessible(): self.skipTest("(no control socket)") + control_socket = runner.get_tor_socket()
control_socket.send("GETINFO blarg") unrecognized_key_response = control_socket.recv() @@ -102,9 +105,8 @@ class TestControlMessage(unittest.TestCase):
runner = test.runner.get_runner() torrc_dst = runner.get_torrc_path() - + if not runner.is_accessible(): self.skipTest("(no control socket)") control_socket = runner.get_tor_socket() - if not control_socket: self.skipTest("(no control socket)")
control_socket.send("GETINFO config-file") config_file_response = control_socket.recv() @@ -122,9 +124,10 @@ class TestControlMessage(unittest.TestCase):
runner = test.runner.get_runner() req_version = stem.version.Requirement.GETINFO_CONFIG_TEXT - our_version = runner.get_tor_version()
- if our_version and our_version < req_version: + if not runner.is_accessible(): + self.skipTest("(no control socket)") + elif runner.get_tor_version() < req_version: self.skipTest("(requires %s)" % req_version)
# We can't be certain of the order, and there may be extra config-text @@ -142,8 +145,6 @@ class TestControlMessage(unittest.TestCase): torrc_contents.append(line)
control_socket = runner.get_tor_socket() - if not control_socket: self.skipTest("(no control socket)") - control_socket.send("GETINFO config-text") config_text_response = control_socket.recv()
@@ -169,8 +170,9 @@ class TestControlMessage(unittest.TestCase): Issues 'SETEVENTS BW' and parses a few events. """
- control_socket = test.runner.get_runner().get_tor_socket() - if not control_socket: self.skipTest("(no control socket)") + runner = test.runner.get_runner() + if not runner.is_accessible(): self.skipTest("(no control socket)") + control_socket = runner.get_tor_socket()
control_socket.send("SETEVENTS BW") setevents_response = control_socket.recv() diff --git a/test/runner.py b/test/runner.py index d5f4a91..5841154 100644 --- a/test/runner.py +++ b/test/runner.py @@ -10,11 +10,13 @@ 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 |- is_running - checks if our tor test instance is running + |- is_accessible - checks if our tor instance can be connected to |- is_debugging_prevented - checks if DisableDebuggerAttachment is set |- get_test_dir - testing directory path |- get_torrc_path - path to our tor instance's torrc |- get_torrc_contents - contents of our tor instance's torrc |- get_connection_type - method by which controllers can connect to tor + |- get_connection_options - connection related options we're running with |- get_pid - process id of our tor process |- get_tor_socket - provides a socket to the tor instance +- get_tor_version - provides the version of tor we're running against @@ -129,6 +131,10 @@ class RunnerStopped(Exception): "Raised when we try to use a Runner that doesn't have an active tor instance" pass
+class TorInaccessable(Exception): + "Raised when information is needed from tor but the instance we have is inaccessable" + pass + class Runner: def __init__(self): self._config = dict(DEFAULT_CONFIG) @@ -256,6 +262,17 @@ class Runner:
return is_running
+ def is_accessible(self): + """ + Checks if our tor instance has a method of being connected to or not. + + Returns: + True if tor has a control socket or port, False otherwise + """ + + conn_opts = self.get_connection_options() + return OPT_PORT in conn_opts or OPT_SOCKET in conn_opts + def is_debugging_prevented(self): """ Checks if tor's 'DisableDebuggerAttachment' option is set. This feature has @@ -263,14 +280,14 @@ class Runner: https://trac.torproject.org/projects/tor/ticket/3313
Returns: - True if debugger attachment is disallowd, False otherwise, and None if - tor can't be checked + True if debugger attachment is disallowd, False otherwise + + Raises: + TorInaccessable if this can't be determined """
# TODO: replace higher level GETCONF query when we have a controller class control_socket = self.get_tor_socket() - if control_socket == None: return None - control_socket.send("GETCONF DisableDebuggerAttachment") getconf_response = control_socket.recv() control_socket.close() @@ -349,6 +366,16 @@ class Runner:
return self._connection_type
+ def get_connection_options(self): + """ + Provides the connection related options we're running with. + + Returns: + list of connection contstants (test.runner.OPT_*) we're running with + """ + + return CONNECTION_OPTS[self.get_connection_type()] + def get_pid(self): """ Provides the process id of the tor process. @@ -371,20 +398,19 @@ class Runner: authenticate (bool) - if True then the socket is authenticated
Returns: - stem.socket.ControlSocket connected with our testing instance, returning - None if we either don't have a test instance or it can't be connected to - """ + stem.socket.ControlSocket connected with our testing instance
- connection_type, cookie_path = self.get_connection_type(), self.get_auth_cookie_path() - if connection_type == None: return None + Raises: + TorInaccessable if tor can't be connected to + """
- conn_opts = CONNECTION_OPTS[connection_type] + conn_opts = self.get_connection_options()
if OPT_PORT in conn_opts: control_socket = stem.socket.ControlPort(control_port = CONTROL_PORT) elif OPT_SOCKET in conn_opts: control_socket = stem.socket.ControlSocketFile(CONTROL_SOCKET_PATH) - else: return None + else: raise TorInaccessable("Unable to connect to tor")
if authenticate: stem.connection.authenticate(control_socket, CONTROL_PASSWORD) @@ -396,15 +422,16 @@ class Runner: Queries our test instance for tor's version.
Returns: - stem.version.Version for our test instance, None if we're unable to - connect to it + stem.version.Version for our test instance + + Raises: + TorInaccessable if this can't be determined """
# TODO: replace with higher level functions when we've completed a basic # controller class
control_socket = self.get_tor_socket() - if not control_socket: return None
control_socket.send("GETINFO version") version_response = control_socket.recv() @@ -466,7 +493,7 @@ class Runner: # resides in is only accessable by the tor user (and refuses to finish # starting if it isn't).
- if OPT_SOCKET in CONNECTION_OPTS[self._connection_type]: + if OPT_SOCKET in self.get_connection_options(): try: socket_dir = os.path.dirname(CONTROL_SOCKET_PATH) _print_status(" making control socket directory (%s)... " % socket_dir, STATUS_ATTR, quiet)
tor-commits@lists.torproject.org