summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsis Lovecruft <isis@torproject.org>2013-02-18 17:46:52 +0000
committerIsis Lovecruft <isis@torproject.org>2013-02-18 17:46:52 +0000
commit58e1eeffb7324476443d7f4e7d87591854498786 (patch)
tree0dfa9b4795daf74de68753779321f71f22874da7
parent8f7ebd8e388a96dd825ee3cc7a72850b51dbca8b (diff)
Add runner class for handling running unittests specified on the commandline
through the options parser, discovering unittest cases within whatever file/module/class/method/package is passed to the runner, and calling twisted.trial on the unittest cases found.
-rw-r--r--src/leap/mx/runner.py121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/leap/mx/runner.py b/src/leap/mx/runner.py
index daf956e..84db927 100644
--- a/src/leap/mx/runner.py
+++ b/src/leap/mx/runner.py
@@ -13,6 +13,12 @@ from os import path as ospath
import re
+from twisted.internet import defer
+from twisted.trial import runner, reporter, unittest
+from twisted.python import usage
+
+from leap.mx.util import log, version
+
class CheckRequirements(ImportError):
"""
@@ -80,4 +86,119 @@ class CheckRequirements(ImportError):
package_name = matched.group()
package_version = shortened.split(package_name, 1)[1]
dependencies.append((package_name, package_version))
+
return dependencies
+
+
+class TestRunner(runner.TrialRunner):
+ """
+ This class handles loading unittests from a directory, module, file,
+ class, method, or anything really, and running any unittests found with
+ twisted.trial.
+
+ @param options: A subclass of :class:twisted.python.usage.Options.
+ @param test: (optional) The thing to load tests from.
+ """
+ def __init__(self, options, test_location=None, *args, **kwargs):
+ """
+ Create a runner for handling unittest runs.
+
+ @param options: An the dictionary :ivar:`opts` from the parsed options
+ of a :class:`twisted.python.usage.Options`.
+ @param test_location: The path to a directory or filename containing
+ unittests to run, or the path to a file prefixed with 'test_', or
+ a subclass of :class:`twisted.trial.unittest.TestCase`, or a
+ function/method prefixed with 'test_'.
+ """
+ log.debug("Creating TestRunner: %s" % self.__repr__())
+
+ if isinstance(options, dict):
+ log.debug("TestRunner loaded options class")
+ self.options = options
+ else:
+ self.options = None
+ raise usage.UsageError(
+ "TestRunner expected t.p.u.Options subclass, got %s"
+ % options)
+
+ self.loader = runner.TestLoader()
+ self._parse_options()
+
+ self.test_location = test_location
+ self.tests_loaded = self.loadUnittests()
+ self.test_list = self.runUnittests()
+ self.results = defer.DeferredList(self.test_list)
+
+ def _parse_options(self):
+ """
+ Parse the :class:`twisted.python.usage.Options` for flags pertaining
+ to running unittests.
+ """
+ if not self.options is None:
+ if self.options['debug']:
+ log.debug("Enabled debugging on test runner.")
+ self.DEBUG = True
+ if self.options['force-gc']:
+ ## not sure if we need to call it or assign it...
+ log.debug("Forcing garbage collection between unittest runs.")
+ self.loader.forceGarbageCollection(True)
+ if self.options['all-tests']:
+ repo = version.getRepoDir()
+ test_directory = ospath.join(repo, 'src/leap/mx/tests')
+ self.test_location = test_directory
+ else:
+ log.warn("TestRunner: got None for t.p.u.Options class!")
+
+ def loadUnittests(self):
+ """
+ Load all tests. Tests may be a module or directory, the path to a
+ filename in the form 'test_*.py", a subclass of
+ :class:`twisted.trial.unittest.TestCase` or
+ :class:`twisted.trial.unittest.TestSuite`, or a any function/method
+ which is prefixed with 'test_'.
+
+ @returns: An instance of :class:`twisted.trial.unittest.TestCase` or
+ :class:`twisted.trial.unittest.TestSuite`.
+ """
+ log.msg("Attempting to load unittests...")
+
+ tests_loaded = None
+
+ if self.test_location:
+ log.msg("Loading unittests from %s" % self.test_location)
+ if ospath.isdir(self.test_location):
+ log.msg("Found test directory: %s" % test)
+ tests_loaded = self.loader.loadAnything(self.test_location,
+ recurse=True)
+ else:
+ log.msg("Found test file: %s" % self.test_location)
+ tests_loaded = self.loader.loadAnything(self.test_location)
+ else:
+ log.warn("Test location %s seems to be None!" % self.test_location)
+
+ return tests_loaded
+
+ def runUnittests(self):
+ """xxx fill me in"""
+ results = []
+ if not self.tests_loaded is None:
+ if isinstance(self.tests_loaded, unittest.TestCase):
+ log.msg("Test case loaded.")
+ classes = self.loader.findTestClasses(self.tests_loaded)
+ for cls in classes:
+ test_instance = cls()
+ test_instance.setUp() ## xxx does TestRunner handle this?
+ d = defer.maybeDeferred(test_instance.run())
+ self.results.append(d)
+ elif isinstance(self.tests, unittest.TestSuite):
+ classes = None ## xxx call each TestCase in TestSuite
+ test_suite = self.tests()
+ self.results.append(test_suite.visit())
+ log.msg("Test suite loaded: %d tests to run"
+ % test_suite.countTestCases)
+ return results
+
+ #return runner.TrialRunner(reporter.TreeReporter, mode=mode,
+ # profile=profile, logfile=logfile,
+ # tbformat, rterrors, unclean_warnings,
+ # temp-directory, force-gc)