forked from Minki/linux
kunit: add run_checks.py script to validate kunit changes
This formalizes the checks KUnit maintainers have been running (or in other cases: forgetting to run). This script also runs them all in parallel to minimize friction (pytype can be fairly slow, but not slower than running kunit.py). Example output: $ ./tools/testing/kunit/run_checks.py Waiting on 4 checks (kunit_tool_test.py, kunit smoke test, pytype, mypy)... kunit_tool_test.py: PASSED mypy: PASSED pytype: PASSED kunit smoke test: PASSED On failure or timeout (5 minutes), it'll dump out the stdout/stderr. E.g. adding in a type-checking error: mypy: FAILED > kunit.py:54: error: Name 'nonexistent_function' is not defined > Found 1 error in 1 file (checked 8 source files) mypy and pytype are two Python type-checkers and must be installed. This file treats them as optional and will mark them as SKIPPED if not installed. This tool also runs `kunit.py run --kunitconfig=lib/kunit` to run KUnit's own KUnit tests and to verify KUnit kernel code and kunit.py play nicely together. It uses --build_dir=kunit_run_checks so as not to clobber the default build_dir, which helps make it faster by reducing the need to rebuild, esp. if you're been passing in --arch instead of using UML. Signed-off-by: Daniel Latypov <dlatypov@google.com> Reviewed-by: David Gow <davidgow@google.com> Reviewed-by: David Gow <davidgow@google.com> Reviewed-by: Brendan Higgins <brendanhiggins@google.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
This commit is contained in:
parent
58b391d746
commit
ee92ed3836
81
tools/testing/kunit/run_checks.py
Executable file
81
tools/testing/kunit/run_checks.py
Executable file
@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# This file runs some basic checks to verify kunit works.
|
||||
# It is only of interest if you're making changes to KUnit itself.
|
||||
#
|
||||
# Copyright (C) 2021, Google LLC.
|
||||
# Author: Daniel Latypov <dlatypov@google.com.com>
|
||||
|
||||
from concurrent import futures
|
||||
import datetime
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
from typing import Dict, List, Sequence, Tuple
|
||||
|
||||
ABS_TOOL_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||
TIMEOUT = datetime.timedelta(minutes=5).total_seconds()
|
||||
|
||||
commands: Dict[str, Sequence[str]] = {
|
||||
'kunit_tool_test.py': ['./kunit_tool_test.py'],
|
||||
'kunit smoke test': ['./kunit.py', 'run', '--kunitconfig=lib/kunit', '--build_dir=kunit_run_checks'],
|
||||
'pytype': ['/bin/sh', '-c', 'pytype *.py'],
|
||||
'mypy': ['/bin/sh', '-c', 'mypy *.py'],
|
||||
}
|
||||
|
||||
# The user might not have mypy or pytype installed, skip them if so.
|
||||
# Note: you can install both via `$ pip install mypy pytype`
|
||||
necessary_deps : Dict[str, str] = {
|
||||
'pytype': 'pytype',
|
||||
'mypy': 'mypy',
|
||||
}
|
||||
|
||||
def main(argv: Sequence[str]) -> None:
|
||||
if argv:
|
||||
raise RuntimeError('This script takes no arguments')
|
||||
|
||||
future_to_name: Dict[futures.Future, str] = {}
|
||||
executor = futures.ThreadPoolExecutor(max_workers=len(commands))
|
||||
for name, argv in commands.items():
|
||||
if name in necessary_deps and shutil.which(necessary_deps[name]) is None:
|
||||
print(f'{name}: SKIPPED, {necessary_deps[name]} not in $PATH')
|
||||
continue
|
||||
f = executor.submit(run_cmd, argv)
|
||||
future_to_name[f] = name
|
||||
|
||||
has_failures = False
|
||||
print(f'Waiting on {len(future_to_name)} checks ({", ".join(future_to_name.values())})...')
|
||||
for f in futures.as_completed(future_to_name.keys()):
|
||||
name = future_to_name[f]
|
||||
ex = f.exception()
|
||||
if not ex:
|
||||
print(f'{name}: PASSED')
|
||||
continue
|
||||
|
||||
has_failures = True
|
||||
if isinstance(ex, subprocess.TimeoutExpired):
|
||||
print(f'{name}: TIMED OUT')
|
||||
elif isinstance(ex, subprocess.CalledProcessError):
|
||||
print(f'{name}: FAILED')
|
||||
else:
|
||||
print('{name}: unexpected exception: {ex}')
|
||||
continue
|
||||
|
||||
output = ex.output
|
||||
if output:
|
||||
print(textwrap.indent(output.decode(), '> '))
|
||||
executor.shutdown()
|
||||
|
||||
if has_failures:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def run_cmd(argv: Sequence[str]):
|
||||
subprocess.check_output(argv, stderr=subprocess.STDOUT, cwd=ABS_TOOL_PATH, timeout=TIMEOUT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
Loading…
Reference in New Issue
Block a user