commit f38ad0811290b51b99475de28628895a663e7dec
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jan 29 14:40:27 2012 -0800
Refactoring ControlMessage integ tests
Besides the normal cleanup I'm pushing most of the skipTest checks into the
runner module. The advantage of this is that it simplifies tests a little more
and allows a standardized skip message rather than having each module provide
their own for the same thing.
---
test/integ/connection/authentication.py | 4 +-
test/integ/connection/connect.py | 4 +-
test/integ/connection/protocolinfo.py | 4 +-
test/integ/socket/control_message.py | 146 +++++++++++++------------------
test/integ/version.py | 13 +--
test/runner.py | 54 ++++++++---
6 files changed, 106 insertions(+), 119 deletions(-)
diff --git a/test/integ/connection/authentication.py b/test/integ/connection/authentication.py
index cc36c66..0762b23 100644
--- a/test/integ/connection/authentication.py
+++ b/test/integ/connection/authentication.py
@@ -78,9 +78,7 @@ def _get_auth_failure_message(auth_type):
class TestAuthenticate(unittest.TestCase):
def setUp(self):
- # none of these tests apply if there's no control connection
- if not test.runner.get_runner().is_accessible():
- self.skipTest("(no connection)")
+ test.runner.require_control(self)
def test_authenticate_general(self):
"""
diff --git a/test/integ/connection/connect.py b/test/integ/connection/connect.py
index ca3cf41..9b6337a 100644
--- a/test/integ/connection/connect.py
+++ b/test/integ/connection/connect.py
@@ -11,9 +11,7 @@ import test.runner
class TestConnect(unittest.TestCase):
def setUp(self):
- # none of these tests apply if there's no control connection
- if not test.runner.get_runner().is_accessible():
- self.skipTest("(no connection)")
+ test.runner.require_control(self)
# prevents the function from printing to the real stdout
self.original_stdout = sys.stdout
diff --git a/test/integ/connection/protocolinfo.py b/test/integ/connection/protocolinfo.py
index a0e1699..b572aee 100644
--- a/test/integ/connection/protocolinfo.py
+++ b/test/integ/connection/protocolinfo.py
@@ -26,9 +26,7 @@ def filter_system_call(prefixes):
class TestProtocolInfo(unittest.TestCase):
def setUp(self):
- if not test.runner.get_runner().is_accessible():
- self.skipTest("(no connection)")
-
+ test.runner.require_control(self)
mocking.mock(stem.util.proc.is_available, mocking.return_false())
mocking.mock(stem.util.system.is_available, mocking.return_true())
diff --git a/test/integ/socket/control_message.py b/test/integ/socket/control_message.py
index ec99edb..ce25c8f 100644
--- a/test/integ/socket/control_message.py
+++ b/test/integ/socket/control_message.py
@@ -3,7 +3,6 @@ Integration tests for the stem.socket.ControlMessage class.
"""
import re
-import socket
import unittest
import stem.socket
@@ -11,19 +10,19 @@ import stem.version
import test.runner
class TestControlMessage(unittest.TestCase):
+ def setUp(self):
+ test.runner.require_control(self)
+
def test_unestablished_socket(self):
"""
Checks message parsing when we have a valid but unauthenticated 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 = test.runner.get_runner().get_tor_socket(False)
control_socket.send("GETINFO version")
auth_required_response = control_socket.recv()
@@ -63,36 +62,26 @@ class TestControlMessage(unittest.TestCase):
Parses the response for a command which doesn't exist.
"""
- 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()
- self.assertEquals('Unrecognized command "blarg"', str(unrecognized_command_response))
- self.assertEquals(['Unrecognized command "blarg"'], list(unrecognized_command_response))
- self.assertEquals('510 Unrecognized command "blarg"\r\n', unrecognized_command_response.raw_content())
- self.assertEquals([('510', ' ', 'Unrecognized command "blarg"')], unrecognized_command_response.content())
-
- control_socket.close()
+ with test.runner.get_runner().get_tor_socket() as control_socket:
+ control_socket.send("blarg")
+ unrecognized_command_response = control_socket.recv()
+ self.assertEquals('Unrecognized command "blarg"', str(unrecognized_command_response))
+ self.assertEquals(['Unrecognized command "blarg"'], list(unrecognized_command_response))
+ self.assertEquals('510 Unrecognized command "blarg"\r\n', unrecognized_command_response.raw_content())
+ self.assertEquals([('510', ' ', 'Unrecognized command "blarg"')], unrecognized_command_response.content())
def test_invalid_getinfo(self):
"""
Parses the response for a GETINFO query which doesn't exist.
"""
- 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()
- self.assertEquals('Unrecognized key "blarg"', str(unrecognized_key_response))
- self.assertEquals(['Unrecognized key "blarg"'], list(unrecognized_key_response))
- self.assertEquals('552 Unrecognized key "blarg"\r\n', unrecognized_key_response.raw_content())
- self.assertEquals([('552', ' ', 'Unrecognized key "blarg"')], unrecognized_key_response.content())
-
- control_socket.close()
+ with test.runner.get_runner().get_tor_socket() as control_socket:
+ control_socket.send("GETINFO blarg")
+ unrecognized_key_response = control_socket.recv()
+ self.assertEquals('Unrecognized key "blarg"', str(unrecognized_key_response))
+ self.assertEquals(['Unrecognized key "blarg"'], list(unrecognized_key_response))
+ self.assertEquals('552 Unrecognized key "blarg"\r\n', unrecognized_key_response.raw_content())
+ self.assertEquals([('552', ' ', 'Unrecognized key "blarg"')], unrecognized_key_response.content())
def test_getinfo_config_file(self):
"""
@@ -101,30 +90,22 @@ 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()
-
- control_socket.send("GETINFO config-file")
- config_file_response = control_socket.recv()
- self.assertEquals("config-file=%s\nOK" % torrc_dst, str(config_file_response))
- self.assertEquals(["config-file=%s" % torrc_dst, "OK"], list(config_file_response))
- self.assertEquals("250-config-file=%s\r\n250 OK\r\n" % torrc_dst, config_file_response.raw_content())
- self.assertEquals([("250", "-", "config-file=%s" % torrc_dst), ("250", " ", "OK")], config_file_response.content())
- control_socket.close()
+ with runner.get_tor_socket() as control_socket:
+ control_socket.send("GETINFO config-file")
+ config_file_response = control_socket.recv()
+ self.assertEquals("config-file=%s\nOK" % torrc_dst, str(config_file_response))
+ self.assertEquals(["config-file=%s" % torrc_dst, "OK"], list(config_file_response))
+ self.assertEquals("250-config-file=%s\r\n250 OK\r\n" % torrc_dst, config_file_response.raw_content())
+ self.assertEquals([("250", "-", "config-file=%s" % torrc_dst), ("250", " ", "OK")], config_file_response.content())
def test_getinfo_config_text(self):
"""
Parses the 'GETINFO config-text' response.
"""
+ test.runner.require_version(self, stem.version.Requirement.GETINFO_CONFIG_TEXT)
runner = test.runner.get_runner()
- req_version = stem.version.Requirement.GETINFO_CONFIG_TEXT
-
- 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
# entries as per...
@@ -140,50 +121,43 @@ class TestControlMessage(unittest.TestCase):
if line and not line.startswith("#"):
torrc_contents.append(line)
- control_socket = runner.get_tor_socket()
- control_socket.send("GETINFO config-text")
- config_text_response = control_socket.recv()
-
- # the response should contain two entries, the first being a data response
- self.assertEqual(2, len(list(config_text_response)))
- self.assertEqual("OK", list(config_text_response)[1])
- self.assertEqual(("250", " ", "OK"), config_text_response.content()[1])
- self.assertTrue(config_text_response.raw_content().startswith("250+config-text=\r\n"))
- self.assertTrue(config_text_response.raw_content().endswith("\r\n.\r\n250 OK\r\n"))
- self.assertTrue(str(config_text_response).startswith("config-text=\n"))
- self.assertTrue(str(config_text_response).endswith("\nOK"))
-
- for torrc_entry in torrc_contents:
- self.assertTrue("\n%s\n" % torrc_entry in str(config_text_response))
- self.assertTrue(torrc_entry in list(config_text_response)[0])
- 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])
-
- control_socket.close()
+ with runner.get_tor_socket() as control_socket:
+ control_socket.send("GETINFO config-text")
+ config_text_response = control_socket.recv()
+
+ # the response should contain two entries, the first being a data response
+ self.assertEqual(2, len(list(config_text_response)))
+ self.assertEqual("OK", list(config_text_response)[1])
+ self.assertEqual(("250", " ", "OK"), config_text_response.content()[1])
+ self.assertTrue(config_text_response.raw_content().startswith("250+config-text=\r\n"))
+ self.assertTrue(config_text_response.raw_content().endswith("\r\n.\r\n250 OK\r\n"))
+ self.assertTrue(str(config_text_response).startswith("config-text=\n"))
+ self.assertTrue(str(config_text_response).endswith("\nOK"))
+
+ for torrc_entry in torrc_contents:
+ self.assertTrue("\n%s\n" % torrc_entry in str(config_text_response))
+ self.assertTrue(torrc_entry in list(config_text_response)[0])
+ 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])
def test_bw_event(self):
"""
- Issues 'SETEVENTS BW' and parses a few events.
+ Issues 'SETEVENTS BW' and parses a couple events.
"""
- 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()
- self.assertEquals("OK", str(setevents_response))
- self.assertEquals(["OK"], list(setevents_response))
- self.assertEquals("250 OK\r\n", setevents_response.raw_content())
- self.assertEquals([("250", " ", "OK")], setevents_response.content())
-
- # Tor will emit a BW event once per second. Parsing two of them.
-
- for _ in range(2):
- bw_event = control_socket.recv()
- self.assertTrue(re.match("BW [0-9]+ [0-9]+", str(bw_event)))
- self.assertTrue(re.match("650 BW [0-9]+ [0-9]+\r\n", bw_event.raw_content()))
- self.assertEquals(("650", " "), bw_event.content()[0][:2])
-
- control_socket.close()
+ with test.runner.get_runner().get_tor_socket() as control_socket:
+ control_socket.send("SETEVENTS BW")
+ setevents_response = control_socket.recv()
+ self.assertEquals("OK", str(setevents_response))
+ self.assertEquals(["OK"], list(setevents_response))
+ self.assertEquals("250 OK\r\n", setevents_response.raw_content())
+ self.assertEquals([("250", " ", "OK")], setevents_response.content())
+
+ # Tor will emit a BW event once per second. Parsing two of them.
+
+ for _ in range(2):
+ bw_event = control_socket.recv()
+ self.assertTrue(re.match("BW [0-9]+ [0-9]+", str(bw_event)))
+ self.assertTrue(re.match("650 BW [0-9]+ [0-9]+\r\n", bw_event.raw_content()))
+ self.assertEquals(("650", " "), bw_event.content()[0][:2])
diff --git a/test/integ/version.py b/test/integ/version.py
index e344ef8..833cbd2 100644
--- a/test/integ/version.py
+++ b/test/integ/version.py
@@ -35,11 +35,9 @@ class TestVersion(unittest.TestCase):
test instance provides.
"""
- runner = test.runner.get_runner()
-
- if not runner.is_accessible():
- self.skipTest("(no connection)")
+ test.runner.require_control(self)
+ runner = test.runner.get_runner()
system_tor_version = stem.version.get_system_tor_version(runner.get_tor_command())
self.assertEquals(runner.get_tor_version(), system_tor_version)
@@ -49,12 +47,9 @@ class TestVersion(unittest.TestCase):
we can parse it.
"""
- runner = test.runner.get_runner()
-
- if not runner.is_accessible():
- self.skipTest("(no connection)")
+ test.runner.require_control(self)
- control_socket = runner.get_tor_socket()
+ control_socket = test.runner.get_runner().get_tor_socket()
control_socket.send("GETINFO version")
version_response = control_socket.recv()
control_socket.close()
diff --git a/test/runner.py b/test/runner.py
index 0e71ade..3cf5542 100644
--- a/test/runner.py
+++ b/test/runner.py
@@ -6,6 +6,8 @@ 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
+require_control - skips the test unless tor provides a controller endpoint
+require_version - skips the test unless we meet a tor version requirement
exercise_socket - Does a basic sanity check that a control socket can be used
get_runner - Singleton for fetching our runtime context.
@@ -86,13 +88,36 @@ class TorInaccessable(Exception):
"Raised when information is needed from tor but the instance we have is inaccessable"
pass
+def require_control(test_case):
+ """
+ Skips the test unless tor provides an endpoint for controllers to attach to.
+
+ Arguments:
+ test_case (unittest.TestCase) - test being ran
+ """
+
+ if not test.runner.get_runner().is_accessible():
+ test_case.skipTest("(no connection)")
+
+def require_version(test_case, req_version):
+ """
+ Skips the test unless we meet the required version.
+
+ Arguments:
+ test_case (unittest.TestCase) - test being ran
+ req_version (stem.version.Version) - required tor version for the test
+ """
+
+ if get_runner().get_tor_version() < req_version:
+ test_case.skipTest("(requires %s)" % req_version)
+
def exercise_socket(test_case, control_socket):
"""
Checks that we can now use the socket by issuing a 'GETINFO config-file'
query.
Arguments:
- test_case (unittest.TestCase) - unit testing case being ran
+ test_case (unittest.TestCase) - test being ran
control_socket (stem.socket.ControlSocket) - socket to be tested
"""
@@ -380,22 +405,21 @@ class Runner:
Returns:
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()
-
- control_socket.send("GETINFO version")
- version_response = control_socket.recv()
- control_socket.close()
-
- tor_version = list(version_response)[0][8:]
- return stem.version.Version(tor_version)
+ try:
+ # TODO: replace with higher level functions when we've completed a basic
+ # controller class
+ control_socket = self.get_tor_socket()
+
+ control_socket.send("GETINFO version")
+ version_response = control_socket.recv()
+ control_socket.close()
+
+ tor_version = list(version_response)[0][8:]
+ return stem.version.Version(tor_version)
+ except TorInaccessable:
+ return stem.version.get_system_tor_version(self.get_tor_command())
def get_tor_command(self):
"""