Message ID | 20211103042228.586967-1-dlatypov@google.com (mailing list archive) |
---|---|
State | Accepted |
Commit | ee92ed38364e7073bb741577d7b243b232442014 |
Delegated to: | Brendan Higgins |
Headers | show |
Series | [v2] kunit: add run_checks.py script to validate kunit changes | expand |
On Wed, Nov 3, 2021 at 12:22 PM Daniel Latypov <dlatypov@google.com> wrote: > > 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> > --- Works a treat, thanks. This is still Reviewed-by: David Gow <davidgow@google.com> Cheers, -- David
On Wed, Nov 3, 2021 at 12:22 AM Daniel Latypov <dlatypov@google.com> wrote: > > 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: Brendan Higgins <brendanhiggins@google.com>
diff --git a/tools/testing/kunit/run_checks.py b/tools/testing/kunit/run_checks.py new file mode 100755 index 000000000000..4f32133ed77c --- /dev/null +++ b/tools/testing/kunit/run_checks.py @@ -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:])