[tor-commits] [stem/master] Helper to asynchronously run tests
atagar at torproject.org
atagar at torproject.org
Thu Jun 8 17:17:55 UTC 2017
commit ad72e524bd1402ca74a96437d5f745932b650e7a
Author: Damian Johnson <atagar at torproject.org>
Date: Sat Jun 3 17:55:24 2017 -0700
Helper to asynchronously run tests
We already ran our installation tests asynchronously, but in a one-off fashion.
Adding a helper so we can experiment with fully parallelizing it and apply this
to other tests.
---
run_tests.py | 3 --
stem/util/test_tools.py | 37 +++++++++++++
test/integ/installation.py | 130 ++++++++++++++++++++-------------------------
3 files changed, 96 insertions(+), 74 deletions(-)
diff --git a/run_tests.py b/run_tests.py
index 7c894d2..49f8465 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -309,9 +309,6 @@ def main():
except OSError:
error_tracker.register_error()
finally:
- if integ_setup_thread:
- test.integ.installation.clean()
-
println()
integ_runner.stop()
println()
diff --git a/stem/util/test_tools.py b/stem/util/test_tools.py
index 6964572..c9912c0 100644
--- a/stem/util/test_tools.py
+++ b/stem/util/test_tools.py
@@ -33,6 +33,7 @@ import linecache
import os
import re
import time
+import threading
import unittest
import stem.prereq
@@ -49,6 +50,42 @@ CONFIG = stem.util.conf.config_dict('test', {
TEST_RUNTIMES = {}
+class SkipTest(Exception):
+ 'Notes that the test was skipped.'
+
+
+class AsyncTestResult(object):
+ """
+ Test results that can be applied later.
+ """
+
+ def __init__(self, runner):
+ self._failure = None
+ self._skip_reason = None
+
+ def _wrapper():
+ try:
+ runner()
+ except AssertionError as exc:
+ self._failure = str(exc)
+ except SkipTest as exc:
+ self._skip_reason = str(exc)
+
+ self._thread = threading.Thread(target = _wrapper)
+ self._thread.start()
+
+ def join(self):
+ self._thread.join()
+
+ def result(self, test):
+ self.join()
+
+ if self._failure:
+ test.fail(self._failure)
+ elif self._skip_reason:
+ test.skipTest(self._skip_reason)
+
+
class Issue(collections.namedtuple('Issue', ['line_number', 'message', 'line'])):
"""
Issue encountered by pyflakes or pycodestyle.
diff --git a/test/integ/installation.py b/test/integ/installation.py
index dd4eb88..da918a4 100644
--- a/test/integ/installation.py
+++ b/test/integ/installation.py
@@ -7,66 +7,95 @@ import os
import shutil
import sys
import tarfile
-import threading
import unittest
import stem
import stem.util.system
import test
-import test.require
INSTALL_MISMATCH_MSG = "Running 'python setup.py sdist' doesn't match our git contents in the following way. The manifest in our setup.py may need to be updated...\n\n"
BASE_INSTALL_PATH = '/tmp/stem_test'
DIST_PATH = os.path.join(test.STEM_BASE, 'dist')
-SETUP_THREAD, INSTALL_FAILURE, INSTALL_PATH, SDIST_FAILURE = None, None, None, None
PYTHON_EXE = sys.executable if sys.executable else 'python'
+TEST_INSTALL, TEST_SDIST = None, None
def setup():
"""
- Performs setup our tests will need. This mostly just needs disk iops so it
- can happen asynchronously with other tests.
+ Performs our tests asynchronously. They take a while due to iops.
"""
- global SETUP_THREAD
+ global TEST_INSTALL, TEST_SDIST
- def _setup():
- global INSTALL_FAILURE, INSTALL_PATH, SDIST_FAILURE
+ TEST_INSTALL = stem.util.test_tools.AsyncTestResult(_test_install)
+ TEST_SDIST = stem.util.test_tools.AsyncTestResult(_test_sdist)
+
+def _test_install():
+ try:
try:
stem.util.system.call('%s setup.py install --prefix %s' % (PYTHON_EXE, BASE_INSTALL_PATH), timeout = 60, cwd = test.STEM_BASE)
stem.util.system.call('%s setup.py clean --all' % PYTHON_EXE, timeout = 60, cwd = test.STEM_BASE) # tidy up the build directory
site_packages_paths = glob.glob('%s/lib*/*/site-packages' % BASE_INSTALL_PATH)
+ except Exception as exc:
+ raise AssertionError("Unable to install with 'python setup.py install': %s" % exc)
- if len(site_packages_paths) != 1:
- raise AssertionError('We should only have a single site-packages directory, but instead had: %s' % site_packages_paths)
+ if len(site_packages_paths) != 1:
+ raise AssertionError('We should only have a single site-packages directory, but instead had: %s' % site_packages_paths)
- INSTALL_PATH = site_packages_paths[0]
- except Exception as exc:
- INSTALL_FAILURE = AssertionError("Unable to install with 'python setup.py install': %s" % exc)
+ install_path = site_packages_paths[0]
+ version_output = stem.util.system.call([PYTHON_EXE, '-c', "import sys;sys.path.insert(0, '%s');import stem;print(stem.__version__)" % install_path])[0]
- if not os.path.exists(DIST_PATH):
- try:
- stem.util.system.call('%s setup.py sdist' % PYTHON_EXE, timeout = 60, cwd = test.STEM_BASE)
- except Exception as exc:
- SDIST_FAILURE = exc
- else:
- SDIST_FAILURE = AssertionError("%s already exists, maybe you manually ran 'python setup.py sdist'?" % DIST_PATH)
+ if stem.__version__ != version_output:
+ raise AssertionError('We expected the installed version to be %s but was %s' % (stem.__version__, version_output))
- if SETUP_THREAD is None:
- SETUP_THREAD = threading.Thread(target = _setup)
- SETUP_THREAD.start()
+ _assert_has_all_files(install_path)
+ finally:
+ if os.path.exists(BASE_INSTALL_PATH):
+ shutil.rmtree(BASE_INSTALL_PATH)
- return SETUP_THREAD
+def _test_sdist():
+ TEST_INSTALL.join() # we need to run these tests serially
+ git_dir = os.path.join(test.STEM_BASE, '.git')
-def clean():
- if os.path.exists(BASE_INSTALL_PATH):
- shutil.rmtree(BASE_INSTALL_PATH)
+ if not stem.util.system.is_available('git'):
+ raise stem.util.test_tools.SkipTest('(git unavailable)')
+ elif not os.path.exists(git_dir):
+ raise stem.util.test_tools.SkipTest('(not a git checkout)')
if os.path.exists(DIST_PATH):
- shutil.rmtree(DIST_PATH)
+ raise AssertionError("%s already exists, maybe you manually ran 'python setup.py sdist'?" % DIST_PATH)
+
+ try:
+ try:
+ stem.util.system.call('%s setup.py sdist' % PYTHON_EXE, timeout = 60, cwd = test.STEM_BASE)
+ except Exception as exc:
+ raise AssertionError("Unable to run 'python setup.py sdist': %s" % exc)
+
+ git_contents = [line.split()[-1] for line in stem.util.system.call('git --git-dir=%s ls-tree --full-tree -r HEAD' % git_dir)]
+
+ # tarball has a prefix 'stem-[verion]' directory so stipping that out
+
+ dist_tar = tarfile.open(os.path.join(DIST_PATH, 'stem-dry-run-%s.tar.gz' % stem.__version__))
+ tar_contents = ['/'.join(info.name.split('/')[1:]) for info in dist_tar.getmembers() if info.isfile()]
+
+ issues = []
+
+ for path in git_contents:
+ if path not in tar_contents and path not in ['.gitignore']:
+ issues.append(' * %s is missing from our release tarball' % path)
+
+ for path in tar_contents:
+ if path not in git_contents and path not in ['MANIFEST.in', 'PKG-INFO']:
+ issues.append(" * %s isn't expected in our release tarball" % path)
+
+ if issues:
+ raise AssertionError(INSTALL_MISMATCH_MSG + '\n'.join(issues))
+ finally:
+ if os.path.exists(DIST_PATH):
+ shutil.rmtree(DIST_PATH)
def _assert_has_all_files(path):
@@ -102,23 +131,14 @@ def _assert_has_all_files(path):
class TestInstallation(unittest.TestCase):
- @test.require.only_run_once
def test_install(self):
"""
Installs with 'python setup.py install' and checks we can use what we
install.
"""
- if not INSTALL_PATH:
- setup().join()
+ TEST_INSTALL.result(self)
- if INSTALL_FAILURE:
- raise INSTALL_FAILURE
-
- self.assertEqual(stem.__version__, stem.util.system.call([PYTHON_EXE, '-c', "import sys;sys.path.insert(0, '%s');import stem;print(stem.__version__)" % INSTALL_PATH])[0])
- _assert_has_all_files(INSTALL_PATH)
-
- @test.require.only_run_once
def test_sdist(self):
"""
Creates a source distribution tarball with 'python setup.py sdist' and
@@ -126,36 +146,4 @@ class TestInstallation(unittest.TestCase):
meant to test that our MANIFEST.in is up to date.
"""
- git_dir = os.path.join(test.STEM_BASE, '.git')
-
- if not stem.util.system.is_available('git'):
- self.skipTest('(git unavailable)')
- return
- elif not os.path.exists(git_dir):
- self.skipTest('(not a git checkout)')
- return
-
- setup().join()
-
- if SDIST_FAILURE:
- raise SDIST_FAILURE
-
- git_contents = [line.split()[-1] for line in stem.util.system.call('git --git-dir=%s ls-tree --full-tree -r HEAD' % git_dir)]
-
- # tarball has a prefix 'stem-[verion]' directory so stipping that out
-
- dist_tar = tarfile.open(os.path.join(DIST_PATH, 'stem-dry-run-%s.tar.gz' % stem.__version__))
- tar_contents = ['/'.join(info.name.split('/')[1:]) for info in dist_tar.getmembers() if info.isfile()]
-
- issues = []
-
- for path in git_contents:
- if path not in tar_contents and path not in ['.gitignore']:
- issues.append(' * %s is missing from our release tarball' % path)
-
- for path in tar_contents:
- if path not in git_contents and path not in ['MANIFEST.in', 'PKG-INFO']:
- issues.append(" * %s isn't expected in our release tarball" % path)
-
- if issues:
- self.fail(INSTALL_MISMATCH_MSG + '\n'.join(issues))
+ TEST_SDIST.result(self)
More information about the tor-commits
mailing list