1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
# 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
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()
|