commit 382a4f5e54a26dc7a2179d17cb4129f68e3e650e Author: Isis Lovecruft isis@torproject.org Date: Thu Apr 16 04:23:24 2015 +0000
Rewrite `python setyp.py test` code to run Trial tests only. --- lib/bridgedb/parse/options.py | 27 ---------- lib/bridgedb/runner.py | 47 ---------------- setup.py | 119 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 109 insertions(+), 84 deletions(-)
diff --git a/lib/bridgedb/parse/options.py b/lib/bridgedb/parse/options.py index 2ed93d0..3979615 100644 --- a/lib/bridgedb/parse/options.py +++ b/lib/bridgedb/parse/options.py @@ -251,32 +251,6 @@ class BaseOptions(usage.Options): print(" self['rundir']=%s" % self['rundir'])
-class TestOptions(BaseOptions): - """Suboptions for running twisted.trial and unittest based tests.""" - - longdesc = textwrap.dedent("""BridgeDB testing commands. - See the `bridgedb mock` command for generating testing environments.""") - - optFlags = [['coverage', 'c', 'Generate coverage statistics']] - optParameters = [ - ['file', 'f', None, 'Run tests in specific file(s) (trial only)'], - ['unittests', 'u', False, 'Run unittests in bridgedb.Tests'], - ['trial', 't', True, 'Run twisted.trial tests in bridgedb.test']] - - completionData = usage.Completions( - mutuallyExclusive=[('unittests', 'coverage'), - ('unittests', 'file')], - optActions={'file': usage.CompleteFiles('lib/bridgedb/test/test_*.py', - repeat=True, - descr="test filename")}, - extraActions=[ - usage.Completer(descr="extra arguments to pass to trial")]) - - def parseArgs(self, *args): - """Parse any additional arguments after the options and flags.""" - self['test_args'] = args - - class MockOptions(BaseOptions): """Suboptions for creating necessary conditions for testing purposes."""
@@ -315,7 +289,6 @@ class MainOptions(BaseOptions): ['dump-bridges', 'd', 'Dump bridges by hashring assignment into files'], ['reload', 'R', 'Reload bridge descriptors into running servers']] subCommands = [ - ['test', None, TestOptions, "Run twisted.trial tests or unittests"], ['mock', None, MockOptions, "Generate a testing environment"], ['SIGHUP', None, SIGHUPOptions, "Reload bridge descriptors into running servers"], diff --git a/lib/bridgedb/runner.py b/lib/bridgedb/runner.py index 7be7700..6ac069f 100644 --- a/lib/bridgedb/runner.py +++ b/lib/bridgedb/runner.py @@ -94,53 +94,6 @@ def generateDescriptors(count=None, rundir=None): del subprocess return statuscode
-def runTrial(options): - """Run Twisted trial based unittests, optionally with coverage. - - :type options: :class:`~bridgedb.opt.TestOptions` - :param options: Parsed options for controlling the twisted.trial test - run. All unrecognised arguments after the known options will be passed - along to trial. - """ - from twisted.scripts import trial - - # Insert 'trial' as the first system cmdline argument: - sys.argv = ['trial'] - - if options['coverage']: - try: - from coverage import coverage - except ImportError as ie: - print(ie.message) - else: - cov = coverage() - cov.start() - sys.argv.append('--coverage') - sys.argv.append('--reporter=bwverbose') - - # Pass all arguments along to its options parser: - if 'test_args' in options: - for arg in options['test_args']: - sys.argv.append(arg) - # Tell trial to test the bridgedb package: - sys.argv.append('bridgedb.test') - trial.run() - - if options['coverage']: - cov.stop() - cov.html_report('_trial_temp/coverage/') - -def runTests(options): - """Run unittest based tests. - - :type options: :class:`~bridgedb.opt.TestOptions` - :param options: Parsed options for controlling the twisted.trial test - run. All unrecognised arguments after the known options will be passed - along to trial. - """ - testModule = __import__('bridgedb.Tests', globals(), '', []) - testModule.Tests.main() - def doDumpBridges(config): """Dump bridges by assignment to a file.
diff --git a/setup.py b/setup.py index 9402071..032aa10 100644 --- a/setup.py +++ b/setup.py @@ -74,6 +74,7 @@ install_i18n = os.path.join('bridgedb', 'i18n') # Directory to install docs, license, and other text resources into: install_docs = os.path.join('share', 'doc', 'bridgedb')
+ def get_cmdclass(): """Get our cmdclass dictionary for use in setuptool.setup().
@@ -81,7 +82,7 @@ def get_cmdclass(): to add our own classes to the cmdclass dictionary, and then update that dictionary with the one returned from versioneer.get_cmdclass(). """ - cmdclass = {'test': runTests, + cmdclass = {'test': Trial, 'compile_catalog': compile_catalog, 'extract_messages': extract_messages, 'init_catalog': init_catalog, @@ -238,15 +239,69 @@ def get_data_files(filesonly=False): return data_files
-class runTests(setuptools.Command): - # Based on setup.py from mixminion, which is based on setup.py - # from Zooko's pyutil package, which is in turn based on - # http://mail.python.org/pipermail/distutils-sig/2002-January/002714.html - description = "Run unit tests" - user_options = [] +class Trial(setuptools.Command): + """Twisted Trial setuptools command. + + Based on the setuptools Trial command in Zooko's Tahoe-LAFS, as well as + https://github.com/simplegeo/setuptools-trial/ (which is also based on the + Tahoe-LAFS code). + + Pieces of the original implementation of this 'test' command (that is, for + the original pyunit-based BridgeDB tests which, a long time ago, in a + galaxy far far away, lived in bridgedb.Tests) were based on setup.py from + Nick Mathewson's mixminion, which was based on the setup.py from Zooko's + pyutil package, which was in turn based on + http://mail.python.org/pipermail/distutils-sig/2002-January/002714.html. + + Crusty, old-ass Python, like hella wut. + """ + description = "Run Twisted Trial-based tests." + user_options = [ + ('debug', 'b', ("Run tests in a debugger. If that debugger is pdb, will " + "load '.pdbrc' from current directory if it exists.")), + ('debug-stacktraces', 'B', "Report Deferred creation and callback stack traces"), + ('debugger=', None, ("The fully qualified name of a debugger to use if " + "--debug is passed (default: pdb)")), + ('disablegc', None, "Disable the garbage collector"), + ('force-gc', None, "Have Trial run gc.collect() before and after each test case"), + ('jobs=', 'j', "Number of local workers to run, a strictly positive integer"), + ('profile', None, "Run tests under the Python profiler"), + ('random=', 'Z', "Run tests in random order using the specified seed"), + ('reactor=', 'r', "Which reactor to use"), + ('reporter=', None, "Customize Trial's output with a reporter plugin"), + ('rterrors', 'e', "Realtime errors: print out tracebacks as soon as they occur"), + ('spew', None, "Print an insanely verbose log of everything that happens"), + ('testmodule=', None, "Filename to grep for test cases (-*- test-case-name)"), + ('tbformat=', None, ("Specify the format to display tracebacks with. Valid " + "formats are 'plain', 'emacs', and 'cgitb' which uses " + "the nicely verbose stdlib cgitb.text function")), + ('unclean-warnings', None, "Turn dirty reactor errors into warnings"), + ('until-failure', 'u', "Repeat a test (specified by -s) until it fails."), + ('without-module=', None, ("Fake the lack of the specified modules, separated " + "with commas")), + ] + boolean_options = ['debug', 'debug-stacktraces', 'disablegc', 'force-gc', + 'profile', 'rterrors', 'spew', 'unclean-warnings', + 'until-failure']
def initialize_options(self): - pass + self.debug = None + self.debug_stacktraces = None + self.debugger = None + self.disablegc = None + self.force_gc = None + self.jobs = None + self.profile = None + self.random = None + self.reactor = None + self.reporter = None + self.rterrors = None + self.spew = None + self.testmodule = None + self.tbformat = None + self.unclean_warnings = None + self.until_failure = None + self.without_module = None
def finalize_options(self): build = self.get_finalized_command('build') @@ -257,11 +312,55 @@ class runTests(setuptools.Command): self.run_command('build') old_path = sys.path[:] sys.path[0:0] = [self.build_purelib, self.build_platlib] + + result = 1 try: - testmod = __import__("bridgedb.Tests", globals(), "", []) - testmod.Tests.main() + result = self.run_tests() finally: sys.path = old_path + raise SystemExit(result) + + def run_tests(self): + # We do the import from Twisted inside the function instead of the top + # of the file because since Twisted is a setup_requires, we can't + # assume that Twisted will be installed on the user's system prior, so + # if we don't do the import here, then importing from this plugin will + # fail. + from twisted.scripts import trial + + if not self.testmodule: + self.testmodule = "bridgedb.test" + + # Handle parsing the trial options passed through the setuptools + # trial command. + cmd_options = [] + for opt in self.boolean_options: + if getattr(self, opt.replace('-', '_'), None): + cmd_options.append('--%s' % opt) + + for opt in ('debugger', 'jobs', 'random', 'reactor', 'reporter', + 'testmodule', 'tbformat', 'without-module'): + value = getattr(self, opt.replace('-', '_'), None) + if value is not None: + cmd_options.extend(['--%s' % opt, value]) + + config = trial.Options() + config.parseOptions(cmd_options) + config['tests'] = [self.testmodule,] + + trial._initialDebugSetup(config) + trialRunner = trial._makeRunner(config) + suite = trial._getSuite(config) + + # run the tests + if self.until_failure: + test_result = trialRunner.runUntilFailure(suite) + else: + test_result = trialRunner.run(suite) + + if test_result.wasSuccessful(): + return 0 # success + return 1 # failure
# If there is an environment variable BRIDGEDB_INSTALL_DEPENDENCIES=0, it will