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
|
#!/usr/bin/env python3
# Don't run tests from the root repo dir.
# We want to ensure we're importing from the installed
# binary package not from the CWD.
import argparse
import os
from contextlib import contextmanager
from subprocess import check_call
_dname = os.path.dirname
REPO_ROOT = _dname(_dname(_dname(os.path.abspath(__file__))))
@contextmanager
def cd(path):
"""Change directory while inside context manager."""
cwd = os.getcwd()
try:
os.chdir(path)
yield
finally:
os.chdir(cwd)
def run(command, allow_repo_root_on_path=False):
env = os.environ.copy()
if not allow_repo_root_on_path:
env['TESTS_REMOVE_REPO_ROOT_FROM_PATH'] = 'true'
return check_call(command, shell=True, env=env)
def process_args(args):
runner = args.test_runner
test_args = ""
if args.ignore:
test_args += " ".join(f"--ignore {ignore}" for ignore in args.ignore)
test_args += " "
if args.with_cov:
test_args += (
# Even though botocore and s3transfer reside in the awscli package,
# they are often imported via their top-level import alias in the
# codebase. Explicitly including them in --cov args ensures we
# include usage of these aliases for coverage purposes.
f"--cov=awscli --cov=botocore --cov=s3transfer "
f"--cov-config={os.path.join(REPO_ROOT, '.coveragerc')} "
f"--cov-report xml "
)
if args.junit_xml_path:
test_args += f'--junit-xml={args.junit_xml_path} '
if args.markers:
test_args += f'-m {args.markers} '
test_args += '--numprocesses=auto --dist=loadfile --maxprocesses=4 '
dirs = " ".join(args.test_dirs)
return runner, test_args, dirs
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"test_dirs",
default=["unit/", "functional/"],
nargs="*",
help="One or more directories containing tests.",
)
parser.add_argument(
"-r",
"--test-runner",
default="pytest",
help="Test runner to execute tests. Defaults to pytest.",
)
parser.add_argument(
"-c",
"--with-cov",
default=False,
action="store_true",
help="Run default test-runner with code coverage enabled.",
)
parser.add_argument(
"--allow-repo-root-on-path",
default=False,
action="store_true",
help=(
"Do not remove the repository root from the Python path when "
"running tests. This allows you to run the tests against the "
"current repository without have to install the package as a "
"distribution."
),
)
parser.add_argument(
"--ignore",
nargs='+',
default=[],
help=("Ignore a test subdirectory. Can be specified multiple times."),
)
parser.add_argument(
"--tests-path",
default=None,
type=os.path.abspath,
help=("Optional path to an alternate test directory to use."),
)
parser.add_argument(
"--junit-xml-path",
default=None,
type=os.path.abspath,
help="Optional path to output a JUnit XML result file to.",
)
parser.add_argument(
"-m",
"--markers",
default=None,
help="Run all tests decorated with the specified marker expression.",
)
raw_args = parser.parse_args()
test_runner, test_args, test_dirs = process_args(raw_args)
tests_path = raw_args.tests_path
if tests_path is None:
tests_path = os.path.join(REPO_ROOT, "tests")
cmd = f"{test_runner} {test_args}{test_dirs}"
print(f"CDing to {tests_path}")
print(f"Running {cmd}...")
with cd(tests_path):
run(cmd, allow_repo_root_on_path=raw_args.allow_repo_root_on_path)
|