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.
This commit is contained in:
Damian Johnson 2011-10-16 15:19:03 -07:00
parent bdbf352ad7
commit 0c03d4eb2a
3 changed files with 143 additions and 109 deletions

View File

@ -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)
# makes a temporary directory for the runtime resources of our integ test
test_dir = tempfile.mktemp("-stem-integ")
integ_runner = test.integ.runner.Runner()
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()
integ_runner.run_setup()
integ_runner.start()
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)
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

View File

@ -2,5 +2,5 @@
Integration tests for the stem library.
"""
__all__ = []
__all__ = ["runner"]

130
test/integ/runner.py Normal file
View File

@ -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