deb-python-greenio/runtests.py

218 lines
6.5 KiB
Python

# Copied from Tulip codebase, covered by Apache 2.0 License
#
"""Run all unittests.
Usage:
python3 runtests.py [-v] [-q] [pattern] ...
Where:
-v: verbose
-q: quiet
pattern: optional regex patterns to match test ids (default all tests)
Note that the test id is the fully qualified name of the test,
including package, module, class and method,
e.g. 'tests.events_test.PolicyTests.testPolicy'.
runtests.py with --coverage argument is equivalent of:
$(COVERAGE) run --branch runtests.py -v
$(COVERAGE) html $(list of files)
$(COVERAGE) report -m $(list of files)
"""
# Originally written by Beech Horn (for NDB).
from __future__ import print_function
import argparse
import logging
import os
import re
import sys
import subprocess
import unittest
if sys.version_info >= (3, 3):
import importlib.machinery
else:
import imp
ARGS = argparse.ArgumentParser(description="Run all unittests.")
ARGS.add_argument(
'-v', action="store", dest='verbose',
nargs='?', const=1, type=int, default=0, help='verbose')
ARGS.add_argument(
'-x', action="store_true", dest='exclude', help='exclude tests')
ARGS.add_argument(
'-q', action="store_true", dest='quiet', help='quiet')
ARGS.add_argument(
'--tests', action="store", dest='testsdir', default='tests',
help='tests directory')
ARGS.add_argument(
'--coverage', action="store", dest='coverage', nargs='?', const='',
help='enable coverage report and provide python files directory')
ARGS.add_argument(
'pattern', action="store", nargs="*",
help='optional regex patterns to match test ids (default all tests)')
COV_ARGS = argparse.ArgumentParser(description="Run all unittests.")
COV_ARGS.add_argument(
'--coverage', action="store", dest='coverage', nargs='?', const='',
help='enable coverage report and provide python files directory')
if sys.version_info >= (3, 3):
def load_module(modname, sourcefile):
loader = importlib.machinery.SourceFileLoader(modname, sourcefile)
return loader.load_module()
else:
def load_module(modname, sourcefile):
return imp.load_source(modname, sourcefile)
def load_modules(basedir, suffix='.py'):
def list_dir(prefix, dir):
files = []
modpath = os.path.join(dir, '__init__.py')
if os.path.isfile(modpath):
mod = os.path.split(dir)[-1]
files.append(('{}{}'.format(prefix, mod), modpath))
prefix = '{}{}.'.format(prefix, mod)
for name in os.listdir(dir):
path = os.path.join(dir, name)
if os.path.isdir(path):
files.extend(list_dir('{}{}.'.format(prefix, name), path))
else:
if (name != '__init__.py' and
name.endswith(suffix) and
not name.startswith(('.', '_'))):
files.append(('{}{}'.format(prefix, name[:-3]), path))
return files
mods = []
for modname, sourcefile in list_dir('', basedir):
if modname == 'runtests':
continue
if (modname in ('test_tasks', 'test_asyncio_trollius')
and sys.version_info <= (3, 3)):
print("Skipping '{0}': need at least Python 3.3".format(modname),
file=sys.stderr)
continue
try:
mod = load_module(modname, sourcefile)
mods.append((mod, sourcefile))
except Exception as err:
print("Skipping '{}': {}".format(modname, err), file=sys.stderr)
return mods
def load_tests(testsdir, includes=(), excludes=()):
mods = [mod for mod, _ in load_modules(testsdir)]
loader = unittest.TestLoader()
suite = unittest.TestSuite()
for mod in mods:
for name in set(dir(mod)):
if name.endswith('Tests'):
test_module = getattr(mod, name)
tests = loader.loadTestsFromTestCase(test_module)
if includes:
tests = [test
for test in tests
if any(re.search(pat, test.id())
for pat in includes)]
if excludes:
tests = [test
for test in tests
if not any(re.search(pat, test.id())
for pat in excludes)]
suite.addTests(tests)
return suite
def runtests():
args = ARGS.parse_args()
testsdir = os.path.abspath(args.testsdir)
if not os.path.isdir(testsdir):
print("Tests directory is not found: {}\n".format(testsdir))
ARGS.print_help()
return
excludes = includes = []
if args.exclude:
excludes = args.pattern
else:
includes = args.pattern
v = 0 if args.quiet else args.verbose + 1
tests = load_tests(args.testsdir, includes, excludes)
logger = logging.getLogger()
if v == 0:
logger.setLevel(logging.CRITICAL)
elif v == 1:
logger.setLevel(logging.ERROR)
elif v == 2:
logger.setLevel(logging.WARNING)
elif v == 3:
logger.setLevel(logging.INFO)
elif v >= 4:
logger.setLevel(logging.DEBUG)
result = unittest.TextTestRunner(verbosity=v).run(tests)
sys.exit(not result.wasSuccessful())
def runcoverage(sdir, args):
"""
To install coverage3 for Python 3, you need:
- Distribute (http://packages.python.org/distribute/)
What worked for me:
- download http://python-distribute.org/distribute_setup.py
* curl -O http://python-distribute.org/distribute_setup.py
- python3 distribute_setup.py
- python3 -m easy_install coverage
"""
try:
import coverage
except ImportError:
print("Coverage package is not found.")
print(runcoverage.__doc__)
return
sdir = os.path.abspath(sdir)
if not os.path.isdir(sdir):
print("Python files directory is not found: {}\n".format(sdir))
ARGS.print_help()
return
mods = [source for _, source in load_modules(sdir)]
coverage = [sys.executable, '-m', 'coverage']
try:
subprocess.check_call(
coverage + ['run', '--branch', 'runtests.py'] + args)
except:
pass
else:
subprocess.check_call(coverage + ['html'] + mods)
subprocess.check_call(coverage + ['report'] + mods)
if __name__ == '__main__':
if '--coverage' in sys.argv:
cov_args, args = COV_ARGS.parse_known_args()
runcoverage(cov_args.coverage, args)
else:
runtests()