
commit b34f8990b6604996d7d60d139267ae43bac1de02 Author: Damian Johnson <atagar@torproject.org> Date: Sun Nov 13 15:09:51 2011 -0800 Shuffling integ tests to match unit tests Unit tests are nicely categorized under their respective modules, so reordering integration tests to match. --- run_tests.py | 8 +- stem/util/__init__.py | 2 +- test/integ/__init__.py | 2 +- test/integ/message.py | 242 ----------------------------------- test/integ/system.py | 64 --------- test/integ/types/__init__.py | 6 + test/integ/types/control_message.py | 242 +++++++++++++++++++++++++++++++++++ test/integ/util/__init__.py | 6 + test/integ/util/system.py | 65 ++++++++++ 9 files changed, 325 insertions(+), 312 deletions(-) diff --git a/run_tests.py b/run_tests.py index 530466a..7dcffaf 100755 --- a/run_tests.py +++ b/run_tests.py @@ -17,8 +17,8 @@ import test.unit.types.control_line import test.unit.types.version import test.unit.connection.protocolinfo_response import test.unit.util.enum -import test.integ.message -import test.integ.system +import test.integ.types.control_message +import test.integ.util.system import stem.util.enum import stem.util.term as term @@ -35,8 +35,8 @@ UNIT_TESTS = (("stem.types.ControlMessage", test.unit.types.control_message.Test ("stem.util.enum", test.unit.util.enum.TestEnum), ) -INTEG_TESTS = (("stem.types.ControlMessage", test.integ.message.TestMessageFunctions), - ("stem.util.system", test.integ.system.TestSystemFunctions), +INTEG_TESTS = (("stem.types.ControlMessage", test.integ.types.control_message.TestControlMessage), + ("stem.util.system", test.integ.util.system.TestSystem), ) # TODO: drop targets? diff --git a/stem/util/__init__.py b/stem/util/__init__.py index 14692fe..42569c9 100644 --- a/stem/util/__init__.py +++ b/stem/util/__init__.py @@ -16,5 +16,5 @@ stem_logger = logging.getLogger("stem") if not stem_logger.handlers: stem_logger.addHandler(NullHandler()) -__all__ = ["conf", "enum", "log", "proc", "system", "term"] +__all__ = ["conf", "enum", "proc", "system", "term"] diff --git a/test/integ/__init__.py b/test/integ/__init__.py index 718d40a..b96692a 100644 --- a/test/integ/__init__.py +++ b/test/integ/__init__.py @@ -2,5 +2,5 @@ Integration tests for the stem library. """ -__all__ = ["message", "system"] +__all__ = [] diff --git a/test/integ/message.py b/test/integ/message.py deleted file mode 100644 index a8e722d..0000000 --- a/test/integ/message.py +++ /dev/null @@ -1,242 +0,0 @@ -""" -Integration tests for the stem.types.ControlMessage class. -""" - -import re -import socket -import unittest - -import stem.types -import test.runner - -class TestMessageFunctions(unittest.TestCase): - """ - Exercises the 'stem.types.ControlMessage' class with an actual tor instance. - """ - - def test_unestablished_socket(self): - """ - Checks message parsing when we have a valid but unauthenticated socket. - """ - - control_socket, control_socket_file = self._get_control_socket(False) - - # If an unauthenticated connection gets a message besides AUTHENTICATE or - # PROTOCOLINFO then tor will give an 'Authentication required.' message and - # hang up. - - control_socket_file.write("GETINFO version\r\n") - control_socket_file.flush() - - auth_required_response = stem.types.read_message(control_socket_file) - self.assertEquals("Authentication required.", str(auth_required_response)) - self.assertEquals(["Authentication required."], list(auth_required_response)) - self.assertEquals("514 Authentication required.\r\n", auth_required_response.raw_content()) - self.assertEquals([("514", " ", "Authentication required.")], auth_required_response.content()) - - # The socket's broken but doesn't realize it yet. Send another message and - # it should fail with a closed exception. - - control_socket_file.write("GETINFO version\r\n") - control_socket_file.flush() - - self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) - - # Additional socket usage should fail, and pulling more responses will fail - # with more closed exceptions. - - control_socket_file.write("GETINFO version\r\n") - self.assertRaises(socket.error, control_socket_file.flush) - self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) - self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) - self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) - - # The socket connection is already broken so calling close shouldn't have - # an impact. - - control_socket.close() - control_socket_file.write("GETINFO version\r\n") - self.assertRaises(socket.error, control_socket_file.flush) - self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) - - # Closing the file handler, however, will cause a different type of error. - # This seems to depend on the python version, in 2.6 we get an - # AttributeError and in 2.7 the close() call raises... - # error: [Errno 32] Broken pipe - - try: - control_socket_file.close() - control_socket_file.write("GETINFO version\r\n") - except: pass - - # receives: AttributeError: 'NoneType' object has no attribute 'sendall' - self.assertRaises(AttributeError, control_socket_file.flush) - - # receives: stem.types.SocketClosed: socket file has been closed - self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) - - def test_invalid_command(self): - """ - Parses the response for a command which doesn't exist. - """ - - control_socket, control_socket_file = self._get_control_socket() - - control_socket_file.write("blarg\r\n") - control_socket_file.flush() - - unrecognized_command_response = stem.types.read_message(control_socket_file) - 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() - control_socket_file.close() - - def test_invalid_getinfo(self): - """ - Parses the response for a GETINFO query which doesn't exist. - """ - - control_socket, control_socket_file = self._get_control_socket() - - control_socket_file.write("GETINFO blarg\r\n") - control_socket_file.flush() - - unrecognized_key_response = stem.types.read_message(control_socket_file) - 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() - control_socket_file.close() - - def test_getinfo_config_file(self): - """ - Parses the 'GETINFO config-file' response. - """ - - runner = test.runner.get_runner() - torrc_dst = runner.get_torrc_path() - - control_socket, control_socket_file = self._get_control_socket() - - control_socket_file.write("GETINFO config-file\r\n") - control_socket_file.flush() - - config_file_response = stem.types.read_message(control_socket_file) - 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() - control_socket_file.close() - - def test_getinfo_config_text(self): - """ - Parses the 'GETINFO config-text' response. - """ - - if stem.process.get_tor_version() < stem.types.REQ_GETINFO_CONFIG_TEXT: - return - - # We can't be certain of the order, and there may be extra config-text - # entries as per... - # https://trac.torproject.org/projects/tor/ticket/2362 - # - # so we'll just check that the response is a superset of our config - - runner = test.runner.get_runner() - torrc_contents = [] - - for line in runner.get_torrc_contents().split("\n"): - line = line.strip() - - if line and not line.startswith("#"): - torrc_contents.append(line) - - control_socket, control_socket_file = self._get_control_socket() - - control_socket_file.write("GETINFO config-text\r\n") - control_socket_file.flush() - - config_text_response = stem.types.read_message(control_socket_file) - - # 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() - control_socket_file.close() - - def test_bw_event(self): - """ - Issues 'SETEVENTS BW' and parses a few events. - """ - - control_socket, control_socket_file = self._get_control_socket() - - control_socket_file.write("SETEVENTS BW\r\n") - control_socket_file.flush() - - setevents_response = stem.types.read_message(control_socket_file) - 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 = stem.types.read_message(control_socket_file) - 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() - control_socket_file.close() - - def _get_control_socket(self, authenticate = True): - """ - Provides a socket connected to the tor test instance's control port. - - Arguments: - authenticate (bool) - if True then the socket is authenticated - - Returns: - (socket.socket, file) tuple with the control socket and its file - """ - - runner = test.runner.get_runner() - - control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - control_socket.connect(("127.0.0.1", runner.get_control_port())) - control_socket_file = control_socket.makefile() - - if authenticate: - control_socket_file.write("AUTHENTICATE\r\n") - control_socket_file.flush() - - authenticate_response = stem.types.read_message(control_socket_file) - - self.assertEquals("OK", str(authenticate_response)) - self.assertEquals(["OK"], list(authenticate_response)) - self.assertEquals("250 OK\r\n", authenticate_response.raw_content()) - self.assertEquals([("250", " ", "OK")], authenticate_response.content()) - - return (control_socket, control_socket_file) - diff --git a/test/integ/system.py b/test/integ/system.py deleted file mode 100644 index 32ac892..0000000 --- a/test/integ/system.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -Unit tests for the stem.util.system functions in the context of a tor process. -""" - -import os -import unittest - -import test.runner -import stem.util.system as system - -class TestSystemFunctions(unittest.TestCase): - """ - Tests the stem.util.system functions against the tor process that we're - running. - """ - - def test_is_available(self): - """ - Checks the stem.util.system.is_available function. - """ - - # since we're running tor it would be kinda sad if this didn't detect it - self.assertTrue(system.is_available("tor")) - - # but it would be kinda weird if this did... - self.assertFalse(system.is_available("blarg_and_stuff")) - - def test_is_running(self): - """ - Checks the stem.util.system.is_running function. - """ - - self.assertTrue(system.is_running("tor")) - self.assertFalse(system.is_running("blarg_and_stuff")) - - def test_get_pid(self): - """ - Checks the stem.util.system.get_pid function. - """ - - runner = test.runner.get_runner() - self.assertEquals(runner.get_pid(), system.get_pid("tor", runner.get_control_port())) - self.assertEquals(None, system.get_pid("blarg_and_stuff")) - - def test_get_cwd(self): - """ - Checks the stem.util.system.get_cwd function. - """ - - # tor's pwd will match our process since we started it - runner = test.runner.get_runner() - self.assertEquals(os.getcwd(), system.get_cwd(runner.get_pid())) - self.assertEquals(None, system.get_cwd(99999, True)) - self.assertRaises(IOError, system.get_cwd, 99999, False) - - def test_get_bsd_jail_id(self): - """ - Exercises the util.system.get_bsd_jail_id function, running through the - failure case (since I'm not on BSD I can't really test this function - properly). - """ - - self.assertEquals(0, system.get_bsd_jail_id(99999)) - diff --git a/test/integ/types/__init__.py b/test/integ/types/__init__.py new file mode 100644 index 0000000..7ab4c07 --- /dev/null +++ b/test/integ/types/__init__.py @@ -0,0 +1,6 @@ +""" +Integration tests for stem.types. +""" + +__all__ = ["control_message"] + diff --git a/test/integ/types/control_message.py b/test/integ/types/control_message.py new file mode 100644 index 0000000..07259e7 --- /dev/null +++ b/test/integ/types/control_message.py @@ -0,0 +1,242 @@ +""" +Integration tests for the stem.types.ControlMessage class. +""" + +import re +import socket +import unittest + +import stem.types +import test.runner + +class TestControlMessage(unittest.TestCase): + """ + Exercises the 'stem.types.ControlMessage' class with an actual tor instance. + """ + + def test_unestablished_socket(self): + """ + Checks message parsing when we have a valid but unauthenticated socket. + """ + + control_socket, control_socket_file = self._get_control_socket(False) + + # If an unauthenticated connection gets a message besides AUTHENTICATE or + # PROTOCOLINFO then tor will give an 'Authentication required.' message and + # hang up. + + control_socket_file.write("GETINFO version\r\n") + control_socket_file.flush() + + auth_required_response = stem.types.read_message(control_socket_file) + self.assertEquals("Authentication required.", str(auth_required_response)) + self.assertEquals(["Authentication required."], list(auth_required_response)) + self.assertEquals("514 Authentication required.\r\n", auth_required_response.raw_content()) + self.assertEquals([("514", " ", "Authentication required.")], auth_required_response.content()) + + # The socket's broken but doesn't realize it yet. Send another message and + # it should fail with a closed exception. + + control_socket_file.write("GETINFO version\r\n") + control_socket_file.flush() + + self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) + + # Additional socket usage should fail, and pulling more responses will fail + # with more closed exceptions. + + control_socket_file.write("GETINFO version\r\n") + self.assertRaises(socket.error, control_socket_file.flush) + self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) + self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) + self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) + + # The socket connection is already broken so calling close shouldn't have + # an impact. + + control_socket.close() + control_socket_file.write("GETINFO version\r\n") + self.assertRaises(socket.error, control_socket_file.flush) + self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) + + # Closing the file handler, however, will cause a different type of error. + # This seems to depend on the python version, in 2.6 we get an + # AttributeError and in 2.7 the close() call raises... + # error: [Errno 32] Broken pipe + + try: + control_socket_file.close() + control_socket_file.write("GETINFO version\r\n") + except: pass + + # receives: AttributeError: 'NoneType' object has no attribute 'sendall' + self.assertRaises(AttributeError, control_socket_file.flush) + + # receives: stem.types.SocketClosed: socket file has been closed + self.assertRaises(stem.types.SocketClosed, stem.types.read_message, control_socket_file) + + def test_invalid_command(self): + """ + Parses the response for a command which doesn't exist. + """ + + control_socket, control_socket_file = self._get_control_socket() + + control_socket_file.write("blarg\r\n") + control_socket_file.flush() + + unrecognized_command_response = stem.types.read_message(control_socket_file) + 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() + control_socket_file.close() + + def test_invalid_getinfo(self): + """ + Parses the response for a GETINFO query which doesn't exist. + """ + + control_socket, control_socket_file = self._get_control_socket() + + control_socket_file.write("GETINFO blarg\r\n") + control_socket_file.flush() + + unrecognized_key_response = stem.types.read_message(control_socket_file) + 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() + control_socket_file.close() + + def test_getinfo_config_file(self): + """ + Parses the 'GETINFO config-file' response. + """ + + runner = test.runner.get_runner() + torrc_dst = runner.get_torrc_path() + + control_socket, control_socket_file = self._get_control_socket() + + control_socket_file.write("GETINFO config-file\r\n") + control_socket_file.flush() + + config_file_response = stem.types.read_message(control_socket_file) + 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() + control_socket_file.close() + + def test_getinfo_config_text(self): + """ + Parses the 'GETINFO config-text' response. + """ + + if stem.process.get_tor_version() < stem.types.REQ_GETINFO_CONFIG_TEXT: + self.skipTest("(requires %s)" % stem.types.REQ_GETINFO_CONFIG_TEXT) + + # We can't be certain of the order, and there may be extra config-text + # entries as per... + # https://trac.torproject.org/projects/tor/ticket/2362 + # + # so we'll just check that the response is a superset of our config + + runner = test.runner.get_runner() + torrc_contents = [] + + for line in runner.get_torrc_contents().split("\n"): + line = line.strip() + + if line and not line.startswith("#"): + torrc_contents.append(line) + + control_socket, control_socket_file = self._get_control_socket() + + control_socket_file.write("GETINFO config-text\r\n") + control_socket_file.flush() + + config_text_response = stem.types.read_message(control_socket_file) + + # 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() + control_socket_file.close() + + def test_bw_event(self): + """ + Issues 'SETEVENTS BW' and parses a few events. + """ + + control_socket, control_socket_file = self._get_control_socket() + + control_socket_file.write("SETEVENTS BW\r\n") + control_socket_file.flush() + + setevents_response = stem.types.read_message(control_socket_file) + 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 = stem.types.read_message(control_socket_file) + 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() + control_socket_file.close() + + def _get_control_socket(self, authenticate = True): + """ + Provides a socket connected to the tor test instance's control port. + + Arguments: + authenticate (bool) - if True then the socket is authenticated + + Returns: + (socket.socket, file) tuple with the control socket and its file + """ + + runner = test.runner.get_runner() + + control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + control_socket.connect(("127.0.0.1", runner.get_control_port())) + control_socket_file = control_socket.makefile() + + if authenticate: + control_socket_file.write("AUTHENTICATE\r\n") + control_socket_file.flush() + + authenticate_response = stem.types.read_message(control_socket_file) + + self.assertEquals("OK", str(authenticate_response)) + self.assertEquals(["OK"], list(authenticate_response)) + self.assertEquals("250 OK\r\n", authenticate_response.raw_content()) + self.assertEquals([("250", " ", "OK")], authenticate_response.content()) + + return (control_socket, control_socket_file) + diff --git a/test/integ/util/__init__.py b/test/integ/util/__init__.py new file mode 100644 index 0000000..a0b3303 --- /dev/null +++ b/test/integ/util/__init__.py @@ -0,0 +1,6 @@ +""" +Integration tests for stem.util.* contents. +""" + +__all__ = ["system"] + diff --git a/test/integ/util/system.py b/test/integ/util/system.py new file mode 100644 index 0000000..fc7c384 --- /dev/null +++ b/test/integ/util/system.py @@ -0,0 +1,65 @@ +""" +Integration tests for the stem.util.system functions in the context of a tor +process. +""" + +import os +import unittest + +import test.runner +import stem.util.system + +class TestSystem(unittest.TestCase): + """ + Tests the stem.util.system functions against the tor process that we're + running. + """ + + def test_is_available(self): + """ + Checks the stem.util.system.is_available function. + """ + + # since we're running tor it would be kinda sad if this didn't detect it + self.assertTrue(stem.util.system.is_available("tor")) + + # but it would be kinda weird if this did... + self.assertFalse(stem.util.system.is_available("blarg_and_stuff")) + + def test_is_running(self): + """ + Checks the stem.util.system.is_running function. + """ + + self.assertTrue(stem.util.system.is_running("tor")) + self.assertFalse(stem.util.system.is_running("blarg_and_stuff")) + + def test_get_pid(self): + """ + Checks the stem.util.system.get_pid function. + """ + + runner = test.runner.get_runner() + self.assertEquals(runner.get_pid(), stem.util.system.get_pid("tor", runner.get_control_port())) + self.assertEquals(None, stem.util.system.get_pid("blarg_and_stuff")) + + def test_get_cwd(self): + """ + Checks the stem.util.system.get_cwd function. + """ + + # tor's pwd will match our process since we started it + runner = test.runner.get_runner() + self.assertEquals(os.getcwd(), stem.util.system.get_cwd(runner.get_pid())) + self.assertEquals(None, stem.util.system.get_cwd(99999, True)) + self.assertRaises(IOError, stem.util.system.get_cwd, 99999, False) + + def test_get_bsd_jail_id(self): + """ + Exercises the stem.util.system.get_bsd_jail_id function, running through + the failure case (since I'm not on BSD I can't really test this function + properly). + """ + + self.assertEquals(0, stem.util.system.get_bsd_jail_id(99999)) +