From 60684c2bd35064043360e6f716d1b7c20e967b7d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 27 Feb 2023 12:12:45 +0100 Subject: [PATCH 01/14] kunit: tool: Add support for m68k under QEMU Add basic support to run m68k under QEMU via kunit_tool. Signed-off-by: Geert Uytterhoeven Reviewed-by: David Gow Signed-off-by: Shuah Khan --- tools/testing/kunit/qemu_configs/m68k.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tools/testing/kunit/qemu_configs/m68k.py diff --git a/tools/testing/kunit/qemu_configs/m68k.py b/tools/testing/kunit/qemu_configs/m68k.py new file mode 100644 index 000000000000..287fc386f8a7 --- /dev/null +++ b/tools/testing/kunit/qemu_configs/m68k.py @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +from ..qemu_config import QemuArchParams + +QEMU_ARCH = QemuArchParams(linux_arch='m68k', + kconfig=''' +CONFIG_VIRT=y''', + qemu_arch='m68k', + kernel_path='vmlinux', + kernel_command_line='console=hvc0', + extra_qemu_params=['-machine', 'virt']) From 887d85a0736ff346cbfe5efaf51cf20c7ca195a3 Mon Sep 17 00:00:00 2001 From: Rae Moar Date: Wed, 8 Mar 2023 20:39:50 +0000 Subject: [PATCH 02/14] kunit: fix bug in debugfs logs of parameterized tests Fix bug in debugfs logs that causes individual parameterized results to not appear because the log is reinitialized (cleared) when each parameter is run. Ensure these results appear in the debugfs logs, increase log size to allow for the size of parameterized results. As a result, append lines to the log directly rather than using an intermediate variable that can cause stack size warnings due to the increased log size. Here is the debugfs log of ext4_inode_test which uses parameterized tests before the fix: KTAP version 1 # Subtest: ext4_inode_test 1..1 # Totals: pass:16 fail:0 skip:0 total:16 ok 1 ext4_inode_test As you can see, this log does not include any of the individual parametrized results. After (in combination with the next two fixes to remove extra empty line and ensure KTAP valid format): KTAP version 1 1..1 KTAP version 1 # Subtest: ext4_inode_test 1..1 KTAP version 1 # Subtest: inode_test_xtimestamp_decoding ok 1 1901-12-13 Lower bound of 32bit < 0 timestamp, no extra bits ... (the rest of the individual parameterized tests) ok 16 2446-05-10 Upper bound of 32bit >=0 timestamp. All extra # inode_test_xtimestamp_decoding: pass:16 fail:0 skip:0 total:16 ok 1 inode_test_xtimestamp_decoding # Totals: pass:16 fail:0 skip:0 total:16 ok 1 ext4_inode_test Signed-off-by: Rae Moar Reviewed-by: David Gow Signed-off-by: Shuah Khan --- include/kunit/test.h | 2 +- lib/kunit/test.c | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/kunit/test.h b/include/kunit/test.h index 08d3559dd703..0668d29f3453 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -34,7 +34,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running); struct kunit; /* Size of log associated with test. */ -#define KUNIT_LOG_SIZE 512 +#define KUNIT_LOG_SIZE 1500 /* Maximum size of parameter description string. */ #define KUNIT_PARAM_DESC_SIZE 128 diff --git a/lib/kunit/test.c b/lib/kunit/test.c index c9e15bb60058..c4d6304edd61 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -114,22 +114,27 @@ static void kunit_print_test_stats(struct kunit *test, */ void kunit_log_append(char *log, const char *fmt, ...) { - char line[KUNIT_LOG_SIZE]; va_list args; - int len_left; + int len, log_len, len_left; if (!log) return; - len_left = KUNIT_LOG_SIZE - strlen(log) - 1; + log_len = strlen(log); + len_left = KUNIT_LOG_SIZE - log_len - 1; if (len_left <= 0) return; + /* Evaluate length of line to add to log */ va_start(args, fmt); - vsnprintf(line, sizeof(line), fmt, args); + len = vsnprintf(NULL, 0, fmt, args) + 1; + va_end(args); + + /* Print formatted line to the log */ + va_start(args, fmt); + vsnprintf(log + log_len, min(len, len_left), fmt, args); va_end(args); - strncat(log, line, len_left); } EXPORT_SYMBOL_GPL(kunit_log_append); @@ -437,7 +442,6 @@ static void kunit_run_case_catch_errors(struct kunit_suite *suite, struct kunit_try_catch_context context; struct kunit_try_catch *try_catch; - kunit_init_test(test, test_case->name, test_case->log); try_catch = &test->try_catch; kunit_try_catch_init(try_catch, @@ -533,6 +537,8 @@ int kunit_run_tests(struct kunit_suite *suite) struct kunit_result_stats param_stats = { 0 }; test_case->status = KUNIT_SKIPPED; + kunit_init_test(&test, test_case->name, test_case->log); + if (!test_case->generate_params) { /* Non-parameterised test. */ kunit_run_case_catch_errors(suite, test_case, &test); From f9a301c3317daa921375da0aec82462ddf019928 Mon Sep 17 00:00:00 2001 From: Rae Moar Date: Wed, 8 Mar 2023 20:39:51 +0000 Subject: [PATCH 03/14] kunit: fix bug in the order of lines in debugfs logs Fix bug in debugfs logs that causes an incorrect order of lines in the debugfs log. Currently, the test counts lines that show the number of tests passed, failed, and skipped, as well as any suite diagnostic lines, appear prior to the individual results, which is a bug. Ensure the order of printing for the debugfs log is correct. Additionally, add a KTAP header to so the debugfs logs can be valid KTAP. This is an example of a log prior to these fixes: KTAP version 1 # Subtest: kunit_status 1..2 # kunit_status: pass:2 fail:0 skip:0 total:2 # Totals: pass:2 fail:0 skip:0 total:2 ok 1 kunit_status_set_failure_test ok 2 kunit_status_mark_skipped_test ok 1 kunit_status Note the two lines with stats are out of order. This is the same debugfs log after the fixes (in combination with the third patch to remove the extra line): KTAP version 1 1..1 KTAP version 1 # Subtest: kunit_status 1..2 ok 1 kunit_status_set_failure_test ok 2 kunit_status_mark_skipped_test # kunit_status: pass:2 fail:0 skip:0 total:2 # Totals: pass:2 fail:0 skip:0 total:2 ok 1 kunit_status Signed-off-by: Rae Moar Reviewed-by: David Gow Signed-off-by: Shuah Khan --- lib/kunit/debugfs.c | 14 ++++++++++++-- lib/kunit/test.c | 21 ++++++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c index de0ee2e03ed6..b08bb1fba106 100644 --- a/lib/kunit/debugfs.c +++ b/lib/kunit/debugfs.c @@ -55,14 +55,24 @@ static int debugfs_print_results(struct seq_file *seq, void *v) enum kunit_status success = kunit_suite_has_succeeded(suite); struct kunit_case *test_case; - if (!suite || !suite->log) + if (!suite) return 0; - seq_printf(seq, "%s", suite->log); + /* Print KTAP header so the debugfs log can be parsed as valid KTAP. */ + seq_puts(seq, "KTAP version 1\n"); + seq_puts(seq, "1..1\n"); + + /* Print suite header because it is not stored in the test logs. */ + seq_puts(seq, KUNIT_SUBTEST_INDENT "KTAP version 1\n"); + seq_printf(seq, KUNIT_SUBTEST_INDENT "# Subtest: %s\n", suite->name); + seq_printf(seq, KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite)); kunit_suite_for_each_test_case(suite, test_case) debugfs_print_result(seq, suite, test_case); + if (suite->log) + seq_printf(seq, "%s", suite->log); + seq_printf(seq, "%s %d %s\n", kunit_status_to_ok_not_ok(success), 1, suite->name); return 0; diff --git a/lib/kunit/test.c b/lib/kunit/test.c index c4d6304edd61..811fcc376d2f 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -152,10 +152,18 @@ EXPORT_SYMBOL_GPL(kunit_suite_num_test_cases); static void kunit_print_suite_start(struct kunit_suite *suite) { - kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "KTAP version 1\n"); - kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "# Subtest: %s", + /* + * We do not log the test suite header as doing so would + * mean debugfs display would consist of the test suite + * header prior to individual test results. + * Hence directly printk the suite status, and we will + * separately seq_printf() the suite header for the debugfs + * representation. + */ + pr_info(KUNIT_SUBTEST_INDENT "KTAP version 1\n"); + pr_info(KUNIT_SUBTEST_INDENT "# Subtest: %s\n", suite->name); - kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "1..%zd", + pr_info(KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite)); } @@ -172,10 +180,9 @@ static void kunit_print_ok_not_ok(void *test_or_suite, /* * We do not log the test suite results as doing so would - * mean debugfs display would consist of the test suite - * description and status prior to individual test results. - * Hence directly printk the suite status, and we will - * separately seq_printf() the suite status for the debugfs + * mean debugfs display would consist of an incorrect test + * number. Hence directly printk the suite result, and we will + * separately seq_printf() the suite results for the debugfs * representation. */ if (suite) From 2c6a96dad5797e57b4cf04101d6c8d5c7a571603 Mon Sep 17 00:00:00 2001 From: Rae Moar Date: Wed, 8 Mar 2023 20:39:52 +0000 Subject: [PATCH 04/14] kunit: fix bug of extra newline characters in debugfs logs Fix bug of the extra newline characters in debugfs logs. When a line is added to debugfs with a newline character at the end, an extra line appears in the debugfs log. This is due to a discrepancy between how the lines are printed and how they are added to the logs. Remove this discrepancy by checking if a newline character is present before adding a newline character. This should closely match the printk behavior. Add kunit_log_newline_test to provide test coverage for this issue. (Also, move kunit_log_test above suite definition to remove the unnecessary declaration prior to the suite definition) As an example, say we add these two lines to the log: kunit_log(..., "KTAP version 1\n"); kunit_log(..., "1..1"); The debugfs log before this fix: KTAP version 1 1..1 The debugfs log after this fix: KTAP version 1 1..1 Signed-off-by: Rae Moar Reviewed-by: David Gow Signed-off-by: Shuah Khan --- include/kunit/test.h | 2 +- lib/kunit/kunit-test.c | 35 +++++++++++++++++++++++------------ lib/kunit/test.c | 18 ++++++++++++++++++ 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/include/kunit/test.h b/include/kunit/test.h index 0668d29f3453..9721584027d8 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -420,7 +420,7 @@ void __printf(2, 3) kunit_log_append(char *log, const char *fmt, ...); #define kunit_log(lvl, test_or_suite, fmt, ...) \ do { \ printk(lvl fmt, ##__VA_ARGS__); \ - kunit_log_append((test_or_suite)->log, fmt "\n", \ + kunit_log_append((test_or_suite)->log, fmt, \ ##__VA_ARGS__); \ } while (0) diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c index 4df0335d0d06..b63595d3e241 100644 --- a/lib/kunit/kunit-test.c +++ b/lib/kunit/kunit-test.c @@ -443,18 +443,6 @@ static struct kunit_suite kunit_resource_test_suite = { .test_cases = kunit_resource_test_cases, }; -static void kunit_log_test(struct kunit *test); - -static struct kunit_case kunit_log_test_cases[] = { - KUNIT_CASE(kunit_log_test), - {} -}; - -static struct kunit_suite kunit_log_test_suite = { - .name = "kunit-log-test", - .test_cases = kunit_log_test_cases, -}; - static void kunit_log_test(struct kunit *test) { struct kunit_suite suite; @@ -481,6 +469,29 @@ static void kunit_log_test(struct kunit *test) #endif } +static void kunit_log_newline_test(struct kunit *test) +{ + kunit_info(test, "Add newline\n"); + if (test->log) { + KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(test->log, "Add newline\n"), + "Missing log line, full log:\n%s", test->log); + KUNIT_EXPECT_NULL(test, strstr(test->log, "Add newline\n\n")); + } else { + kunit_skip(test, "only useful when debugfs is enabled"); + } +} + +static struct kunit_case kunit_log_test_cases[] = { + KUNIT_CASE(kunit_log_test), + KUNIT_CASE(kunit_log_newline_test), + {} +}; + +static struct kunit_suite kunit_log_test_suite = { + .name = "kunit-log-test", + .test_cases = kunit_log_test_cases, +}; + static void kunit_status_set_failure_test(struct kunit *test) { struct kunit fake; diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 811fcc376d2f..e2910b261112 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -108,6 +108,22 @@ static void kunit_print_test_stats(struct kunit *test, stats.total); } +/** + * kunit_log_newline() - Add newline to the end of log if one is not + * already present. + * @log: The log to add the newline to. + */ +static void kunit_log_newline(char *log) +{ + int log_len, len_left; + + log_len = strlen(log); + len_left = KUNIT_LOG_SIZE - log_len - 1; + + if (log_len > 0 && log[log_len - 1] != '\n') + strncat(log, "\n", len_left); +} + /* * Append formatted message to log, size of which is limited to * KUNIT_LOG_SIZE bytes (including null terminating byte). @@ -135,6 +151,8 @@ void kunit_log_append(char *log, const char *fmt, ...) vsnprintf(log + log_len, min(len, len_left), fmt, args); va_end(args); + /* Add newline to end of log if not already present. */ + kunit_log_newline(log); } EXPORT_SYMBOL_GPL(kunit_log_append); From 695e26030858b27648ca107b77095fed53377b4b Mon Sep 17 00:00:00 2001 From: Daniel Latypov Date: Thu, 16 Mar 2023 15:06:36 -0700 Subject: [PATCH 05/14] kunit: tool: add subscripts for type annotations where appropriate E.g. for subprocess.Popen, it can be opened in `text=True` mode where it returns strings, or `text=False` where it returns bytes. To differentiate, you can annotate types as `Popen[str]` or `Popen[bytes]`. This patch should add subscripts in all the places we were missing them. Reported-by: Johannes Berg Link: https://lore.kernel.org/linux-kselftest/20230315105055.9b2be0153625.I7a2cb99b95dff216c0feed4604255275e0b156a7@changeid/ Signed-off-by: Daniel Latypov Reviewed-by: David Gow Signed-off-by: Shuah Khan --- tools/testing/kunit/kunit_kernel.py | 6 +++--- tools/testing/kunit/kunit_printer.py | 2 +- tools/testing/kunit/run_checks.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py index 53e90c335834..e6fc8fcb071a 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -92,7 +92,7 @@ class LinuxSourceTreeOperations: if stderr: # likely only due to build warnings print(stderr.decode()) - def start(self, params: List[str], build_dir: str) -> subprocess.Popen: + def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]: raise RuntimeError('not implemented!') @@ -112,7 +112,7 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations): kconfig.merge_in_entries(base_kunitconfig) return kconfig - def start(self, params: List[str], build_dir: str) -> subprocess.Popen: + def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]: kernel_path = os.path.join(build_dir, self._kernel_path) qemu_command = ['qemu-system-' + self._qemu_arch, '-nodefaults', @@ -141,7 +141,7 @@ class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations): kconfig.merge_in_entries(base_kunitconfig) return kconfig - def start(self, params: List[str], build_dir: str) -> subprocess.Popen: + def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]: """Runs the Linux UML binary. Must be named 'linux'.""" linux_bin = os.path.join(build_dir, 'linux') params.extend(['mem=1G', 'console=tty', 'kunit_shutdown=halt']) diff --git a/tools/testing/kunit/kunit_printer.py b/tools/testing/kunit/kunit_printer.py index 5f1cc55ecdf5..015adf87dc2c 100644 --- a/tools/testing/kunit/kunit_printer.py +++ b/tools/testing/kunit/kunit_printer.py @@ -15,7 +15,7 @@ _RESET = '\033[0;0m' class Printer: """Wraps a file object, providing utilities for coloring output, etc.""" - def __init__(self, output: typing.IO): + def __init__(self, output: typing.IO[str]): self._output = output self._use_color = output.isatty() diff --git a/tools/testing/kunit/run_checks.py b/tools/testing/kunit/run_checks.py index 066e6f938f6d..61cece1684df 100755 --- a/tools/testing/kunit/run_checks.py +++ b/tools/testing/kunit/run_checks.py @@ -37,7 +37,7 @@ def main(argv: Sequence[str]) -> None: if argv: raise RuntimeError('This script takes no arguments') - future_to_name: Dict[futures.Future, str] = {} + future_to_name: Dict[futures.Future[None], 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: From 126901ba3499880c9ed033633817cf7493120fda Mon Sep 17 00:00:00 2001 From: Daniel Latypov Date: Thu, 16 Mar 2023 15:06:37 -0700 Subject: [PATCH 06/14] kunit: tool: remove unused imports and variables We don't run a linter regularly over kunit.py code (the default settings on most don't like kernel style, e.g. tabs) so some of these imports didn't get removed when they stopped being used. Signed-off-by: Daniel Latypov Reviewed-by: David Gow Signed-off-by: Shuah Khan --- tools/testing/kunit/kunit.py | 2 +- tools/testing/kunit/kunit_config.py | 2 +- tools/testing/kunit/kunit_kernel.py | 1 - tools/testing/kunit/kunit_parser.py | 1 - tools/testing/kunit/kunit_tool_test.py | 2 +- 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py index 741f15420467..52853634ba23 100755 --- a/tools/testing/kunit/kunit.py +++ b/tools/testing/kunit/kunit.py @@ -123,7 +123,7 @@ def _suites_from_test_list(tests: List[str]) -> List[str]: parts = t.split('.', maxsplit=2) if len(parts) != 2: raise ValueError(f'internal KUnit error, test name should be of the form ".", got "{t}"') - suite, case = parts + suite, _ = parts if not suites or suites[-1] != suite: suites.append(suite) return suites diff --git a/tools/testing/kunit/kunit_config.py b/tools/testing/kunit/kunit_config.py index 48b5f34b2e5d..9f76d7b89617 100644 --- a/tools/testing/kunit/kunit_config.py +++ b/tools/testing/kunit/kunit_config.py @@ -8,7 +8,7 @@ from dataclasses import dataclass import re -from typing import Dict, Iterable, List, Set, Tuple +from typing import Dict, Iterable, List, Tuple CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$' CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$' diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py index e6fc8fcb071a..775842b912d8 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -18,7 +18,6 @@ import threading from typing import Iterator, List, Optional, Tuple import kunit_config -from kunit_printer import stdout import qemu_config KCONFIG_PATH = '.config' diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py index a225799f6b1b..fbc094f0567e 100644 --- a/tools/testing/kunit/kunit_parser.py +++ b/tools/testing/kunit/kunit_parser.py @@ -12,7 +12,6 @@ from __future__ import annotations from dataclasses import dataclass import re -import sys import textwrap from enum import Enum, auto diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py index 0c2190514103..be35999bb84f 100755 --- a/tools/testing/kunit/kunit_tool_test.py +++ b/tools/testing/kunit/kunit_tool_test.py @@ -328,7 +328,7 @@ class KUnitParserTest(unittest.TestCase): def test_parse_subtest_header(self): ktap_log = test_data_path('test_parse_subtest_header.log') with open(ktap_log) as file: - result = kunit_parser.parse_run_tests(file.readlines()) + kunit_parser.parse_run_tests(file.readlines()) self.print_mock.assert_any_call(StrContains('suite (1 subtest)')) def test_show_test_output_on_failure(self): From 1da2e6220e1115930694c649605534baf6fa3dea Mon Sep 17 00:00:00 2001 From: Daniel Latypov Date: Thu, 16 Mar 2023 15:06:38 -0700 Subject: [PATCH 07/14] kunit: tool: fix pre-existing `mypy --strict` errors and update run_checks.py Basically, get this command to be happy and make run_checks.py happy $ mypy --strict --exclude '_test.py$' --exclude qemu_configs/ ./tools/testing/kunit/ Primarily the changes are * add `-> None` return type annotations * add all the missing argument type annotations Previously, we had false positives from mypy in `main()`, see commit 09641f7c7d8f ("kunit: tool: surface and address more typing issues"). But after commit 2dc9d6ca52a4 ("kunit: kunit.py extract handlers") refactored things, the variable name reuse mypy hated is gone. Note: mypy complains we don't annotate the types the unused args in our signal handler. That's silly. But to make it happy, I've copy-pasted an appropriate annotation from https://github.com/python/typing/discussions/1042#discussioncomment-2013595. Reported-by: Johannes Berg Link: https://lore.kernel.org/linux-kselftest/9a172b50457f4074af41fe1dc8e55dcaf4795d7e.camel@sipsolutions.net/ Signed-off-by: Daniel Latypov Reviewed-by: David Gow Signed-off-by: Shuah Khan --- tools/testing/kunit/kunit.py | 24 ++++++++++++------------ tools/testing/kunit/kunit_config.py | 4 ++-- tools/testing/kunit/kunit_kernel.py | 29 +++++++++++++++-------------- tools/testing/kunit/run_checks.py | 4 ++-- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py index 52853634ba23..3905c43369c3 100755 --- a/tools/testing/kunit/kunit.py +++ b/tools/testing/kunit/kunit.py @@ -269,7 +269,7 @@ def massage_argv(argv: Sequence[str]) -> Sequence[str]: def get_default_jobs() -> int: return len(os.sched_getaffinity(0)) -def add_common_opts(parser) -> None: +def add_common_opts(parser: argparse.ArgumentParser) -> None: parser.add_argument('--build_dir', help='As in the make command, it specifies the build ' 'directory.', @@ -320,13 +320,13 @@ def add_common_opts(parser) -> None: help='Additional QEMU arguments, e.g. "-smp 8"', action='append', metavar='') -def add_build_opts(parser) -> None: +def add_build_opts(parser: argparse.ArgumentParser) -> None: parser.add_argument('--jobs', help='As in the make command, "Specifies the number of ' 'jobs (commands) to run simultaneously."', type=int, default=get_default_jobs(), metavar='N') -def add_exec_opts(parser) -> None: +def add_exec_opts(parser: argparse.ArgumentParser) -> None: parser.add_argument('--timeout', help='maximum number of seconds to allow for all tests ' 'to run. This does not include time taken to build the ' @@ -351,7 +351,7 @@ def add_exec_opts(parser) -> None: type=str, choices=['suite', 'test']) -def add_parse_opts(parser) -> None: +def add_parse_opts(parser: argparse.ArgumentParser) -> None: parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. ' 'By default, filters to just KUnit output. Use ' '--raw_output=all to show everything', @@ -386,7 +386,7 @@ def tree_from_args(cli_args: argparse.Namespace) -> kunit_kernel.LinuxSourceTree extra_qemu_args=qemu_args) -def run_handler(cli_args): +def run_handler(cli_args: argparse.Namespace) -> None: if not os.path.exists(cli_args.build_dir): os.mkdir(cli_args.build_dir) @@ -405,7 +405,7 @@ def run_handler(cli_args): sys.exit(1) -def config_handler(cli_args): +def config_handler(cli_args: argparse.Namespace) -> None: if cli_args.build_dir and ( not os.path.exists(cli_args.build_dir)): os.mkdir(cli_args.build_dir) @@ -421,7 +421,7 @@ def config_handler(cli_args): sys.exit(1) -def build_handler(cli_args): +def build_handler(cli_args: argparse.Namespace) -> None: linux = tree_from_args(cli_args) request = KunitBuildRequest(build_dir=cli_args.build_dir, make_options=cli_args.make_options, @@ -434,7 +434,7 @@ def build_handler(cli_args): sys.exit(1) -def exec_handler(cli_args): +def exec_handler(cli_args: argparse.Namespace) -> None: linux = tree_from_args(cli_args) exec_request = KunitExecRequest(raw_output=cli_args.raw_output, build_dir=cli_args.build_dir, @@ -450,10 +450,10 @@ def exec_handler(cli_args): sys.exit(1) -def parse_handler(cli_args): +def parse_handler(cli_args: argparse.Namespace) -> None: if cli_args.file is None: - sys.stdin.reconfigure(errors='backslashreplace') # pytype: disable=attribute-error - kunit_output = sys.stdin + sys.stdin.reconfigure(errors='backslashreplace') # type: ignore + kunit_output = sys.stdin # type: Iterable[str] else: with open(cli_args.file, 'r', errors='backslashreplace') as f: kunit_output = f.read().splitlines() @@ -475,7 +475,7 @@ subcommand_handlers_map = { } -def main(argv): +def main(argv: Sequence[str]) -> None: parser = argparse.ArgumentParser( description='Helps writing and running KUnit tests.') subparser = parser.add_subparsers(dest='subcommand') diff --git a/tools/testing/kunit/kunit_config.py b/tools/testing/kunit/kunit_config.py index 9f76d7b89617..eb5dd01210b1 100644 --- a/tools/testing/kunit/kunit_config.py +++ b/tools/testing/kunit/kunit_config.py @@ -8,7 +8,7 @@ from dataclasses import dataclass import re -from typing import Dict, Iterable, List, Tuple +from typing import Any, Dict, Iterable, List, Tuple CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$' CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$' @@ -34,7 +34,7 @@ class Kconfig: def __init__(self) -> None: self._entries = {} # type: Dict[str, str] - def __eq__(self, other) -> bool: + def __eq__(self, other: Any) -> bool: if not isinstance(other, self.__class__): return False return self._entries == other._entries diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py index 775842b912d8..a3321a991f11 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -16,6 +16,7 @@ import shutil import signal import threading from typing import Iterator, List, Optional, Tuple +from types import FrameType import kunit_config import qemu_config @@ -56,7 +57,7 @@ class LinuxSourceTreeOperations: def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig: return base_kunitconfig - def make_olddefconfig(self, build_dir: str, make_options) -> None: + def make_olddefconfig(self, build_dir: str, make_options: Optional[List[str]]) -> None: command = ['make', 'ARCH=' + self._linux_arch, 'O=' + build_dir, 'olddefconfig'] if self._cross_compile: command += ['CROSS_COMPILE=' + self._cross_compile] @@ -70,7 +71,7 @@ class LinuxSourceTreeOperations: except subprocess.CalledProcessError as e: raise ConfigError(e.output.decode()) - def make(self, jobs, build_dir: str, make_options) -> None: + def make(self, jobs: int, build_dir: str, make_options: Optional[List[str]]) -> None: command = ['make', 'ARCH=' + self._linux_arch, 'O=' + build_dir, '--jobs=' + str(jobs)] if make_options: command.extend(make_options) @@ -132,7 +133,7 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations): class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations): """An abstraction over command line operations performed on a source tree.""" - def __init__(self, cross_compile=None): + def __init__(self, cross_compile: Optional[str]=None): super().__init__(linux_arch='um', cross_compile=cross_compile) def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig: @@ -215,7 +216,7 @@ def _get_qemu_ops(config_path: str, if not hasattr(config, 'QEMU_ARCH'): raise ValueError('qemu_config module missing "QEMU_ARCH": ' + config_path) - params: qemu_config.QemuArchParams = config.QEMU_ARCH # type: ignore + params: qemu_config.QemuArchParams = config.QEMU_ARCH if extra_qemu_args: params.extra_qemu_params.extend(extra_qemu_args) return params.linux_arch, LinuxSourceTreeOperationsQemu( @@ -229,10 +230,10 @@ class LinuxSourceTree: build_dir: str, kunitconfig_paths: Optional[List[str]]=None, kconfig_add: Optional[List[str]]=None, - arch=None, - cross_compile=None, - qemu_config_path=None, - extra_qemu_args=None) -> None: + arch: Optional[str]=None, + cross_compile: Optional[str]=None, + qemu_config_path: Optional[str]=None, + extra_qemu_args: Optional[List[str]]=None) -> None: signal.signal(signal.SIGINT, self.signal_handler) if qemu_config_path: self._arch, self._ops = _get_qemu_ops(qemu_config_path, extra_qemu_args, cross_compile) @@ -275,7 +276,7 @@ class LinuxSourceTree: logging.error(message) return False - def build_config(self, build_dir: str, make_options) -> bool: + def build_config(self, build_dir: str, make_options: Optional[List[str]]) -> bool: kconfig_path = get_kconfig_path(build_dir) if build_dir and not os.path.exists(build_dir): os.mkdir(build_dir) @@ -303,7 +304,7 @@ class LinuxSourceTree: old_kconfig = kunit_config.parse_file(old_path) return old_kconfig != self._kconfig - def build_reconfig(self, build_dir: str, make_options) -> bool: + def build_reconfig(self, build_dir: str, make_options: Optional[List[str]]) -> bool: """Creates a new .config if it is not a subset of the .kunitconfig.""" kconfig_path = get_kconfig_path(build_dir) if not os.path.exists(kconfig_path): @@ -319,7 +320,7 @@ class LinuxSourceTree: os.remove(kconfig_path) return self.build_config(build_dir, make_options) - def build_kernel(self, jobs, build_dir: str, make_options) -> bool: + def build_kernel(self, jobs: int, build_dir: str, make_options: Optional[List[str]]) -> bool: try: self._ops.make_olddefconfig(build_dir, make_options) self._ops.make(jobs, build_dir, make_options) @@ -328,7 +329,7 @@ class LinuxSourceTree: return False return self.validate_config(build_dir) - def run_kernel(self, args=None, build_dir='', filter_glob='', timeout=None) -> Iterator[str]: + def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', timeout: Optional[int]=None) -> Iterator[str]: if not args: args = [] if filter_glob: @@ -339,7 +340,7 @@ class LinuxSourceTree: assert process.stdout is not None # tell mypy it's set # Enforce the timeout in a background thread. - def _wait_proc(): + def _wait_proc() -> None: try: process.wait(timeout=timeout) except Exception as e: @@ -365,6 +366,6 @@ class LinuxSourceTree: waiter.join() subprocess.call(['stty', 'sane']) - def signal_handler(self, unused_sig, unused_frame) -> None: + def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None: logging.error('Build interruption occurred. Cleaning console.') subprocess.call(['stty', 'sane']) diff --git a/tools/testing/kunit/run_checks.py b/tools/testing/kunit/run_checks.py index 61cece1684df..8208c3b3135e 100755 --- a/tools/testing/kunit/run_checks.py +++ b/tools/testing/kunit/run_checks.py @@ -23,7 +23,7 @@ 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'], + 'mypy': ['mypy', '--strict', '--exclude', '_test.py$', '--exclude', 'qemu_configs/', '.'], } # The user might not have mypy or pytype installed, skip them if so. @@ -73,7 +73,7 @@ def main(argv: Sequence[str]) -> None: sys.exit(1) -def run_cmd(argv: Sequence[str]): +def run_cmd(argv: Sequence[str]) -> None: subprocess.check_output(argv, stderr=subprocess.STDOUT, cwd=ABS_TOOL_PATH, timeout=TIMEOUT) From 99be6588118bedc522fa989146f35efceff07c1e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Mar 2023 16:39:25 -0700 Subject: [PATCH 08/14] kunit: Use gfp in kunit_alloc_resource() kernel-doc Copy/pasting the code from the kernel-doc here doesn't compile because kunit_alloc_resource() takes a gfp flags argument. Pass the gfp argument from the caller to complete the example. Signed-off-by: Stephen Boyd Reviewed-by: David Gow Signed-off-by: Shuah Khan --- include/kunit/resource.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/kunit/resource.h b/include/kunit/resource.h index cf6fb8f2ac1b..c0d88b318e90 100644 --- a/include/kunit/resource.h +++ b/include/kunit/resource.h @@ -72,7 +72,7 @@ typedef void (*kunit_resource_free_t)(struct kunit_resource *); * params.gfp = gfp; * * return kunit_alloc_resource(test, kunit_kmalloc_init, - * kunit_kmalloc_free, ¶ms); + * kunit_kmalloc_free, gfp, ¶ms); * } * * Resources can also be named, with lookup/removal done on a name From 7232282dd47cce6a780c9414bd9baccf232c7686 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 27 Mar 2023 13:53:31 +0200 Subject: [PATCH 09/14] kunit: increase KUNIT_LOG_SIZE to 2048 bytes The s390 specific test_unwind kunit test has 39 parameterized tests. The results in debugfs are truncated since the full log doesn't fit into 1500 bytes. Therefore increase KUNIT_LOG_SIZE to 2048 bytes in a similar way like it was done recently with commit "kunit: fix bug in debugfs logs of parameterized tests". With that the whole test result is present. Reported-by: Alexander Egorenkov Signed-off-by: Heiko Carstens Reviewed-by: Rae Moar Reviewed-by: David Gow Signed-off-by: Shuah Khan --- include/kunit/test.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/kunit/test.h b/include/kunit/test.h index 9721584027d8..57b309c6ca27 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -34,7 +34,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running); struct kunit; /* Size of log associated with test. */ -#define KUNIT_LOG_SIZE 1500 +#define KUNIT_LOG_SIZE 2048 /* Maximum size of parameter description string. */ #define KUNIT_PARAM_DESC_SIZE 128 From 57b4f760f94da13104cd596d5fb1643ae09c4d49 Mon Sep 17 00:00:00 2001 From: Sadiya Kazi Date: Fri, 31 Mar 2023 06:45:29 +0000 Subject: [PATCH 10/14] list: test: Test the klist structure Add KUnit tests to the klist linked-list structure. These perform testing for different variations of node add and node delete in the klist data structure (). Limitation: Since we use a static global variable, and if multiple instances of this test are run concurrently, the test may fail. Signed-off-by: Sadiya Kazi Reviewed-by: Brendan Higgins Reviewed-by: David Gow Signed-off-by: Shuah Khan --- lib/list-test.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 299 insertions(+), 1 deletion(-) diff --git a/lib/list-test.c b/lib/list-test.c index d374cf5d1a57..0cc27de9cec8 100644 --- a/lib/list-test.c +++ b/lib/list-test.c @@ -8,6 +8,7 @@ #include #include +#include struct list_test_struct { int data; @@ -1199,6 +1200,303 @@ static struct kunit_suite hlist_test_module = { .test_cases = hlist_test_cases, }; -kunit_test_suites(&list_test_module, &hlist_test_module); + +struct klist_test_struct { + int data; + struct klist klist; + struct klist_node klist_node; +}; + +static int node_count; +static struct klist_node *last_node; + +static void check_node(struct klist_node *node_ptr) +{ + node_count++; + last_node = node_ptr; +} + +static void check_delete_node(struct klist_node *node_ptr) +{ + node_count--; + last_node = node_ptr; +} + +static void klist_test_add_tail(struct kunit *test) +{ + struct klist_node a, b; + struct klist mylist; + struct klist_iter i; + + node_count = 0; + klist_init(&mylist, &check_node, NULL); + + klist_add_tail(&a, &mylist); + KUNIT_EXPECT_EQ(test, node_count, 1); + KUNIT_EXPECT_PTR_EQ(test, last_node, &a); + + klist_add_tail(&b, &mylist); + KUNIT_EXPECT_EQ(test, node_count, 2); + KUNIT_EXPECT_PTR_EQ(test, last_node, &b); + + /* should be [list] -> a -> b */ + klist_iter_init(&mylist, &i); + + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b); + KUNIT_EXPECT_NULL(test, klist_next(&i)); + + klist_iter_exit(&i); + +} + +static void klist_test_add_head(struct kunit *test) +{ + struct klist_node a, b; + struct klist mylist; + struct klist_iter i; + + node_count = 0; + klist_init(&mylist, &check_node, NULL); + + klist_add_head(&a, &mylist); + KUNIT_EXPECT_EQ(test, node_count, 1); + KUNIT_EXPECT_PTR_EQ(test, last_node, &a); + + klist_add_head(&b, &mylist); + KUNIT_EXPECT_EQ(test, node_count, 2); + KUNIT_EXPECT_PTR_EQ(test, last_node, &b); + + /* should be [list] -> b -> a */ + klist_iter_init(&mylist, &i); + + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a); + KUNIT_EXPECT_NULL(test, klist_next(&i)); + + klist_iter_exit(&i); + +} + +static void klist_test_add_behind(struct kunit *test) +{ + struct klist_node a, b, c, d; + struct klist mylist; + struct klist_iter i; + + node_count = 0; + klist_init(&mylist, &check_node, NULL); + + klist_add_head(&a, &mylist); + klist_add_head(&b, &mylist); + + klist_add_behind(&c, &a); + KUNIT_EXPECT_EQ(test, node_count, 3); + KUNIT_EXPECT_PTR_EQ(test, last_node, &c); + + klist_add_behind(&d, &b); + KUNIT_EXPECT_EQ(test, node_count, 4); + KUNIT_EXPECT_PTR_EQ(test, last_node, &d); + + klist_iter_init(&mylist, &i); + + /* should be [list] -> b -> d -> a -> c*/ + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c); + KUNIT_EXPECT_NULL(test, klist_next(&i)); + + klist_iter_exit(&i); + +} + +static void klist_test_add_before(struct kunit *test) +{ + struct klist_node a, b, c, d; + struct klist mylist; + struct klist_iter i; + + node_count = 0; + klist_init(&mylist, &check_node, NULL); + + klist_add_head(&a, &mylist); + klist_add_head(&b, &mylist); + klist_add_before(&c, &a); + KUNIT_EXPECT_EQ(test, node_count, 3); + KUNIT_EXPECT_PTR_EQ(test, last_node, &c); + + klist_add_before(&d, &b); + KUNIT_EXPECT_EQ(test, node_count, 4); + KUNIT_EXPECT_PTR_EQ(test, last_node, &d); + + klist_iter_init(&mylist, &i); + + /* should be [list] -> b -> d -> a -> c*/ + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a); + KUNIT_EXPECT_NULL(test, klist_next(&i)); + + klist_iter_exit(&i); + +} + +/* + * Verify that klist_del() delays the deletion of a node until there + * are no other references to it + */ +static void klist_test_del_refcount_greater_than_zero(struct kunit *test) +{ + struct klist_node a, b, c, d; + struct klist mylist; + struct klist_iter i; + + node_count = 0; + klist_init(&mylist, &check_node, &check_delete_node); + + /* Add nodes a,b,c,d to the list*/ + klist_add_tail(&a, &mylist); + klist_add_tail(&b, &mylist); + klist_add_tail(&c, &mylist); + klist_add_tail(&d, &mylist); + + klist_iter_init(&mylist, &i); + + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b); + /* Advance the iterator to point to node c*/ + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c); + + /* Try to delete node c while there is a reference to it*/ + klist_del(&c); + + /* + * Verify that node c is still attached to the list even after being + * deleted. Since the iterator still points to c, the reference count is not + * decreased to 0 + */ + KUNIT_EXPECT_TRUE(test, klist_node_attached(&c)); + + /* Check that node c has not been removed yet*/ + KUNIT_EXPECT_EQ(test, node_count, 4); + KUNIT_EXPECT_PTR_EQ(test, last_node, &d); + + klist_iter_exit(&i); + + /* + * Since the iterator is no longer pointing to node c, node c is removed + * from the list + */ + KUNIT_EXPECT_EQ(test, node_count, 3); + KUNIT_EXPECT_PTR_EQ(test, last_node, &c); + +} + +/* + * Verify that klist_del() deletes a node immediately when there are no + * other references to it. + */ +static void klist_test_del_refcount_zero(struct kunit *test) +{ + struct klist_node a, b, c, d; + struct klist mylist; + struct klist_iter i; + + node_count = 0; + klist_init(&mylist, &check_node, &check_delete_node); + + /* Add nodes a,b,c,d to the list*/ + klist_add_tail(&a, &mylist); + klist_add_tail(&b, &mylist); + klist_add_tail(&c, &mylist); + klist_add_tail(&d, &mylist); + /* Delete node c*/ + klist_del(&c); + + /* Check that node c is deleted from the list*/ + KUNIT_EXPECT_EQ(test, node_count, 3); + KUNIT_EXPECT_PTR_EQ(test, last_node, &c); + + /* Should be [list] -> a -> b -> d*/ + klist_iter_init(&mylist, &i); + + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d); + KUNIT_EXPECT_NULL(test, klist_next(&i)); + + klist_iter_exit(&i); + +} + +static void klist_test_remove(struct kunit *test) +{ + /* This test doesn't check correctness under concurrent access */ + struct klist_node a, b, c, d; + struct klist mylist; + struct klist_iter i; + + node_count = 0; + klist_init(&mylist, &check_node, &check_delete_node); + + /* Add nodes a,b,c,d to the list*/ + klist_add_tail(&a, &mylist); + klist_add_tail(&b, &mylist); + klist_add_tail(&c, &mylist); + klist_add_tail(&d, &mylist); + /* Delete node c*/ + klist_remove(&c); + + /* Check the nodes in the list*/ + KUNIT_EXPECT_EQ(test, node_count, 3); + KUNIT_EXPECT_PTR_EQ(test, last_node, &c); + + /* should be [list] -> a -> b -> d*/ + klist_iter_init(&mylist, &i); + + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b); + KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d); + KUNIT_EXPECT_NULL(test, klist_next(&i)); + + klist_iter_exit(&i); + +} + +static void klist_test_node_attached(struct kunit *test) +{ + struct klist_node a = {}; + struct klist mylist; + + klist_init(&mylist, NULL, NULL); + + KUNIT_EXPECT_FALSE(test, klist_node_attached(&a)); + klist_add_head(&a, &mylist); + KUNIT_EXPECT_TRUE(test, klist_node_attached(&a)); + klist_del(&a); + KUNIT_EXPECT_FALSE(test, klist_node_attached(&a)); + +} + +static struct kunit_case klist_test_cases[] = { + KUNIT_CASE(klist_test_add_tail), + KUNIT_CASE(klist_test_add_head), + KUNIT_CASE(klist_test_add_behind), + KUNIT_CASE(klist_test_add_before), + KUNIT_CASE(klist_test_del_refcount_greater_than_zero), + KUNIT_CASE(klist_test_del_refcount_zero), + KUNIT_CASE(klist_test_remove), + KUNIT_CASE(klist_test_node_attached), + {}, +}; + +static struct kunit_suite klist_test_module = { + .name = "klist", + .test_cases = klist_test_cases, +}; + +kunit_test_suites(&list_test_module, &hlist_test_module, &klist_test_module); MODULE_LICENSE("GPL v2"); From cb8865fd865f5b2f656d0d91f3b0146ef1acb10d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 27 Jan 2023 16:57:08 +0200 Subject: [PATCH 11/14] .gitignore: Unignore .kunitconfig There are almost dozen of .kunitconfig files that are ignored but tracked. Unignore them. Signed-off-by: Andy Shevchenko Reviewed-by: David Gow Signed-off-by: Shuah Khan --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8fe465f251c0..8779916df8b8 100644 --- a/.gitignore +++ b/.gitignore @@ -102,6 +102,7 @@ modules.order !.get_maintainer.ignore !.gitattributes !.gitignore +!.kunitconfig !.mailmap !.rustfmt.toml From 5ffb8629b133fecf7cdd36134ae6d6a1efb46eb5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Feb 2023 11:31:02 +0100 Subject: [PATCH 12/14] kunit: tool: Add support for overriding the QEMU serial port On some platforms, the console is not the first serial port. To make this work, the first serial port in QEMU must be set to "null". Add support for this by adding an optional "serial" parameter, which defaults to "stdio", and can be overridden by platform-specific configuration. Signed-off-by: Geert Uytterhoeven Reviewed-by: David Gow Signed-off-by: Shuah Khan --- tools/testing/kunit/kunit_kernel.py | 3 ++- tools/testing/kunit/qemu_config.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py index a3321a991f11..f01f94106129 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -106,6 +106,7 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations): self._kernel_path = qemu_arch_params.kernel_path self._kernel_command_line = qemu_arch_params.kernel_command_line + ' kunit_shutdown=reboot' self._extra_qemu_params = qemu_arch_params.extra_qemu_params + self._serial = qemu_arch_params.serial def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig: kconfig = kunit_config.parse_from_string(self._kconfig) @@ -121,7 +122,7 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations): '-append', ' '.join(params + [self._kernel_command_line]), '-no-reboot', '-nographic', - '-serial', 'stdio'] + self._extra_qemu_params + '-serial', self._serial] + self._extra_qemu_params # Note: shlex.join() does what we want, but requires python 3.8+. print('Running tests with:\n$', ' '.join(shlex.quote(arg) for arg in qemu_command)) return subprocess.Popen(qemu_command, diff --git a/tools/testing/kunit/qemu_config.py b/tools/testing/kunit/qemu_config.py index 0b6a80398ccc..b1fba9016eed 100644 --- a/tools/testing/kunit/qemu_config.py +++ b/tools/testing/kunit/qemu_config.py @@ -17,3 +17,4 @@ class QemuArchParams: kernel_path: str kernel_command_line: str extra_qemu_params: List[str] + serial: str = 'stdio' From 8110a3cab05ee4a26f36015f0423fb2b5cea1392 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Feb 2023 11:31:03 +0100 Subject: [PATCH 13/14] kunit: tool: Add support for SH under QEMU Add basic support to run SH under QEMU via kunit_tool using the virtualized r2d platform. Signed-off-by: Geert Uytterhoeven Reviewed-by: David Gow Signed-off-by: Shuah Khan --- tools/testing/kunit/qemu_configs/sh.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tools/testing/kunit/qemu_configs/sh.py diff --git a/tools/testing/kunit/qemu_configs/sh.py b/tools/testing/kunit/qemu_configs/sh.py new file mode 100644 index 000000000000..78a474a5b95f --- /dev/null +++ b/tools/testing/kunit/qemu_configs/sh.py @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +from ..qemu_config import QemuArchParams + +QEMU_ARCH = QemuArchParams(linux_arch='sh', + kconfig=''' +CONFIG_CPU_SUBTYPE_SH7751R=y +CONFIG_MEMORY_START=0x0c000000 +CONFIG_SH_RTS7751R2D=y +CONFIG_RTS7751R2D_PLUS=y +CONFIG_SERIAL_SH_SCI=y''', + qemu_arch='sh4', + kernel_path='arch/sh/boot/zImage', + kernel_command_line='console=ttySC1', + serial='null', + extra_qemu_params=[ + '-machine', 'r2d', + '-serial', 'mon:stdio']) From a42077b787680cbc365a96446b30f32399fa3f6f Mon Sep 17 00:00:00 2001 From: Rae Moar Date: Mon, 3 Apr 2023 20:19:30 +0000 Subject: [PATCH 14/14] kunit: add tests for using current KUnit test field Create test suite called "kunit_current" to add test coverage for the use of current->kunit_test, which returns the current KUnit test. Add two test cases: - kunit_current_test to test current->kunit_test and the method kunit_get_current_test(), which utilizes current->kunit_test. - kunit_current_fail_test to test the method kunit_fail_current_test(), which utilizes current->kunit_test. Signed-off-by: Rae Moar Reviewed-by: Daniel Latypov Reviewed-by: David Gow Signed-off-by: Shuah Khan --- lib/kunit/kunit-test.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c index b63595d3e241..42e44caa1bdd 100644 --- a/lib/kunit/kunit-test.c +++ b/lib/kunit/kunit-test.c @@ -6,6 +6,7 @@ * Author: Brendan Higgins */ #include +#include #include "try-catch-impl.h" @@ -532,7 +533,46 @@ static struct kunit_suite kunit_status_test_suite = { .test_cases = kunit_status_test_cases, }; +static void kunit_current_test(struct kunit *test) +{ + /* Check results of both current->kunit_test and + * kunit_get_current_test() are equivalent to current test. + */ + KUNIT_EXPECT_PTR_EQ(test, test, current->kunit_test); + KUNIT_EXPECT_PTR_EQ(test, test, kunit_get_current_test()); +} + +static void kunit_current_fail_test(struct kunit *test) +{ + struct kunit fake; + + kunit_init_test(&fake, "fake test", NULL); + KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS); + + /* Set current->kunit_test to fake test. */ + current->kunit_test = &fake; + + kunit_fail_current_test("This should make `fake` test fail."); + KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE); + kunit_cleanup(&fake); + + /* Reset current->kunit_test to current test. */ + current->kunit_test = test; +} + +static struct kunit_case kunit_current_test_cases[] = { + KUNIT_CASE(kunit_current_test), + KUNIT_CASE(kunit_current_fail_test), + {} +}; + +static struct kunit_suite kunit_current_test_suite = { + .name = "kunit_current", + .test_cases = kunit_current_test_cases, +}; + kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite, - &kunit_log_test_suite, &kunit_status_test_suite); + &kunit_log_test_suite, &kunit_status_test_suite, + &kunit_current_test_suite); MODULE_LICENSE("GPL v2");