debugpy/tests/__main__.py
Derek Keeler e80a669624
Update for VSTS-based CI process (#431)
* Add flake8 configuration files
- .flake8.ci: addendum config for CI to make use of only.
* Add build badge for CI in VSTS
* Enable JUnit style test file output.
- convert_args return value simplified
- allow original style of unittest reporting as well
- remove unnecessary flags from junit xmlrunner
* Use argparse to collect runtime configuration of tests module
2018-06-21 17:09:53 -07:00

222 lines
6.2 KiB
Python

from __future__ import absolute_import
import argparse
import os
import os.path
import subprocess
import sys
import unittest
from xmlrunner import XMLTestRunner
from . import TEST_ROOT, PROJECT_ROOT, VENDORED_ROOTS
def parse_cmdline(argv=None):
"""Obtain command line arguments and setup the test run accordingly."""
parser = argparse.ArgumentParser(
description="Run tests associated to the PTVSD project.",
prog="tests",
usage="python -m %(prog)s OPTS",
add_help=False
)
# allow_abbrev was added in 3.5
if sys.version_info >= (3, 5):
parser.allow_abbrev = False
parser.add_argument(
"-c",
"--coverage",
help="Generate code coverage report.",
action="store_true"
)
parser.add_argument(
"--full",
help="Do full suite of tests (disables prior --quick options).",
action="store_false",
dest="quick"
)
parser.add_argument(
"-j",
"--junit-xml",
help="Output report is generated to JUnit-style XML file specified.",
type=str
)
parser.add_argument(
"-l",
"--lint",
help="Run and report on Linter compliance.",
action="store_true"
)
parser.add_argument(
"-L",
"--lint-only",
help="Run and report on Linter compliance only, do not perform tests.",
action="store_true"
)
parser.add_argument(
"-n",
"--network",
help="Perform tests taht require network connectivity.",
action="store_true",
dest="network"
)
parser.add_argument(
"--no-network",
help="Do not perform tests that require network connectivity.",
action="store_false",
dest="network"
)
parser.add_argument(
"-q",
"--quick",
help="Only do the tests under test/ptvsd.",
action="store_true",
dest="quick"
)
parser.add_argument(
"--quick-py2",
help=("Only do the tests under test/ptvsd, that are compatible "
"with Python 2.x."),
action="store_true"
)
# these destinations have 2 switches, be explicit about the default
parser.set_defaults(quick=False)
parser.set_defaults(network=True)
config, passthrough_args = parser.parse_known_args(argv)
return config, passthrough_args
def convert_argv(argv=None):
"""Convert commandling args into unittest/linter/coverage input."""
config, passthru = parse_cmdline(argv)
modules = set()
args = []
help = False
for arg in passthru:
# Unittest's main has only flags and positional args.
# So we don't worry about options with values.
if not arg.startswith('-'):
# It must be the name of a test, case, module, or file.
# We convert filenames to module names. For filenames
# we support specifying a test name by appending it to
# the filename with a ":" in between.
mod, _, test = arg.partition(':')
if mod.endswith(os.sep):
mod = mod.rsplit(os.sep, 1)[0]
mod = mod.rsplit('.py', 1)[0]
mod = mod.replace(os.sep, '.')
arg = mod if not test else mod + '.' + test
modules.add(mod)
elif arg in ('-h', '--help'):
help = True
args.append(arg)
env = {}
if config.network:
env['HAS_NETWORK'] = '1'
# We make the "executable" a single arg because unittest.main()
# doesn't work if we split it into 3 parts.
cmd = [sys.executable + ' -m unittest']
if not modules and not help:
# Do discovery.
quickroot = os.path.join(TEST_ROOT, 'ptvsd')
if config.quick:
start = quickroot
elif config.quick_py2 and sys.version_info[0] == 2:
start = quickroot
else:
start = PROJECT_ROOT
cmd += [
'discover',
'--top-level-directory', PROJECT_ROOT,
'--start-directory', start,
]
args = cmd + args
return config, args, env
def fix_sys_path():
pos = 1 if (not sys.path[0] or sys.path[0] == '.') else 0
for projectroot in VENDORED_ROOTS:
sys.path.insert(pos, projectroot)
def check_lint():
print('linting...')
args = [
sys.executable,
'-m', 'flake8',
'--config', '.flake8',
PROJECT_ROOT,
]
rc = subprocess.call(args)
if rc != 0:
print('...linting failed!')
sys.exit(rc)
print('...done')
def run_tests(argv, env, coverage, junit_xml):
print('running tests...')
if coverage:
omissions = [os.path.join(root, '*') for root in VENDORED_ROOTS]
# TODO: Drop the explicit pydevd omit once we move the subtree.
omissions.append(os.path.join('ptvsd', 'pydevd', '*'))
ver = 3 if sys.version_info < (3,) else 2
omissions.append(os.path.join('ptvsd', 'reraise{}.py'.format(ver)))
args = [
sys.executable,
'-m', 'coverage',
'run',
# We use --source instead of "--include ptvsd/*".
'--source', 'ptvsd',
'--omit', ','.join(omissions),
'-m', 'unittest',
] + argv[1:]
assert 'PYTHONPATH' not in env
env['PYTHONPATH'] = os.pathsep.join(VENDORED_ROOTS)
rc = subprocess.call(args, env=env)
if rc != 0:
print('...coverage failed!')
sys.exit(rc)
print('...done')
elif junit_xml:
os.environ.update(env)
with open(junit_xml, 'wb') as output:
unittest.main(
testRunner=XMLTestRunner(output=output),
module=None,
argv=argv
)
else:
os.environ.update(env)
unittest.main(module=None, argv=argv)
if __name__ == '__main__':
config, argv, env = convert_argv()
fix_sys_path()
if config.lint or config.lint_only:
check_lint()
if not config.lint_only:
if '--start-directory' in argv:
start = argv[argv.index('--start-directory') + 1]
print('(will look for tests under {})'.format(start))
run_tests(
argv,
env,
config.coverage,
config.junit_xml
)