commit 0c03d4eb2a04f71942c53caf6314c25ce66be18e Author: Damian Johnson atagar@torproject.org Date: Sun Oct 16 15:19:03 2011 -0700
Moving integration test init/shutdown into class
Making a Runner class which will be available to integration tests. This both better modularizes the code and will allow for us to give runtime context to the tests. --- run_tests.py | 120 +++++--------------------------------------- test/integ/__init__.py | 2 +- test/integ/runner.py | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 109 deletions(-)
diff --git a/run_tests.py b/run_tests.py index 9e4487c..dab1c4f 100755 --- a/run_tests.py +++ b/run_tests.py @@ -4,18 +4,14 @@ Runs unit and integration tests. """
-import os import sys -import time import getopt -import signal -import tempfile import unittest -import subprocess import test.unit.message import test.unit.version +import test.integ.runner
-from stem.util import enum, system, term +from stem.util import enum, term
OPT = "uit:h" OPT_EXPANDED = ["unit", "integ", "targets=", "help"] @@ -51,57 +47,6 @@ Runs tests for the stem library. %s """
-# Number of seconds before we time out our attempt to start a tor instance -TOR_INIT_TIMEOUT = 20 - -def init_tor_process(torrc_dst): - """ - Initializes and returns a tor process. This blocks until initialization - completes or we error out. - - Arguments: - torrc_dst (str) - path for a torrc configuration to use - - Returns: - subprocess.Popen instance for the instantiated tor process - - Raises: - OSError if we either fail to create the tor process or reached a timeout without success - """ - - start_time = time.time() - - # starts a tor subprocess, raising an OSError if it fails - tor_process = subprocess.Popen(["tor", "-f", torrc_dst], stdout = subprocess.PIPE, stderr = subprocess.PIPE) - - # time ourselves out if we reach TOR_INIT_TIMEOUT - def timeout_handler(signum, frame): - # terminates the uninitialized tor process and raise on timeout - tor_process.kill() - raise OSError("unable to start tor: reached a %i second timeout without success" % TOR_INIT_TIMEOUT) - - signal.signal(signal.SIGALRM, timeout_handler) - signal.alarm(TOR_INIT_TIMEOUT) - - print term.format("Starting tor...", term.Color.BLUE, term.Attr.BOLD) - - while True: - init_line = tor_process.stdout.readline().strip() - - # this will provide empty results if the process is terminated - if not init_line: - tor_process.kill() # ... but best make sure - raise OSError("tor process terminated") - - print term.format(" %s" % init_line, term.Color.BLUE) - - # return the process if we're done with bootstrapping - if init_line.endswith("Bootstrapped 100%: Done."): - print term.format(" done (%i seconds)" % (time.time() - start_time), term.Color.BLUE, term.Attr.BOLD) - print - - return tor_process - if __name__ == '__main__': run_unit_tests = False run_integ_tests = False @@ -160,62 +105,21 @@ if __name__ == '__main__': print
if run_integ_tests: - # TODO: check if there's already a tor instance running - print "%s\n%s\n%s\n" % (DIVIDER, "INTEGRATION TESTS".center(70), DIVIDER)
- print term.format("Setting up a test instance...", term.Color.BLUE, term.Attr.BOLD) + integ_runner = test.integ.runner.Runner()
- # makes a temporary directory for the runtime resources of our integ test - test_dir = tempfile.mktemp("-stem-integ") - - try: - os.makedirs(test_dir) - print term.format(" created test directory: %s" % test_dir, term.Color.BLUE, term.Attr.BOLD) - except OSError, exc: - print term.format("Unable to make testing directory: %s" % exc, term.Color.RED, term.Attr.BOLD) - sys.exit(1) - - # makes a basic torrc for the integration tests to run against - torrc_contents = """# basic integration testing configuration -DataDirectory %s -ControlPort 9051 -""" % test_dir - - # writes our testing torrc - torrc_dst = os.path.join(test_dir, "torrc") - try: - torrc_file = open(torrc_dst, "w") - torrc_file.write(torrc_contents) - torrc_file.close() - - print term.format(" wrote torrc: %s" % torrc_dst, term.Color.BLUE, term.Attr.BOLD) - - for line in torrc_contents.split("\n"): - print term.format(" %s" % line.strip(), term.Color.BLUE) - except Exception, exc: - print term.format("Unable to write testing torrc: %s" % exc, term.Color.RED, term.Attr.BOLD) - sys.exit(1) - - # starts a tor instance try: - tor_process = init_tor_process(torrc_dst) - except OSError, exc: - print term.format("Unable to start a tor instance: %s" % exc, term.Color.RED, term.Attr.BOLD) - sys.exit(1) + integ_runner.run_setup() + integ_runner.start()
- print term.format("Running tests...", term.Color.BLUE, term.Attr.BOLD) - print - - # TODO: run tests - - print term.format("Shutting down tor...", term.Color.BLUE, term.Attr.BOLD) - tor_process.kill() - print term.format(" done", term.Color.BLUE, term.Attr.BOLD) - - - - + # TODO: run tests + print term.format("Running tests...", term.Color.BLUE, term.Attr.BOLD) + print + except OSError: + pass + finally: + integ_runner.stop()
# TODO: we might do target selection later but for now we should simply # work with a single simple tor instance and see how it works out diff --git a/test/integ/__init__.py b/test/integ/__init__.py index b96692a..ecfc9cd 100644 --- a/test/integ/__init__.py +++ b/test/integ/__init__.py @@ -2,5 +2,5 @@ Integration tests for the stem library. """
-__all__ = [] +__all__ = ["runner"]
diff --git a/test/integ/runner.py b/test/integ/runner.py new file mode 100644 index 0000000..207c2e3 --- /dev/null +++ b/test/integ/runner.py @@ -0,0 +1,130 @@ +""" +Starts and stops test instances for integration tests. +""" + +import os +import sys +import time +import signal +import tempfile +import subprocess + +from stem.util import term + +# number of seconds before we time out our attempt to start a tor instance +TOR_INIT_TIMEOUT = 30 + +BASIC_TORRC = """# configuration for stem integration tests +DataDirectory %s +ControlPort 1111 +""" + +class Runner: + def __init__(self): + self._test_dir = tempfile.mktemp("-stem-integ") + self._torrc_contents = BASIC_TORRC % self._test_dir + self._tor_process = None + + def run_setup(self): + """ + Makes a temporary directory for the runtime resources of our integ tests. + + Raises: + OSError if unsuccessful + """ + + print term.format("Setting up a test instance...", term.Color.BLUE, term.Attr.BOLD) + + # makes a temporary directory for the runtime resources of our integ test + try: + sys.stdout.write(term.format(" making test directory (%s)... " % self._test_dir, term.Color.BLUE, term.Attr.BOLD)) + os.makedirs(self._test_dir) + sys.stdout.write(term.format("done\n", term.Color.BLUE, term.Attr.BOLD)) + except OSError, exc: + sys.stdout.write(term.format("failed (%s)\n" % exc, term.Color.RED, term.Attr.BOLD)) + raise exc + + # writes our testing torrc + torrc_dst = os.path.join(self._test_dir, "torrc") + try: + sys.stdout.write(term.format(" writing torrc (%s)... " % torrc_dst, term.Color.BLUE, term.Attr.BOLD)) + + torrc_file = open(torrc_dst, "w") + torrc_file.write(self._torrc_contents) + torrc_file.close() + + sys.stdout.write(term.format("done\n", term.Color.BLUE, term.Attr.BOLD)) + + for line in self._torrc_contents.strip().split("\n"): + print term.format(" %s" % line.strip(), term.Color.BLUE) + except Exception, exc: + sys.stdout.write(term.format("failed (%s)\n" % exc, term.Color.RED, term.Attr.BOLD)) + raise exc + finally: + print # extra newline + + def start(self): + """ + Initializes a tor process. This blocks until initialization completes or we + error out. + + Raises: + OSError if we either fail to create the tor process or reached a timeout + without success + """ + + print term.format("Starting tor...", term.Color.BLUE, term.Attr.BOLD) + start_time = time.time() + + try: + # terminate our previous instance before continuing if we had one + if self._tor_process: self._tor_process.kill() + + # double check that we have a torrc to work with + torrc_dst = os.path.join(self._test_dir, "torrc") + if not os.path.exists(torrc_dst): + raise OSError("torrc doesn't exist (%s)" % torrc_dst) + + # starts a tor subprocess, raising an OSError if it fails + self._tor_process = subprocess.Popen(["tor", "-f", torrc_dst], stdout = subprocess.PIPE, stderr = subprocess.PIPE) + + # time ourselves out if we reach TOR_INIT_TIMEOUT + def timeout_handler(signum, frame): + # terminates the uninitialized tor process and raise on timeout + self._tor_process.kill() + raise OSError("reached a %i second timeout without success" % TOR_INIT_TIMEOUT) + + signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(TOR_INIT_TIMEOUT) + + while True: + init_line = self._tor_process.stdout.readline().strip() + + # this will provide empty results if the process is terminated + if not init_line: + self._tor_process.kill() # ... but best make sure + raise OSError("process terminated") + + print term.format(" %s" % init_line, term.Color.BLUE) + + # return the process if we're done with bootstrapping + if init_line.endswith("Bootstrapped 100%: Done."): + print term.format(" done (%i seconds)" % (time.time() - start_time), term.Color.BLUE, term.Attr.BOLD) + return + except OSError, exc: + print term.format(" failed to start tor: %s" % exc, term.Color.RED, term.Attr.BOLD) + raise exc + finally: + print # extra newline + + def stop(self): + """ + Terminates our tor instance. + """ + + if self._tor_process: + sys.stdout.write(term.format("Shutting down tor... ", term.Color.BLUE, term.Attr.BOLD)) + self._tor_process.kill() + sys.stdout.write(term.format("done\n", term.Color.BLUE, term.Attr.BOLD)) + print # extra newline +