[PATCH 1/2] kunit: tool: add parsing of test attributes

2023-09-14 Thread Rae Moar
Add parsing of attributes as diagnostic data. Fixes issue with test plan
being parsed incorrectly as diagnostic data when located after
suite-level attributes.

Note that if there does not exist a test plan line, the diagnostic lines
between the suite header and the first result will be saved in the suite
log rather than the first test log.

This could be changed to do the opposite if preferred.

Signed-off-by: Rae Moar 
---
 tools/testing/kunit/kunit_parser.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/testing/kunit/kunit_parser.py 
b/tools/testing/kunit/kunit_parser.py
index 79d8832c862a..ce34be15c929 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -450,7 +450,7 @@ def parse_diagnostic(lines: LineStream) -> List[str]:
Log of diagnostic lines
"""
log = []  # type: List[str]
-   non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, TAP_START]
+   non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, 
TAP_START, TEST_PLAN]
while lines and not any(re.match(lines.peek())
for re in non_diagnostic_lines):
log.append(lines.pop())
@@ -726,6 +726,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
# test plan
test.name = "main"
ktap_line = parse_ktap_header(lines, test)
+   test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
parent_test = True
else:
@@ -737,6 +738,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
if parent_test:
# If KTAP version line and/or subtest header is found, 
attempt
# to parse test plan and print test header
+   test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
print_test_header(test)
expected_count = test.expected_count

base-commit: 9076bc476d7ebf0565903c4b048442131825c1c3
-- 
2.42.0.459.ge4e396fd5e-goog



[PATCH 2/2] kunit: tool: add attributes output to kunit.py

2023-09-14 Thread Rae Moar
Output attributes in kunit.py results.

Example of format:

[21:33:23] === example (7 subtests) ===
[21:33:23] module: kunit_example_test
[21:33:23] [PASSED] example_simple_test
...
[21:33:23] [PASSED] example_slow_test
[21:33:23] speed: slow
[21:33:23] === [PASSED] example ===

The attributes are outputted directly below the associated test.

Note that the attributes lines are saved in the log and then the log is
parsed for attributes rather than saving attributes in their own field.

This is due to diagnostic lines being saved prior to the creation of the
associated test object.

Signed-off-by: Rae Moar 
---
 tools/testing/kunit/kunit_parser.py | 31 +
 1 file changed, 31 insertions(+)

diff --git a/tools/testing/kunit/kunit_parser.py 
b/tools/testing/kunit/kunit_parser.py
index ce34be15c929..ffa9cfdcf5d6 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -509,6 +509,34 @@ def print_test_header(test: Test) -> None:
message += f'({test.expected_count} subtests)'
stdout.print_with_timestamp(format_test_divider(message, len(message)))
 
+TEST_HEADER_ATTR = re.compile(r'^\s*# (.*): (.*)$')
+TEST_ATTR = re.compile(r'^\s*# (.*)\.(.*): (.*)$')
+
+def print_test_attr(test: Test) -> None:
+   """
+   Attributes, if present, will be printed in a list separated by
+   commas.
+
+   Example:
+   'module: example_test, speed: slow'
+
+   Parameters:
+   test - Test object representing current test being printed
+   """
+   attr_list = ["module", "speed"]
+   output = []
+
+   for line in test.log:
+   test_match = TEST_ATTR.match(line)
+   header_match = TEST_HEADER_ATTR.match(line)
+   if test_match and (test_match.group(1) == test.name
+ and (test_match.group(2) in 
attr_list)):
+   output.append(test_match.group(2) + ": " + 
test_match.group(3))
+   elif header_match and (header_match.group(1) in attr_list):
+   output.append(header_match.group(1) + ": " + 
header_match.group(2))
+   if output:
+   stdout.print_with_timestamp(", ".join(output))
+
 def print_log(log: Iterable[str]) -> None:
"""Prints all strings in saved log for test in yellow."""
formatted = textwrap.dedent('\n'.join(log))
@@ -741,6 +769,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
print_test_header(test)
+   print_test_attr(test)
expected_count = test.expected_count
subtests = []
test_num = 1
@@ -763,6 +792,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
test.counts.add_status(
TestStatus.TEST_CRASHED)
print_test_result(sub_test)
+   print_test_attr(sub_test)
else:
test.log.extend(sub_log)
break
@@ -796,6 +826,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
print_test_footer(test)
elif is_subtest:
print_test_result(test)
+   print_test_attr(test)
return test
 
 def parse_run_tests(kernel_output: Iterable[str]) -> Test:
-- 
2.42.0.459.ge4e396fd5e-goog



Re: [PATCH] kunit: Check for kunit_parse_glob_filter() failure

2023-09-19 Thread Rae Moar
On Fri, Sep 15, 2023 at 8:58 AM Dan Carpenter  wrote:
>
> Smatch complains that the missing error checks would lead to a crash:
>
> lib/kunit/executor_test.c:40 parse_filter_test()
> error: double free of 'filter.test_glob'
>
> We may as well do it right...
>
> Fixes: a127b154a8f2 ("kunit: tool: allow filtering test cases via glob")
> Signed-off-by: Dan Carpenter 

Hello!

We definitely should add in checks for these errors. I have a couple
comments below.

Thanks!
-Rae

> ---
>  lib/kunit/executor_test.c | 6 --
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
> index b4f6f96b2844..176c9c9dfcfc 100644
> --- a/lib/kunit/executor_test.c
> +++ b/lib/kunit/executor_test.c
> @@ -27,13 +27,15 @@ static void parse_filter_test(struct kunit *test)
>  {
> struct kunit_glob_filter filter = {NULL, NULL};
>
> -   kunit_parse_glob_filter(&filter, "suite");
> +   if (!kunit_parse_glob_filter(&filter, "suite"))
> +   return;

First, this is returning every time this test is run because the
kunit_parse_glob_filter returns 0 when there is no error. So this
should instead be checking for a result of not equal to 0.

Secondly, this should fail the test if the parsing returns an error.
So instead of returning I would recommend using a KUNIT_ASSERT
statement to check the result of this method is equal to 0.

> KUNIT_EXPECT_STREQ(test, filter.suite_glob, "suite");
> KUNIT_EXPECT_FALSE(test, filter.test_glob);
> kfree(filter.suite_glob);
> kfree(filter.test_glob);
>
> -   kunit_parse_glob_filter(&filter, "suite.test");
> +   if (!kunit_parse_glob_filter(&filter, "suite.test"))
> +   return;

Similar to above I think this should be changed to a KUNIT_ASSERT
statement to ensure the result is equal to 0.

> KUNIT_EXPECT_STREQ(test, filter.suite_glob, "suite");
> KUNIT_EXPECT_STREQ(test, filter.test_glob, "test");
> kfree(filter.suite_glob);
> --
> 2.39.2
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/3ff9d019-75b6-45ee-9b03-9d6ec7c5364f%40moroto.mountain.


Re: [PATCH 1/2] kunit: Warn if tests are slow

2023-09-19 Thread Rae Moar
On Mon, Sep 11, 2023 at 5:51 AM Maxime Ripard  wrote:
>
> Kunit recently gained support to setup attributes, the first one being
> the speed of a given test, then allowing to filter out slow tests.
>
> A slow test is defined in the documentation as taking more than one
> second. There's an another speed attribute called "super slow" but whose
> definition is less clear.
>
> Add support to the test runner to check the test execution time, and
> report tests that should be marked as slow but aren't.
>
> Signed-off-by: Maxime Ripard 

Hi!

I like this idea especially if it was helpful in identifying slow
tests already! I have a few thoughts on this. I share Jani's concern
for warning all tests on slow machines. I can think of a few options.

First, we could increase the threshold to about 2s even though that
would eliminate warnings on potentially slow tests. However, this
would point out the slowest tests.

Second, we could change this to warn users only when they choose by
making this a configurable option or making this a script to output a
list of all unmarked slow tests.

Third, we could leave this as is. As the KUnit warnings do not show up
in the kunit.py output and do not cause the test to fail in any way
they are relatively harmless if they are unwanted by the user.

Not quite sure which I prefer? The second option might be the cleanest
for the user and the time threshold could even be customizable. Let me
know what you think.

> ---
>  lib/kunit/test.c | 16 
>  1 file changed, 16 insertions(+)
>
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index 49698a168437..a3b924501f3d 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -379,6 +379,9 @@ static void kunit_run_case_internal(struct kunit *test,
> struct kunit_suite *suite,
> struct kunit_case *test_case)
>  {
> +   struct timespec64 start, end;
> +   struct timespec64 duration;
> +
> if (suite->init) {
> int ret;
>
> @@ -390,7 +393,20 @@ static void kunit_run_case_internal(struct kunit *test,
> }
> }
>
> +   ktime_get_ts64(&start);
> +
> test_case->run_case(test);
> +
> +   ktime_get_ts64(&end);
> +
> +   duration = timespec64_sub(end, start);
> +
> +   if (duration.tv_sec >= 1 &&
> +   (test_case->attr.speed == KUNIT_SPEED_UNSET ||
> +test_case->attr.speed >= KUNIT_SPEED_NORMAL))
> +   kunit_warn(test,
> +  "Test should be marked slow (runtime: 
> %lld.%09lds)",
> +  duration.tv_sec, duration.tv_nsec);

I would consider moving this if statement into a separate function.

>  }
>
>  static void kunit_case_internal_cleanup(struct kunit *test)
>
> --
> 2.41.0
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/20230911-kms-slow-tests-v1-1-d3800a69a1a1%40kernel.org.


Re: [PATCH 1/4] kunit: Fix missed memory release in kunit_free_suite_set()

2023-09-19 Thread Rae Moar
On Thu, Sep 14, 2023 at 7:47 AM 'Jinjie Ruan' via KUnit Development
 wrote:
>
> modprobe cpumask_kunit and rmmod cpumask_kunit, kmemleak detect
> a suspected memory leak as below.
>
> If kunit_filter_suites() in kunit_module_init() succeeds, the
> suite_set.start will not be NULL and the kunit_free_suite_set() in
> kunit_module_exit() should free all the memory which has not
> been freed. However the test_cases in suites is left out.
>
> unreferenced object 0x54ac47e83200 (size 512):
>   comm "modprobe", pid 592, jiffies 4294913238 (age 1367.612s)
>   hex dump (first 32 bytes):
> 84 13 1a f0 d3 b6 ff ff 30 68 1a f0 d3 b6 ff ff  0h..
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>   backtrace:
> [<8dec63a2>] slab_post_alloc_hook+0xb8/0x368
> [<ec280d8e>] __kmem_cache_alloc_node+0x174/0x290
> [<896c7740>] __kmalloc+0x60/0x2c0
> [<7a50fa06>] kunit_filter_suites+0x254/0x5b8
> [<78cc98e2>] kunit_module_notify+0xf4/0x240
> [<33cea952>] notifier_call_chain+0x98/0x17c
> [<973d05cc>] notifier_call_chain_robust+0x4c/0xa4
> [<5f95895f>] blocking_notifier_call_chain_robust+0x4c/0x74
> [<48e36fa7>] load_module+0x1a2c/0x1c40
> [<04eb8a91>] init_module_from_file+0x94/0xcc
> [<37dbba28>] idempotent_init_module+0x184/0x278
> [<161b75cb>] __arm64_sys_finit_module+0x68/0xa8
> [<6dc1669b>] invoke_syscall+0x44/0x100
> [<fa87e304>] el0_svc_common.constprop.1+0x68/0xe0
> [<9d8ad866>] do_el0_svc+0x1c/0x28
> [<5b83c607>] el0_svc+0x3c/0xc4
>
> Fixes: e5857d396f35 ("kunit: flatten kunit_suite*** to kunit_suite** in 
> .kunit_test_suites")
> Fixes: b67abaad4d25 ("kunit: Allow kunit test modules to use test filtering")
> Signed-off-by: Jinjie Ruan 

Hello!

This looks good to me.

Reviewed-by: Rae Moar 

Thanks!

-Rae

> ---
>  lib/kunit/executor.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
> index a6348489d45f..a037a46fae5e 100644
> --- a/lib/kunit/executor.c
> +++ b/lib/kunit/executor.c
> @@ -137,8 +137,10 @@ void kunit_free_suite_set(struct kunit_suite_set 
> suite_set)
>  {
> struct kunit_suite * const *suites;
>
> -   for (suites = suite_set.start; suites < suite_set.end; suites++)
> +   for (suites = suite_set.start; suites < suite_set.end; suites++) {
> +   kfree((*suites)->test_cases);
> kfree(*suites);
> +   }
> kfree(suite_set.start);
>  }
>
> --
> 2.34.1
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/20230914114629.1517650-2-ruanjinjie%40huawei.com.


Re: [PATCH 2/4] kunit: Fix the wrong kfree of copy for kunit_filter_suites()

2023-09-19 Thread Rae Moar
On Thu, Sep 14, 2023 at 7:47 AM 'Jinjie Ruan' via KUnit Development
 wrote:
>
> If the outer layer for loop is iterated more than once and it fails not
> in the first iteration, the copy pointer has been moved. So it should free
> the original copy's backup copy_start.
>
> Fixes: abbf73816b6f ("kunit: fix possible memory leak in 
> kunit_filter_suites()")
> Signed-off-by: Jinjie Ruan 

Hello!

This looks good to me as well.

Reviewed-by: Rae Moar 

Thanks!

-Rae

> ---
>  lib/kunit/executor.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
> index a037a46fae5e..9358ed2df839 100644
> --- a/lib/kunit/executor.c
> +++ b/lib/kunit/executor.c
> @@ -243,7 +243,7 @@ kunit_filter_suites(const struct kunit_suite_set 
> *suite_set,
>
>  free_copy:
> if (*err)
> -   kfree(copy);
> +   kfree(copy_start);
>
> return filtered;
>  }
> --
> 2.34.1
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/20230914114629.1517650-3-ruanjinjie%40huawei.com.


Re: [PATCH 3/4] kunit: Fix possible memory leak in kunit_filter_suites()

2023-09-19 Thread Rae Moar
On Thu, Sep 14, 2023 at 7:47 AM 'Jinjie Ruan' via KUnit Development
 wrote:
>
> If the outer layer for loop is iterated more than once and it fails not
> in the first iteration, the filtered_suite and filtered_suite->test_cases
> allocated in the last kunit_filter_attr_tests() in last inner for loop
> is leaked.
>
> So add a new free_filtered_suite err label and free the filtered_suite
> and filtered_suite->test_cases so far. And change kmalloc_array of copy
> to kcalloc to Clear the copy to make the kfree safe.
>
> Fixes: 5d31f71efcb6 ("kunit: add kunit.filter_glob cmdline option to filter 
> suites")
> Fixes: 529534e8cba3 ("kunit: Add ability to filter attributes")
> Signed-off-by: Jinjie Ruan 

Hello!

This looks good to me. I just have one comment below.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
>  lib/kunit/executor.c | 17 +
>  1 file changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
> index 9358ed2df839..1236b3cd2fbb 100644
> --- a/lib/kunit/executor.c
> +++ b/lib/kunit/executor.c
> @@ -157,10 +157,11 @@ kunit_filter_suites(const struct kunit_suite_set 
> *suite_set,
> struct kunit_suite_set filtered = {NULL, NULL};
> struct kunit_glob_filter parsed_glob;
> struct kunit_attr_filter *parsed_filters = NULL;
> +   struct kunit_suite * const *suites;
>
> const size_t max = suite_set->end - suite_set->start;
>
> -   copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
> +   copy = kcalloc(max, sizeof(*filtered.start), GFP_KERNEL);
> if (!copy) { /* won't be able to run anything, return an empty set */
> return filtered;
> }
> @@ -195,7 +196,7 @@ kunit_filter_suites(const struct kunit_suite_set 
> *suite_set,
> parsed_glob.test_glob);
> if (IS_ERR(filtered_suite)) {
> *err = PTR_ERR(filtered_suite);
> -   goto free_parsed_filters;
> +   goto free_filtered_suite;
> }
> }
> if (filter_count > 0 && parsed_filters != NULL) {
> @@ -212,11 +213,11 @@ kunit_filter_suites(const struct kunit_suite_set 
> *suite_set,
> filtered_suite = new_filtered_suite;
>
> if (*err)
> -   goto free_parsed_filters;
> +   goto free_filtered_suite;
>
> if (IS_ERR(filtered_suite)) {
> *err = PTR_ERR(filtered_suite);
> -   goto free_parsed_filters;
> +   goto free_filtered_suite;
> }
> if (!filtered_suite)
> break;
> @@ -231,6 +232,14 @@ kunit_filter_suites(const struct kunit_suite_set 
> *suite_set,
> filtered.start = copy_start;
> filtered.end = copy;
>
> +free_filtered_suite:
> +   if (*err) {
> +   for (suites = copy_start; suites < copy; suites++) {
> +   kfree((*suites)->test_cases);
> +   kfree(*suites);
> +   }
> +   }
> +

As this is pretty similar code to kunit_free_suite_set, I wish you
could use that method instead but I'm not actually sure it would be
cleaner.


>  free_parsed_filters:
> if (filter_count)
> kfree(parsed_filters);
> --
> 2.34.1
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/20230914114629.1517650-4-ruanjinjie%40huawei.com.


Re: [PATCH 4/4] kunit: test: Fix the possible memory leak in executor_test

2023-09-19 Thread Rae Moar
On Thu, Sep 14, 2023 at 7:47 AM 'Jinjie Ruan' via KUnit Development
 wrote:
>
> If kunit_filter_suites() succeeds, not only copy but also filtered_suite
> and filtered_suite->test_cases should be freed.
>
> So use kunit_free_suite_set() to free the filtered_suite,
> filtered_suite->test_cases and copy as kunit_module_exit() and
> kunit_run_all_tests() do it.
>
> Fixes: e5857d396f35 ("kunit: flatten kunit_suite*** to kunit_suite** in 
> .kunit_test_suites")
> Signed-off-by: Jinjie Ruan 

Hello!

This looks mostly good to me. But I have one notable comment. See below.

Thanks!
-Rae

> ---
>  lib/kunit/executor_test.c | 24 ++--
>  1 file changed, 18 insertions(+), 6 deletions(-)
>
> diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
> index b4f6f96b2844..987b81dce01e 100644
> --- a/lib/kunit/executor_test.c
> +++ b/lib/kunit/executor_test.c
> @@ -56,7 +56,6 @@ static void filter_suites_test(struct kunit *test)
> got = kunit_filter_suites(&suite_set, "suite2", NULL, NULL, &err);
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
> KUNIT_ASSERT_EQ(test, err, 0);
> -   kfree_at_end(test, got.start);
>
> /* Validate we just have suite2 */
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
> @@ -64,6 +63,9 @@ static void filter_suites_test(struct kunit *test)
>
> /* Contains one element (end is 1 past end) */
> KUNIT_ASSERT_EQ(test, got.end - got.start, 1);
> +
> +   if (!err)
> +   kunit_free_suite_set(got);

I definitely appreciate the change to free all of "got" rather than
just "got.start".

However, kfree_at_end used deferred actions to ensure the kfree would
occur at the end of the test. With this change, if the test fails the
suite set could not be freed.

Intead, is there any way to alter the function kfree_at_end (could be
renamed) to take in "got" and then use deferred actions to ensure
kunit_free_suite_set is called at the end of the test?

Let me know what you think about this.


>  }
>
>  static void filter_suites_test_glob_test(struct kunit *test)
> @@ -82,7 +84,6 @@ static void filter_suites_test_glob_test(struct kunit *test)
> got = kunit_filter_suites(&suite_set, "suite2.test2", NULL, NULL, 
> &err);
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
> KUNIT_ASSERT_EQ(test, err, 0);
> -   kfree_at_end(test, got.start);
>
> /* Validate we just have suite2 */
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
> @@ -93,6 +94,9 @@ static void filter_suites_test_glob_test(struct kunit *test)
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases);
> KUNIT_EXPECT_STREQ(test, (const char 
> *)got.start[0]->test_cases[0].name, "test2");
> KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].name);
> +
> +   if (!err)
> +   kunit_free_suite_set(got);
>  }
>
>  static void filter_suites_to_empty_test(struct kunit *test)
> @@ -109,10 +113,12 @@ static void filter_suites_to_empty_test(struct kunit 
> *test)
>
> got = kunit_filter_suites(&suite_set, "not_found", NULL, NULL, &err);
> KUNIT_ASSERT_EQ(test, err, 0);
> -   kfree_at_end(test, got.start); /* just in case */
>
> KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
> "should be empty to indicate no match");
> +
> +   if (!err)
> +   kunit_free_suite_set(got);
>  }
>
>  static void parse_filter_attr_test(struct kunit *test)
> @@ -172,7 +178,6 @@ static void filter_attr_test(struct kunit *test)
> got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err);
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
> KUNIT_ASSERT_EQ(test, err, 0);
> -   kfree_at_end(test, got.start);
>
> /* Validate we just have normal_suite */
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
> @@ -183,6 +188,9 @@ static void filter_attr_test(struct kunit *test)
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases);
> KUNIT_EXPECT_STREQ(test, got.start[0]->test_cases[0].name, "normal");
> KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].name);
> +
> +   if (!err)
> +   kunit_free_suite_set(got);
>  }
>
>  static void filter_attr_empty_test(struct kunit *test)
> @@ -200,10 +208,12 @@ static void filter_attr_empty_test(struct kunit *test)
>
> got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err);
> KUNIT_ASSERT_EQ(test, err, 0);
> -   kfree_at_end(test, got.start); /* just in case */
>
> KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
> "should be empty to indicate no match");
> +
> +   if (!err)
> +   kunit_free_suite_set(got);
>  }
>
>  static void filter_attr_skip_test(struct kunit *test)
> @@ -222,7 +232,6 @@ static void filter_attr_skip_test(struct kunit *test)
> got = kunit_filter_suites(&suite_set, NULL, filter

Re: [PATCH v2 4/4] kunit: test: Fix the possible memory leak in executor_test

2023-09-21 Thread Rae Moar
On Wed, Sep 20, 2023 at 9:41 PM 'Jinjie Ruan' via KUnit Development
 wrote:
>
> When CONFIG_KUNIT_ALL_TESTS=y, making CONFIG_DEBUG_KMEMLEAK=y and
> CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN=y, the below memory leak is detected.
>
> If kunit_filter_suites() succeeds, not only copy but also filtered_suite
> and filtered_suite->test_cases should be freed.
>
> So use kunit_free_suite_set() to free the filtered_suite,
> filtered_suite->test_cases and copy as kunit_module_exit() and
> kunit_run_all_tests() do it. And the func kfree_at_end() is not used so
> remove it. After applying this patch, the following memory leak is never
> detected.
>
> unreferenced object 0x8881001de400 (size 1024):
>   comm "kunit_try_catch", pid 1396, jiffies 4294720452 (age 932.801s)
>   hex dump (first 32 bytes):
> 73 75 69 74 65 32 00 00 00 00 00 00 00 00 00 00  suite2..
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>   backtrace:
> [] __kmalloc_node_track_caller+0x53/0x150
> [] kmemdup+0x22/0x50
> [] kunit_filter_suites+0x44d/0xcc0
> [] filter_suites_test+0x12f/0x360
> [] kunit_generic_run_threadfn_adapter+0x4a/0x90
> [] kthread+0x2b6/0x380
> [] ret_from_fork+0x2d/0x70
> [] ret_from_fork_asm+0x11/0x20
> unreferenced object 0x8881052cd388 (size 192):
>   comm "kunit_try_catch", pid 1396, jiffies 4294720452 (age 932.801s)
>   hex dump (first 32 bytes):
> a0 85 9e 82 ff ff ff ff 80 cd 7c 84 ff ff ff ff  ..|.
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>   backtrace:
> [] __kmalloc+0x52/0x150
> [] kunit_filter_suites+0x481/0xcc0
> [] filter_suites_test+0x12f/0x360
> [] kunit_generic_run_threadfn_adapter+0x4a/0x90
> [] kthread+0x2b6/0x380
> [] ret_from_fork+0x2d/0x70
> [] ret_from_fork_asm+0x11/0x20
>
> unreferenced object 0x888100da8400 (size 1024):
>   comm "kunit_try_catch", pid 1398, jiffies 4294720454 (age 781.945s)
>   hex dump (first 32 bytes):
> 73 75 69 74 65 32 00 00 00 00 00 00 00 00 00 00  suite2..
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>   backtrace:
> [] __kmalloc_node_track_caller+0x53/0x150
> [] kmemdup+0x22/0x50
> [] kunit_filter_suites+0x44d/0xcc0
> [] filter_suites_test_glob_test+0x12f/0x560
> [] kunit_generic_run_threadfn_adapter+0x4a/0x90
> [] kthread+0x2b6/0x380
> [] ret_from_fork+0x2d/0x70
> [] ret_from_fork_asm+0x11/0x20
> unreferenced object 0x888105117878 (size 96):
>   comm "kunit_try_catch", pid 1398, jiffies 4294720454 (age 781.945s)
>   hex dump (first 32 bytes):
> a0 85 9e 82 ff ff ff ff a0 ac 7c 84 ff ff ff ff  ..|.
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>   backtrace:
> [] __kmalloc+0x52/0x150
> [] kunit_filter_suites+0x481/0xcc0
> [] filter_suites_test_glob_test+0x12f/0x560
> [] kunit_generic_run_threadfn_adapter+0x4a/0x90
> [] kthread+0x2b6/0x380
> [] ret_from_fork+0x2d/0x70
> [] ret_from_fork_asm+0x11/0x20
> unreferenced object 0x888102c31c00 (size 1024):
>   comm "kunit_try_catch", pid 1404, jiffies 4294720460 (age 781.948s)
>   hex dump (first 32 bytes):
> 6e 6f 72 6d 61 6c 5f 73 75 69 74 65 00 00 00 00  normal_suite
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>   backtrace:
> [] __kmalloc_node_track_caller+0x53/0x150
> [] kmemdup+0x22/0x50
> [] kunit_filter_attr_tests+0xf7/0x860
> [] kunit_filter_suites+0x82f/0xcc0
> [] filter_attr_test+0x195/0x5f0
> [] kunit_generic_run_threadfn_adapter+0x4a/0x90
> [] kthread+0x2b6/0x380
> [] ret_from_fork+0x2d/0x70
> [] ret_from_fork_asm+0x11/0x20
> unreferenced object 0x8881052cd250 (size 192):
>   comm "kunit_try_catch", pid 1404, jiffies 4294720460 (age 781.948s)
>   hex dump (first 32 bytes):
> a0 85 9e 82 ff ff ff ff 00 a9 7c 84 ff ff ff ff  ..|.
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>   backtrace:
> [] __kmalloc+0x52/0x150
> [] kunit_filter_attr_tests+0x1a1/0x860
> [] kunit_filter_suites+0x82f/0xcc0
> [] filter_attr_test+0x195/0x5f0
> [] kunit_generic_run_threadfn_adapter+0x4a/0x90
> [] kthread+0x2b6/0x380
> [] ret_from_fork+0x2d/0x70
> [] ret_from_fork_asm+0x11/0x20
> unreferenced object 0x888104f4e400 (size 1024):
>   comm "kunit_try_catch", pid 1408, jiffies 4294720464 (age 781.944s)
>   hex dump (first 32 bytes):
> 73 75 69 74 65 00 00 00 00 00 00 00 00 00 00 00  suite...
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>   backtrace:
> [] __kmalloc_node_track_caller+0x53/0x150
> [] kmemdup+0x22/0x50
> [] kunit_filter_attr_tests+0xf7/0x860
> [] kunit_filter_suites+0x82f/0xcc0
> [] filter_attr_skip_test+0x133/0x6e0
> [] kunit_generic_run_threadfn_adapter+0x4a/0x90
> [] kthread+0x2b6/0x380
> [] ret_from_fork+0x2d/0x70
> [] re

Re: [PATCH] kunit: debugfs: Handle errors from alloc_string_stream()

2023-09-27 Thread Rae Moar
On Wed, Sep 27, 2023 at 12:51 PM 'Richard Fitzgerald' via KUnit
Development  wrote:
>
> In kunit_debugfs_create_suite() give up and skip creating the debugfs
> file if any of the alloc_string_stream() calls return an error or NULL.
> Only put a value in the log pointer of kunit_suite and kunit_test if it
> is a valid pointer to a log.
>
> This prevents the potential invalid dereference reported by smatch:
>
>  lib/kunit/debugfs.c:115 kunit_debugfs_create_suite() error: 'suite->log'
> dereferencing possible ERR_PTR()
>  lib/kunit/debugfs.c:119 kunit_debugfs_create_suite() error: 'test_case->log'
> dereferencing possible ERR_PTR()
>
> Signed-off-by: Richard Fitzgerald 
> Reported-by: Dan Carpenter 
> Fixes: 05e2006ce493 ("kunit: Use string_stream for test log")

Hi!

I've tested this and this all looks good to me.

Reviewed-by: Rae Moar 

Thanks!
Rae

> ---
>  lib/kunit/debugfs.c | 29 -
>  1 file changed, 24 insertions(+), 5 deletions(-)
>
> diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
> index 270d185737e6..73075ca6e88c 100644
> --- a/lib/kunit/debugfs.c
> +++ b/lib/kunit/debugfs.c
> @@ -109,14 +109,27 @@ static const struct file_operations 
> debugfs_results_fops = {
>  void kunit_debugfs_create_suite(struct kunit_suite *suite)
>  {
> struct kunit_case *test_case;
> +   struct string_stream *stream;
>
> -   /* Allocate logs before creating debugfs representation. */
> -   suite->log = alloc_string_stream(GFP_KERNEL);
> -   string_stream_set_append_newlines(suite->log, true);
> +   /*
> +* Allocate logs before creating debugfs representation.
> +* The log pointer must be NULL if there isn't a log so only
> +* set it if the log stream was created successfully.
> +*/
> +   stream = alloc_string_stream(GFP_KERNEL);
> +   if (IS_ERR_OR_NULL(stream))
> +   goto err;
> +
> +   string_stream_set_append_newlines(stream, true);
> +   suite->log = stream;
>
> kunit_suite_for_each_test_case(suite, test_case) {
> -   test_case->log = alloc_string_stream(GFP_KERNEL);
> -   string_stream_set_append_newlines(test_case->log, true);
> +   stream = alloc_string_stream(GFP_KERNEL);
> +   if (IS_ERR_OR_NULL(stream))
> +   goto err;
> +
> +   string_stream_set_append_newlines(stream, true);
> +   test_case->log = stream;
> }
>
> suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir);
> @@ -124,6 +137,12 @@ void kunit_debugfs_create_suite(struct kunit_suite 
> *suite)
> debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444,
> suite->debugfs,
> suite, &debugfs_results_fops);
> +   return;
> +
> +err:
> +   string_stream_destroy(suite->log);
> +   kunit_suite_for_each_test_case(suite, test_case)
> +   string_stream_destroy(test_case->log);
>  }
>
>  void kunit_debugfs_destroy_suite(struct kunit_suite *suite)
> --
> 2.30.2
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/20230927165058.29484-1-rf%40opensource.cirrus.com.


Re: [PATCH 1/4] kunit: Drop redundant text from suite init failure message

2023-09-28 Thread Rae Moar
On Mon, Sep 25, 2023 at 1:58 PM Michal Wajdeczko
 wrote:
>
> If a suite initialization fails, then our diagnostic message
> will include redundant indent and hash sign as all this was
> already added by the kunit_printk() used by kunit_err() macro.
>
> This could be easily seen if we force some error in our example
> test by modyfing example_test_init_suite() and running:
>
> $ ./tools/testing/kunit/kunit.py run --raw_output \
> --kunitconfig ./lib/kunit/.kunitconfig "example.*"
>
> KTAP version 1
> 1..1
> # example: initializing suite
> # example: # failed to initialize (-19)
> not ok 1 example
>
> Fix that and while around improve error code reporting by using
> error pointer format %pe that gives more user friendly output:
>
> KTAP version 1
> 1..1
> # example: initializing suite
> # example: failed to initialize (-ENODEV)
> not ok 1 example
>
> Signed-off-by: Michal Wajdeczko 
> Cc: David Gow 
> Cc: Rae Moar 

Hello!

This change looks good to me.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
>  lib/kunit/test.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index f2eb71f1a66c..fb5981ce578d 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -568,8 +568,8 @@ int kunit_run_tests(struct kunit_suite *suite)
> if (suite->suite_init) {
> suite->suite_init_err = suite->suite_init(suite);
> if (suite->suite_init_err) {
> -   kunit_err(suite, KUNIT_SUBTEST_INDENT
> - "# failed to initialize (%d)", 
> suite->suite_init_err);
> +   kunit_err(suite, "failed to initialize (%pe)",
> + ERR_PTR(suite->suite_init_err));
> goto suite_end;
> }
> }
> --
> 2.25.1
>


Re: [PATCH 2/4] kunit: Fix indentation level of suite messages

2023-09-28 Thread Rae Moar
On Mon, Sep 25, 2023 at 1:58 PM Michal Wajdeczko
 wrote:
>
> A kunit suite is a top level test from the KTAP point of view but
> all suite diagnostic messages are printed at the subtest level:
>
> $ ./tools/testing/kunit/kunit.py run --raw_output \
> --kunitconfig ./lib/kunit/.kunitconfig "example.*simple*"
>
> KTAP version 1
> 1..1
> # example: initializing suite
> # example: failed to initialize (-ENODEV)
> not ok 1 example
>
> KTAP version 1
> 1..1
> # example: initializing suite
> KTAP version 1
> # Subtest: example
> # module: kunit_example_test
> 1..1
> # example_simple_test: initializing
> # example_simple_test: cleaning up
> ok 1 example_simple_test
> # example: exiting suite
> ok 1 example
>
> Replace hardcoded indent in kunit_printk() with flexible
> indentation based on the argument type (test or suite):
>
> KTAP version 1
> 1..1
> # example: initializing suite
> # example: failed to initialize (-ENODEV)
> not ok 1 example
>
> KTAP version 1
> 1..1
> # example: initializing suite
> KTAP version 1
> # Subtest: example
> # module: kunit_example_test
> 1..1
> # example_simple_test: initializing
> # example_simple_test: cleaning up
> ok 1 example_simple_test
> # example: exiting suite
> ok 1 example

Hi!

I am happy to see this change to improve the indentation of
parameterized tests. It has been bugging me for a bit. This seems to
be working well but I just had a few comments to potentially discuss.

Thanks!

-Rae

>
> Signed-off-by: Michal Wajdeczko 
> Cc: David Gow 
> Cc: Rae Moar 
> ---
>  include/kunit/test.h | 24 ++--
>  lib/kunit/test.c |  7 ---
>  2 files changed, 22 insertions(+), 9 deletions(-)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index 20ed9f9275c9..158876c4cb43 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -509,6 +509,21 @@ void __printf(2, 3) kunit_log_append(struct 
> string_stream *log, const char *fmt,
> kunit_try_catch_throw(&((test_or_suite)->try_catch));   \
> } while (0)
>
> +/* Currently supported test levels */
> +enum {
> +   KUNIT_LEVEL_SUITE = 0,
> +   KUNIT_LEVEL_CASE,
> +   KUNIT_LEVEL_CASE_PARAM,
> +};

I do find this slightly confusing to have a KUNIT_LEVEL_SUITE as the
suite output occurs on multiple levels. Plus, I also don't see any
uses of the SUITE level or the PARAM level anymore. Do you have any
ideas on this?

We could consider just using the test->level field introduced in the
next patch to manage the levels. Or I wouldn't mind keeping this just
for clarity?

> +
> +#define kunit_level(test_or_suite) \
> +   _Generic((test_or_suite),   \
> +struct kunit_suite * : KUNIT_LEVEL_SUITE,  \
> +struct kunit * : KUNIT_LEVEL_CASE)
> +

I am not super familiar with using _Generic so I would want David's opinion.

Also I can think of cases where it would be helpful to add an option
for struct kunit_case *, however, that may be an addition for the
future.

And then additionally, this macro seems to be only used for the struct
kunit * case. Will we plan to use this in the future for suites?

> +#define kunit_indent_level(test_or_suite)  \
> +   (KUNIT_INDENT_LEN * kunit_level(test_or_suite))
> +
>  /*
>   * printk and log to per-test or per-suite log buffer.  Logging only done
>   * if CONFIG_KUNIT_DEBUGFS is 'y'; if it is 'n', no log is allocated/used.
> @@ -520,9 +535,14 @@ void __printf(2, 3) kunit_log_append(struct 
> string_stream *log, const char *fmt,
>  ##__VA_ARGS__);\
> } while (0)
>
> +#define kunit_log_indent(lvl, test_or_suite, fmt, ...) \
> +   kunit_log(lvl, test_or_suite, "%*s" fmt,\
> + kunit_indent_level(test_or_suite), "",\
> + ##__VA_ARGS__)
> +
>  #define kunit_printk(lvl, test, fmt, ...)  \
> -   kunit_log(lvl, test, KUNIT_SUBTEST_INDENT "# %s: " fmt, \
> - (test)->name, ##__VA_ARGS__)
> +   kunit_log_indent(lvl, test, "# %s: " fmt,   \
> +(test)->name, ##__VA_ARGS__)
>

I wonder if we could consider removing the need to use

Re: [PATCH 3/4] kunit: Fix indentation of parameterized tests messages

2023-09-28 Thread Rae Moar
On Mon, Sep 25, 2023 at 1:58 PM Michal Wajdeczko
 wrote:
>
> When running parametrized test cases, diagnostic messages
> are not properly aligned with the test result lines:
>
> $ ./tools/testing/kunit/kunit.py run --raw_output \
> --kunitconfig ./lib/kunit/.kunitconfig *.example_params*
>
> KTAP version 1
> 1..1
> # example: initializing suite
> KTAP version 1
> # Subtest: example
> # module: kunit_example_test
> 1..1
> KTAP version 1
> # Subtest: example_params_test
> # example_params_test: initializing
> # example_params_test: cleaning up
> ok 1 example value 3 # SKIP unsupported param value 3
> # example_params_test: initializing
> # example_params_test: cleaning up
> ok 2 example value 2
> # example_params_test: initializing
> # example_params_test: cleaning up
> ok 3 example value 1
> # example_params_test: initializing
> # example_params_test: cleaning up
> ok 4 example value 0 # SKIP unsupported param value 0
> # example_params_test: pass:2 fail:0 skip:2 total:4
> ok 1 example_params_test
> # example: exiting suite
> # Totals: pass:2 fail:0 skip:2 total:4
> ok 1 example
>
> Add test level attribute and use it to generate proper indent
> at the runtime:
>
> KTAP version 1
> 1..1
> # example: initializing suite
> KTAP version 1
> # Subtest: example
> # module: kunit_example_test
> 1..1
> KTAP version 1
> # Subtest: example_params_test
> # example_params_test: initializing
> # example_params_test: cleaning up
> ok 1 example value 3 # SKIP unsupported param value 3
> # example_params_test: initializing
> # example_params_test: cleaning up
> ok 2 example value 2
> # example_params_test: initializing
> # example_params_test: cleaning up
> ok 3 example value 1
> # example_params_test: initializing
> # example_params_test: cleaning up
> ok 4 example value 0 # SKIP unsupported param value 0
> # example_params_test: pass:2 fail:0 skip:2 total:4
> ok 1 example_params_test
> # example: exiting suite
> # Totals: pass:2 fail:0 skip:2 total:4
> ok 1 example
>
> Signed-off-by: Michal Wajdeczko 
> Cc: David Gow 
> Cc: Rae Moar 

Hello!

Great to see these changes! Just a few comments below.

Thanks!
-Rae

> ---
>  include/kunit/test.h |  3 ++-
>  lib/kunit/test.c | 52 
>  2 files changed, 26 insertions(+), 29 deletions(-)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index 158876c4cb43..4804d539e10f 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -276,6 +276,7 @@ struct kunit {
> void *priv;
>
> /* private: internal use only. */
> +   unsigned int level; /* Helps in proper log indent */
> const char *name; /* Read only after initialization! */
> struct string_stream *log; /* Points at case log after initialization 
> */
> struct kunit_try_catch try_catch;
> @@ -519,7 +520,7 @@ enum {
>  #define kunit_level(test_or_suite) \
> _Generic((test_or_suite),   \
>  struct kunit_suite * : KUNIT_LEVEL_SUITE,  \
> -struct kunit * : KUNIT_LEVEL_CASE)
> +struct kunit * : ((struct kunit *)(test_or_suite))->level)
>
>  #define kunit_indent_level(test_or_suite)  \
> (KUNIT_INDENT_LEN * kunit_level(test_or_suite))
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index d10e6d610e20..43c3efc286e4 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -99,14 +99,13 @@ static void kunit_print_test_stats(struct kunit *test,
> if (!kunit_should_print_stats(stats))
> return;
>
> -   kunit_log(KERN_INFO, test,
> - KUNIT_SUBTEST_INDENT
> - "# %s: pass:%lu fail:%lu skip:%lu total:%lu",
> - test->name,
> - stats.passed,
> - stats.failed,
> - stats.skipped,
> - stats.total);
> +   kunit_log_indent(KERN_INFO, test,
> +"# %s: pass:%lu fail:%lu skip:%lu total:%lu",
> +test->name,
> +stats.passed,

Re: [PATCH 4/4] kunit: Prepare test plan for parameterized subtests

2023-09-28 Thread Rae Moar
On Mon, Sep 25, 2023 at 1:58 PM Michal Wajdeczko
 wrote:
>
> In case of parameterized tests we are not providing a test plan
> so we can't detect if any result is missing.
>
> Count available params using the same generator as during a test
> execution
>
> Signed-off-by: Michal Wajdeczko 
> Cc: David Gow 
> Cc: Rae Moar 
> ---
>  lib/kunit/test.c | 16 
>  1 file changed, 16 insertions(+)
>
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index 43c3efc286e4..55eabb324f39 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -540,6 +540,20 @@ static void kunit_accumulate_stats(struct 
> kunit_result_stats *total,
> total->total += add.total;
>  }
>
> +static size_t count_test_case_params(struct kunit_case *test_case)
> +{
> +   char param_desc[KUNIT_PARAM_DESC_SIZE];
> +   const void *param_value = NULL;
> +   size_t num = 0;
> +
> +   if (test_case->generate_params)
> +   while ((param_value = test_case->generate_params(param_value,
> +param_desc)))
> +   num++;
> +
> +   return num;
> +}
> +

Hello!

This change largely looks good to me. However, I am not 100 percent
confident that the function to generate parameters always produces the
same output (or same number of test cases). I would be interested in
David's opinion on this.

Otherwise it seems to work well!

Thanks!
-Rae

>  int kunit_run_tests(struct kunit_suite *suite)
>  {
> char param_desc[KUNIT_PARAM_DESC_SIZE];
> @@ -585,6 +599,8 @@ int kunit_run_tests(struct kunit_suite *suite)
> test_case->status = KUNIT_SKIPPED;
> kunit_log_indent(KERN_INFO, &test, "KTAP version 
> 1\n");
> kunit_log_indent(KERN_INFO, &test, "# Subtest: %s", 
> test_case->name);
> +   kunit_log_indent(KERN_INFO, &test, "1..%zd\n",
> +count_test_case_params(test_case));
>
> while (test.param_value) {
> kunit_run_case_catch_errors(suite, test_case, 
> &test);
> --
> 2.25.1
>


Re: [PATCH 1/2] kunit: Add param generator macro for zero terminated arrays

2023-09-29 Thread Rae Moar
On Tue, Sep 26, 2023 at 6:02 PM Michal Wajdeczko
 wrote:
>
> The existing macro KUNIT_ARRAY_PARAM can produce parameter
> generator function but only when we fully know the definition
> of the array. However, there might be cases where we would like
> to generate test params based on externaly defined array, which
> is defined as zero-terminated array, like pci_driver.id_table.
>
> Add helper macro KUNIT_ZERO_ARRAY_PARAM that can work with zero
> terminated arrays and provide example how to use it.
>
> $ ./tools/testing/kunit/kunit.py run \
> --kunitconfig ./lib/kunit/.kunitconfig *.example_params*
>
> [ ] Starting KUnit Kernel (1/1)...
> [ ] 
> [ ] = example  =
> [ ] === example_params_test  ===
> [ ] [SKIPPED] example value 3
> [ ] [PASSED] example value 2
> [ ] [PASSED] example value 1
> [ ] [SKIPPED] example value 0
> [ ] === [PASSED] example_params_test ===
> [ ] === example_params_test  ===
> [ ] [SKIPPED] example value 3
> [ ] [PASSED] example value 2
> [ ] [PASSED] example value 1
> [ ] === [PASSED] example_params_test ===
> [ ] = [PASSED] example =
> [ ] 
> [ ] Testing complete. Ran 7 tests: passed: 4, skipped: 3
>
> Signed-off-by: Michal Wajdeczko 
> Cc: David Gow 
> Cc: Rae Moar 
> ---
>  include/kunit/test.h   | 22 ++
>  lib/kunit/kunit-example-test.c |  2 ++
>  2 files changed, 24 insertions(+)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index 20ed9f9275c9..280113ceb6a6 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -1514,6 +1514,28 @@ do {   
>  \
> return NULL;  
>   \
> }
>
> +/**
> + * KUNIT_ZERO_ARRAY_PARAM() - Define test parameter generator from a zero 
> terminated array.
> + * @name:  prefix for the test parameter generator function.
> + * @array: zero terminated array of test parameters.
> + * @get_desc: function to convert param to description; NULL to use default
> + *
> + * Define function @name_gen_params which uses zero terminated @array to 
> generate parameters.
> + */
> +#define KUNIT_ZERO_ARRAY_PARAM(name, array, get_desc)
>   \
> +   static const void *name##_gen_params(const void *prev, char *desc)
>   \
> +   { 
>   \
> +   typeof((array)[0]) *__prev = prev;
>   \
> +   typeof(__prev) __next = __prev ? __prev + 1 : (array);
>   \
> +   void (*__get_desc)(typeof(__next), char *) = get_desc;
>   \
> +   for (; memchr_inv(__next, 0, sizeof(*__next)); __prev = 
> __next++) { \
> +   if (__get_desc)   
>   \
> +   __get_desc(__next, desc); 
>   \
> +   return __next;
>   \
> +   } 
>   \
> +   return NULL;  
>   \
> +   }
> +

Hello!

This overall looks good to me. I am not sure how many uses there are
for zero-terminated arrays for parameterized tests.

However, since it seems to be a well designed feature, I think it
should be good to add this to KUnit.

Thanks for including an example! Just one other comment below.

-Rae

>  // TODO(dlaty...@google.com): consider eventually migrating users to 
> explicitly
>  // include resource.h themselves if they need it.
>  #include 
> diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
> index 6bb5c2ef6696..ad9ebcfd513e 100644
> --- a/lib/kunit/kunit-example-test.c
> +++ b/lib/kunit/kunit-example-test.c
> @@ -202,6 +202,7 @@ static void example_param_get_desc(const struct 
> example_param *p, char *desc)
>  }
>
>  KUNIT_ARRAY_PARAM(example, example_params_array, example_param_get_desc);
> +KUNIT_ZERO_ARRAY_PARAM(example_zero, example_params_array, 
> example_param_get_desc);
>
>  /*
>

Re: [PATCH 2/2] kunit: Allow to filter entries from zero terminated arrays

2023-09-29 Thread Rae Moar
On Tue, Sep 26, 2023 at 6:02 PM Michal Wajdeczko
 wrote:
>
> In some cases we may want to generate params based on existing
> zero terminated array, but with some entries filtered out.
> Extend macro KUNIT_ZERO_ARRAY_PARAM to accept filter function
> and provide example how to use it.

Hello!

I definitely understand the use case of wanting to filter params.
However, since this is a static filter, it seems this could be done in
the test file and rather than implemented as a new KUnit feature.

I would be interested to see David's thoughts on this. If we do decide
to implement this as a KUnit feature, I would also prefer if the
filtering ability is available for both the zero-terminated param
arrays and normal param arrays.

Otherwise I just have one comment below. Let me know what you think.

Thanks!
-Rae

>
> $ ./tools/testing/kunit/kunit.py run \
> --kunitconfig ./lib/kunit/.kunitconfig *.example_params*
>
> [ ] Starting KUnit Kernel (1/1)...
> [ ] 
> [ ] = example  =
> [ ] === example_params_test  ===
> [ ] [SKIPPED] example value 3
> [ ] [PASSED] example value 2
> [ ] [PASSED] example value 1
> [ ] [SKIPPED] example value 0
> [ ] === [PASSED] example_params_test ===
> [ ] === example_params_test  ===
> [ ] [SKIPPED] example value 3
> [ ] [PASSED] example value 2
> [ ] [PASSED] example value 1
> [ ] === [PASSED] example_params_test ===
> [ ] === example_params_test  ===
> [ ] [PASSED] example value 2
> [ ] [PASSED] example value 1
> [ ] === [PASSED] example_params_test ===
> [ ] = [PASSED] example =
> [ ] 
> [ ] Testing complete. Ran 9 tests: passed: 6, skipped: 3
>
> Signed-off-by: Michal Wajdeczko 
> Cc: David Gow 
> Cc: Rae Moar 
> ---
>  include/kunit/test.h   | 19 +--
>  lib/kunit/kunit-example-test.c |  9 +
>  2 files changed, 26 insertions(+), 2 deletions(-)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index 280113ceb6a6..8a87d1ce37e0 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -1515,20 +1515,24 @@ do {  
>  \
> }
>
>  /**
> - * KUNIT_ZERO_ARRAY_PARAM() - Define test parameter generator from a zero 
> terminated array.
> + * KUNIT_FILTERED_ZERO_ARRAY_PARAM() - Define test parameter generator from 
> a zero terminated array.
>   * @name:  prefix for the test parameter generator function.
>   * @array: zero terminated array of test parameters.
>   * @get_desc: function to convert param to description; NULL to use default
> + * @filter: function to filter out unwanted params (like duplicates); can be 
> NULL
>   *
>   * Define function @name_gen_params which uses zero terminated @array to 
> generate parameters.
>   */
> -#define KUNIT_ZERO_ARRAY_PARAM(name, array, get_desc)
>   \
> +#define KUNIT_FILTERED_ZERO_ARRAY_PARAM(name, array, get_desc, filter)   
>   \
> static const void *name##_gen_params(const void *prev, char *desc)
>   \
> { 
>   \
> typeof((array)[0]) *__prev = prev;
>   \
> typeof(__prev) __next = __prev ? __prev + 1 : (array);
>   \
> void (*__get_desc)(typeof(__next), char *) = get_desc;
>   \
> +   bool (*__filter)(typeof(__prev), typeof(__next)) = filter;
>   \
> for (; memchr_inv(__next, 0, sizeof(*__next)); __prev = 
> __next++) { \
> +   if (__filter && !__filter(__prev, __next))
>   \
> +   continue; 
>   \
> if (__get_desc)   
>   \
> __get_desc(__next, desc); 
>   \
> return __next;
>   \
> @@ -1536,6 +1540,17 @@ do {   
>  \
> return NULL;  

Re: [PATCH 2/4] kunit: Fix indentation level of suite messages

2023-10-03 Thread Rae Moar
On Mon, Oct 2, 2023 at 9:42 AM Michal Wajdeczko
 wrote:
>
>
>
> On 28.09.2023 22:52, Rae Moar wrote:
> > On Mon, Sep 25, 2023 at 1:58 PM Michal Wajdeczko
> >  wrote:
> >>
> >> A kunit suite is a top level test from the KTAP point of view but
> >> all suite diagnostic messages are printed at the subtest level:
> >>
> >> $ ./tools/testing/kunit/kunit.py run --raw_output \
> >> --kunitconfig ./lib/kunit/.kunitconfig "example.*simple*"
> >>
> >> KTAP version 1
> >> 1..1
> >> # example: initializing suite
> >> # example: failed to initialize (-ENODEV)
> >> not ok 1 example
> >>
> >> KTAP version 1
> >> 1..1
> >> # example: initializing suite
> >> KTAP version 1
> >> # Subtest: example
> >> # module: kunit_example_test
> >> 1..1
> >> # example_simple_test: initializing
> >> # example_simple_test: cleaning up
> >> ok 1 example_simple_test
> >> # example: exiting suite
> >> ok 1 example
> >>
> >> Replace hardcoded indent in kunit_printk() with flexible
> >> indentation based on the argument type (test or suite):
> >>
> >> KTAP version 1
> >> 1..1
> >> # example: initializing suite
> >> # example: failed to initialize (-ENODEV)
> >> not ok 1 example
> >>
> >> KTAP version 1
> >> 1..1
> >> # example: initializing suite
> >> KTAP version 1
> >> # Subtest: example
> >> # module: kunit_example_test
> >> 1..1
> >> # example_simple_test: initializing
> >> # example_simple_test: cleaning up
> >> ok 1 example_simple_test
> >> # example: exiting suite
> >> ok 1 example
> >
> > Hi!
> >
> > I am happy to see this change to improve the indentation of
> > parameterized tests. It has been bugging me for a bit. This seems to
> > be working well but I just had a few comments to potentially discuss.
> >
> > Thanks!
> >
> > -Rae
> >

Hello!

Thanks for getting back to me.

> >>
> >> Signed-off-by: Michal Wajdeczko 
> >> Cc: David Gow 
> >> Cc: Rae Moar 
> >> ---
> >>  include/kunit/test.h | 24 ++--
> >>  lib/kunit/test.c |  7 ---
> >>  2 files changed, 22 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/include/kunit/test.h b/include/kunit/test.h
> >> index 20ed9f9275c9..158876c4cb43 100644
> >> --- a/include/kunit/test.h
> >> +++ b/include/kunit/test.h
> >> @@ -509,6 +509,21 @@ void __printf(2, 3) kunit_log_append(struct 
> >> string_stream *log, const char *fmt,
> >> kunit_try_catch_throw(&((test_or_suite)->try_catch));   \
> >> } while (0)
> >>
> >> +/* Currently supported test levels */
> >> +enum {
> >> +   KUNIT_LEVEL_SUITE = 0,
> >> +   KUNIT_LEVEL_CASE,
> >> +   KUNIT_LEVEL_CASE_PARAM,
> >> +};
> >
> > I do find this slightly confusing to have a KUNIT_LEVEL_SUITE as the
> > suite output occurs on multiple levels. Plus, I also don't see any
> > uses of the SUITE level or the PARAM level anymore. Do you have any
> > ideas on this?
>
> This enum was just promoted as-is from the test.c as I didn't want to
> use magic 0 or 1 in below kunit_level() macro.
>
> Note that the KUNIT_LEVEL_SUITE is now used indirectly whenever you call
> any of kunit_printk() with suite param like here:
>
> ./kunit-example-test.c:60:  kunit_info(suite, "initializing suite\n");
> ./kunit-example-test.c:71:  kunit_info(suite, "exiting suite\n");
>

Oops sorry for missing this instance.

> as this will result in calls to kunit_indent_level(suite) and
> kunit_level(suite) macro.
>
> And KUNIT_LEVEL_CASE_PARAM is maybe a leftover, as now we change test
> levels using direct increase/decrease statements, but still IMO this
> enum nicely reflects what kind of levels we currently do support at this
> point. But could be dropped if needed.

Given the suite level is being used, I am on board with keeping the
enum as is. Plus, although the param level is not explicitly being
used, it does correspond with the value of the test->level field when
running parameterized tests.

>
> Regarding _"suite output occurs on multip

Re: [PATCH 3/4] kunit: Fix indentation of parameterized tests messages

2023-10-03 Thread Rae Moar
On Mon, Oct 2, 2023 at 9:43 AM Michal Wajdeczko
 wrote:
>
>
>
> On 28.09.2023 22:53, Rae Moar wrote:
> > On Mon, Sep 25, 2023 at 1:58 PM Michal Wajdeczko
> >  wrote:
> >>
> >> When running parametrized test cases, diagnostic messages
> >> are not properly aligned with the test result lines:
> >>
> >> $ ./tools/testing/kunit/kunit.py run --raw_output \
> >> --kunitconfig ./lib/kunit/.kunitconfig *.example_params*
> >>
> >> KTAP version 1
> >> 1..1
> >> # example: initializing suite
> >> KTAP version 1
> >> # Subtest: example
> >> # module: kunit_example_test
> >> 1..1
> >> KTAP version 1
> >> # Subtest: example_params_test
> >> # example_params_test: initializing
> >> # example_params_test: cleaning up
> >> ok 1 example value 3 # SKIP unsupported param value 3
> >> # example_params_test: initializing
> >> # example_params_test: cleaning up
> >> ok 2 example value 2
> >> # example_params_test: initializing
> >> # example_params_test: cleaning up
> >> ok 3 example value 1
> >> # example_params_test: initializing
> >> # example_params_test: cleaning up
> >> ok 4 example value 0 # SKIP unsupported param value 0
> >> # example_params_test: pass:2 fail:0 skip:2 total:4
> >> ok 1 example_params_test
> >> # example: exiting suite
> >> # Totals: pass:2 fail:0 skip:2 total:4
> >> ok 1 example
> >>
> >> Add test level attribute and use it to generate proper indent
> >> at the runtime:
> >>
> >> KTAP version 1
> >> 1..1
> >> # example: initializing suite
> >> KTAP version 1
> >> # Subtest: example
> >> # module: kunit_example_test
> >> 1..1
> >> KTAP version 1
> >> # Subtest: example_params_test
> >> # example_params_test: initializing
> >> # example_params_test: cleaning up
> >> ok 1 example value 3 # SKIP unsupported param value 3
> >> # example_params_test: initializing
> >> # example_params_test: cleaning up
> >> ok 2 example value 2
> >> # example_params_test: initializing
> >> # example_params_test: cleaning up
> >> ok 3 example value 1
> >> # example_params_test: initializing
> >> # example_params_test: cleaning up
> >> ok 4 example value 0 # SKIP unsupported param value 0
> >> # example_params_test: pass:2 fail:0 skip:2 total:4
> >> ok 1 example_params_test
> >> # example: exiting suite
> >> # Totals: pass:2 fail:0 skip:2 total:4
> >> ok 1 example
> >>
> >> Signed-off-by: Michal Wajdeczko 
> >> Cc: David Gow 
> >> Cc: Rae Moar 
> >
> > Hello!
> >
> > Great to see these changes! Just a few comments below.
> >
> > Thanks!
> > -Rae
> >
> >> ---
> >>  include/kunit/test.h |  3 ++-
> >>  lib/kunit/test.c | 52 
> >>  2 files changed, 26 insertions(+), 29 deletions(-)
> >>
> >> diff --git a/include/kunit/test.h b/include/kunit/test.h
> >> index 158876c4cb43..4804d539e10f 100644
> >> --- a/include/kunit/test.h
> >> +++ b/include/kunit/test.h
> >> @@ -276,6 +276,7 @@ struct kunit {
> >> void *priv;
> >>
> >> /* private: internal use only. */
> >> +   unsigned int level; /* Helps in proper log indent */
> >> const char *name; /* Read only after initialization! */
> >> struct string_stream *log; /* Points at case log after 
> >> initialization */
> >> struct kunit_try_catch try_catch;
> >> @@ -519,7 +520,7 @@ enum {
> >>  #define kunit_level(test_or_suite) \
> >> _Generic((test_or_suite),   \
> >>  struct kunit_suite * : KUNIT_LEVEL_SUITE,  \
> >> -struct kunit * : KUNIT_LEVEL_CASE)
> >> +struct kunit * : ((struct kunit *)(test_or_suite))->level)
> >>
>

Re: [PATCH v2 1/2] kunit: add ability to run tests after boot using debugfs

2023-10-04 Thread Rae Moar
On Thu, Sep 14, 2023 at 5:06 AM David Gow  wrote:
>
> On Sat, 9 Sept 2023 at 05:31, Rae Moar  wrote:
> >
> > Add functionality to run built-in tests after boot by writing to a
> > debugfs file.
> >
> > Add a new debugfs file labeled "run" for each test suite to use for
> > this purpose.
> >
> > As an example, write to the file using the following:
> >
> > echo "any string" > /sys/kernel/debugfs/kunit//run
> >
> > This will trigger the test suite to run and will print results to the
> > kernel log.
> >
> > Note that what you "write" to the debugfs file will not be saved.
> >
> > To guard against running tests concurrently with this feature, add a
> > mutex lock around running kunit. This supports the current practice of
> > not allowing tests to be run concurrently on the same kernel.
> >
> > This functionality may not work for all tests.
> >
> > This new functionality could be used to design a parameter
> > injection feature in the future.
> >
> > Signed-off-by: Rae Moar 
> > ---
>
> This is looking pretty good, but I have a few nitpicks below and one big 
> issue.
>
> The big issue is that this doesn't seem to exclude test suites created
> with kunit_test_init_section_suite{,s}(). The init section versions of
> the suite declarations, by definition, won't work if run after the
> kernel has finished booting. At the moment, these macros just pass
> through to the normal versions (because we've not been able to run
> after boot until now), but we'll need to implement it (maybe as a
> separate linker section, maybe as an attribute, etc) now. I expect
> that the correct solution here would be to not create the 'run'
> debugfs file for these tests. But I could be convinced to have it
> exist, but to just say "this test cannot be run after boot" if you've
> got a good argument. In any case, grep 'test.h' for "NOTE TO KUNIT
> DEVS" and you'll see the details.
>
> My one other not-totally-related thought (and this extends to module
> loading, too, so is possibly more useful as a separate patch) is that
> we're continually incrementing the test number still. This doesn't
> matter if we read the results from debugfs though, and it may make
> more sense to have this continue to increment (and thus treat all of
> dmesg as one long KTAP document). We could always add a reset option
> to debugfs in a follow-up patch if we want. But that's not something
> I'd hold this up with.
>

Hello!

Sorry for the delay in this response. I was working on other items but
I have started working on the next version of this patch.

Thanks for bringing my attention to the init tests. I am currently
working on a draft to remove the run files for these tests. However,
if that does not work, I will resort to outputting the message you
detailed above: "this test cannot be run after boot".

I am currently fine with the test number incrementing. However, I
would also be fine to implement a reset to ensure all the re-run
results have the test number of 1.

> >
> > Changes since v1:
> > - Removed second patch as this problem has been fixed
> > - Added Documentation patch
> > - Made changes to work with new dynamically-extending log feature
> >
> > Note that these patches now rely on (and are rebased on) the patch series:
> > https://lore.kernel.org/all/20230828104111.2394344-1...@opensource.cirrus.com/
> >
> >  lib/kunit/debugfs.c | 66 +
> >  lib/kunit/test.c| 13 +
> >  2 files changed, 79 insertions(+)
> >
> > diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
> > index 270d185737e6..8c0a970321ce 100644
> > --- a/lib/kunit/debugfs.c
> > +++ b/lib/kunit/debugfs.c
> > @@ -8,12 +8,14 @@
> >  #include 
> >
> >  #include 
> > +#include 
> >
> >  #include "string-stream.h"
> >  #include "debugfs.h"
> >
> >  #define KUNIT_DEBUGFS_ROOT "kunit"
> >  #define KUNIT_DEBUGFS_RESULTS  "results"
> > +#define KUNIT_DEBUGFS_RUN  "run"
> >
> >  /*
> >   * Create a debugfs representation of test suites:
> > @@ -21,6 +23,8 @@
> >   * PathSemantics
> >   * /sys/kernel/debug/kunit//results Show results of last run for
> >   * testsuite
> > + * /sys/kernel/debug/kunit//run Write to this file to 
> > trigger
> > + * 

Re: [PATCH v2 2/2] Documentation: Add debugfs docs with run after boot

2023-10-04 Thread Rae Moar
On Thu, Sep 14, 2023 at 5:06 AM David Gow  wrote:
>
> On Sat, 9 Sept 2023 at 05:32, Rae Moar  wrote:
> >
> > Expand the documentation on the KUnit debugfs filesystem on the
> > run_manual.rst page.
> >
> > Add section describing how to access results using debugfs.
> >
> > Add section describing how to run tests after boot using debugfs.
> >
> > Signed-off-by: Rae Moar 
> > Co-developed-by: Sadiya Kazi 
> > Signed-off-by: Sadiya Kazi 
> > ---
>
> Looks good to me, a few nitpicks, and the fact that we'll probably
> need to add something about init section suites when those are
> implemented.
>
> (Also, since you sent the email, your sign off should be at the bottom
> of the list above.)

Hello!

Thanks for the comments! Sorry about the Signed-off order. I will
change that for next time.

>
> >  Documentation/dev-tools/kunit/run_manual.rst | 45 ++--
> >  1 file changed, 41 insertions(+), 4 deletions(-)
> >
> > diff --git a/Documentation/dev-tools/kunit/run_manual.rst 
> > b/Documentation/dev-tools/kunit/run_manual.rst
> > index e7b46421f247..613385c5ba5b 100644
> > --- a/Documentation/dev-tools/kunit/run_manual.rst
> > +++ b/Documentation/dev-tools/kunit/run_manual.rst
> > @@ -49,9 +49,46 @@ loaded.
> >
> >  The results will appear in TAP format in ``dmesg``.
> >
> > +debugfs
> > +===
> > +
> > +``debugfs`` is a file system that enables user interaction with the files 
> > to
> > +make kernel information available to user space. A user can interact with
> > +the debugfs filesystem using a variety of file operations, such as open,
> > +read, and write.
> > +
> > +By default, only the root user has access to the debugfs directory.
>
> These two paragraphs are probably a bit excessive: we want to focus on
> what KUnit can do with debugfs, not describing what debugfs is as a
> whole (which is best left to pages like
> Documentation/filesystems/debugfs.rst )

Got it. Maybe I should just leave the first sentence and then link to
../debugfs.rst.

>
> > +
> > +If ``CONFIG_KUNIT_DEBUGFS`` is enabled, you can use KUnit debugfs
> > +filesystem to perform the following actions.
> > +
> > +Retrieve Test Results
> > +=
> > +
> > +You can use debugfs to retrieve KUnit test results. The test results are
> > +accessible from the debugfs filesystem in the following read-only file:
> > +
> > +.. code-block :: bash
> > +
> > +   /sys/kernel/debug/kunit//results
> > +
> > +The test results are available in KTAP format.
>
> We _could_ mention that this is a separate KTAP document (i.e., the
> numbering starts at 1), though it may be obvious.
>
> > +
> > +Run Tests After Kernel Has Booted
> > +=
> > +
> > +You can use the debugfs filesystem to trigger built-in tests to run after
> > +boot. To run the test suite, you can use the following command to write to
> > +the ``/sys/kernel/debug/kunit//run`` file:
> > +
> > +.. code-block :: bash
> > +
> > +   echo "any string" > /sys/kernel/debugfs/kunit//run
> > +
> > +As a result, the test suite runs and the results are printed to the kernel
> > +log.
> > +
> >  .. note ::
> >
> > -   If ``CONFIG_KUNIT_DEBUGFS`` is enabled, KUnit test results will
> > -   be accessible from the ``debugfs`` filesystem (if mounted).
> > -   They will be in ``/sys/kernel/debug/kunit//results``, in
> > -   TAP format.
> > +   The contents written to the debugfs file
> > +   ``/sys/kernel/debug/kunit//run`` are not saved.
>
> This is possibly a bit obvious. Maybe it'd be more useful with a bit
> more context, e.g., "The contents written to the file ... are
> discarded; it is the act of writing which triggers the test, not the
> specific contents written."?

I will try to add more context here in the next version.

>
> It might be worth having a note that tests cannot run concurrently, so
> this may block or fail.
>
> Equally, it may be worth having a note for test authors, that their
> tests will need to correctly initialise and/or clean up any data, so
> the test runs correctly a second time.
>

Yes these are two good points. I will add notes on tests not being
able to run concurrently, cleaning up data, and also init tests.

>
> > --
> > 2.42.0.283.g2d96d420d3-goog
> >


Re: [PATCH v2] kunit: Warn if tests are slow

2023-10-24 Thread Rae Moar
On Wed, Sep 20, 2023 at 4:49 AM Maxime Ripard  wrote:
>
> Kunit recently gained support to setup attributes, the first one being
> the speed of a given test, then allowing to filter out slow tests.
>
> A slow test is defined in the documentation as taking more than one
> second. There's an another speed attribute called "super slow" but whose
> definition is less clear.
>
> Add support to the test runner to check the test execution time, and
> report tests that should be marked as slow but aren't.
>
> Signed-off-by: Maxime Ripard 
>

Hello!

Thanks for following up! Sorry for the delay in this response.

This looks great to me. I do have one comment below regarding the
KUNIT_SPEED_SLOW_THRESHOLD_S macro but other than that I would be
happy with this patch.

This patch does bring up the question of how to handle KUnit warnings
as mentioned before. But I am happy to approach that in a future
patch.

And I do still have concerns with this being annoying for those on
slower architectures but again that would depend on how we deal with
KUnit warnings.

Thanks!
-Rae

> ---
>
> To: Brendan Higgins 
> To: David Gow 
> Cc: Jani Nikula 
> Cc: Rae Moar 
> Cc: linux-kselftest@vger.kernel.org
> Cc: kunit-...@googlegroups.com
> Cc: linux-ker...@vger.kernel.org
>
> Changes from v1:
> - Split the patch out of the series
> - Change to trigger the warning only if the runtime is twice the
>   threshold (Jani, Rae)
> - Split the speed check into a separate function (Rae)
> - Link: 
> https://lore.kernel.org/all/20230911-kms-slow-tests-v1-0-d3800a69a...@kernel.org/
> ---
>  lib/kunit/test.c | 27 +++
>  1 file changed, 27 insertions(+)
>
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index 49698a168437..a1d5dd2bf87d 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -372,6 +372,25 @@ void kunit_init_test(struct kunit *test, const char 
> *name, char *log)
>  }
>  EXPORT_SYMBOL_GPL(kunit_init_test);
>
> +#define KUNIT_SPEED_SLOW_THRESHOLD_S   1
> +
> +static void kunit_run_case_check_speed(struct kunit *test,
> +  struct kunit_case *test_case,
> +  struct timespec64 duration)
> +{
> +   enum kunit_speed speed = test_case->attr.speed;
> +
> +   if (duration.tv_sec < (2 * KUNIT_SPEED_SLOW_THRESHOLD_S))

I think I would prefer that KUNIT_SPEED_SLOW_THRESHOLD_S is instead
set to 2 rather than using 2 as the multiplier. I realize the actual
threshold for the attributes is 1 sec but for the practical use of
this warning it is 2 sec.

Also I would still be open to this being 1 sec depending on others
opinions. David, what are your thoughts on this?

> +   return;
> +
> +   if (speed == KUNIT_SPEED_VERY_SLOW || speed == KUNIT_SPEED_SLOW)
> +   return;
> +
> +   kunit_warn(test,
> +  "Test should be marked slow (runtime: %lld.%09lds)",
> +  duration.tv_sec, duration.tv_nsec);
> +}
> +
>  /*
>   * Initializes and runs test case. Does not clean up or do post validations.
>   */
> @@ -379,6 +398,8 @@ static void kunit_run_case_internal(struct kunit *test,
> struct kunit_suite *suite,
> struct kunit_case *test_case)
>  {
> +   struct timespec64 start, end;
> +
> if (suite->init) {
> int ret;
>
> @@ -390,7 +411,13 @@ static void kunit_run_case_internal(struct kunit *test,
> }
> }
>
> +   ktime_get_ts64(&start);
> +
> test_case->run_case(test);
> +
> +   ktime_get_ts64(&end);
> +
> +   kunit_run_case_check_speed(test, test_case, timespec64_sub(end, 
> start));
>  }
>
>  static void kunit_case_internal_cleanup(struct kunit *test)
> --
> 2.41.0
>


Re: [PATCH] kunit: string-stream-test: Avoid cast warning when testing gfp_t flags

2023-11-29 Thread Rae Moar
On Tue, Nov 21, 2023 at 11:25 AM Richard Fitzgerald
 wrote:
>
> Passing a gfp_t to KUNIT_EXPECT_EQ() causes a cast warning:
>
>   lib/kunit/string-stream-test.c:73:9: sparse: sparse: incorrect type in
>   initializer (different base types) expected long long right_value
>   got restricted gfp_t const __right
>
> Avoid this by testing stream->gfp for the expected value and passing the
> boolean result of this comparison to KUNIT_EXPECT_TRUE(), as was already
> done a few lines above in string_stream_managed_init_test().
>
> Signed-off-by: Richard Fitzgerald 
> Fixes: d1a0d699bfc0 ("kunit: string-stream: Add tests for freeing 
> resource-managed string_stream")
> Reported-by: kernel test robot 
> Closes: 
> https://lore.kernel.org/oe-kbuild-all/202311181918.0mpcu2xh-...@intel.com/

Hello!

This looks good to me. Thanks for fixing this!

Reviewed-by: Rae Moar 

-Rae

> ---
>  lib/kunit/string-stream-test.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/kunit/string-stream-test.c b/lib/kunit/string-stream-test.c
> index 06822766f29a..03fb511826f7 100644
> --- a/lib/kunit/string-stream-test.c
> +++ b/lib/kunit/string-stream-test.c
> @@ -72,7 +72,7 @@ static void string_stream_unmanaged_init_test(struct kunit 
> *test)
>
> KUNIT_EXPECT_EQ(test, stream->length, 0);
> KUNIT_EXPECT_TRUE(test, list_empty(&stream->fragments));
> -   KUNIT_EXPECT_EQ(test, stream->gfp, GFP_KERNEL);
> +   KUNIT_EXPECT_TRUE(test, (stream->gfp == GFP_KERNEL));
> KUNIT_EXPECT_FALSE(test, stream->append_newlines);
>
> KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream));
> --
> 2.30.2
>



Re: [PATCH RESEND] kunit: string-stream: Allow ERR_PTR to be passed to string_stream_destroy()

2023-11-30 Thread Rae Moar
On Mon, Oct 30, 2023 at 6:47 AM Richard Fitzgerald
 wrote:
>
> Check the stream pointer passed to string_stream_destroy() for
> IS_ERR_OR_NULL() instead of only NULL.
>
> Whatever alloc_string_stream() returns should be safe to pass
> to string_stream_destroy(), and that will be an ERR_PTR.
>
> It's obviously good practise and generally helpful to also check
> for NULL pointers so that client cleanup code can call
> string_stream_destroy() unconditionally - which could include
> pointers that have never been set to anything and so are NULL.
>
> Signed-off-by: Richard Fitzgerald 

Hello!

Sorry for the delay in reviewing this patch but this looks good to me!

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
>  lib/kunit/string-stream.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
> index a6f3616c2048..54f4fdcbfac8 100644
> --- a/lib/kunit/string-stream.c
> +++ b/lib/kunit/string-stream.c
> @@ -173,7 +173,7 @@ void string_stream_destroy(struct string_stream *stream)
>  {
> KUNIT_STATIC_STUB_REDIRECT(string_stream_destroy, stream);
>
> -   if (!stream)
> +   if (IS_ERR_OR_NULL(stream))
> return;
>
> string_stream_clear(stream);
> --
> 2.30.2
>



Re: [PATCH RESEND] kunit: debugfs: Fix unchecked dereference in debugfs_print_results()

2023-11-30 Thread Rae Moar
On Mon, Oct 30, 2023 at 6:48 AM Richard Fitzgerald
 wrote:
>
> Move the call to kunit_suite_has_succeeded() after the check that
> the kunit_suite pointer is valid.
>
> This was found by smatch:
>
>  lib/kunit/debugfs.c:66 debugfs_print_results() warn: variable
>  dereferenced before check 'suite' (see line 63)
>
> Signed-off-by: Richard Fitzgerald 
> Reported-by: Dan Carpenter 
> Fixes: 38289a26e1b8 ("kunit: fix debugfs code to use enum kunit_status, not 
> bool")

Hello!

This patch looks good to me! Thanks for fixing this!

Reviewed-by: Rae Moar 

-Rae

> ---
>  lib/kunit/debugfs.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
> index 9d167adfa746..382706dfb47d 100644
> --- a/lib/kunit/debugfs.c
> +++ b/lib/kunit/debugfs.c
> @@ -60,12 +60,14 @@ static void debugfs_print_result(struct seq_file *seq, 
> struct string_stream *log
>  static int debugfs_print_results(struct seq_file *seq, void *v)
>  {
> struct kunit_suite *suite = (struct kunit_suite *)seq->private;
> -   enum kunit_status success = kunit_suite_has_succeeded(suite);
> +   enum kunit_status success;
> struct kunit_case *test_case;
>
> if (!suite)
> return 0;
>
> +   success = kunit_suite_has_succeeded(suite);
> +
> /* 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");
> --
> 2.30.2
>



Re: [PATCH v2 RESEND] kunit: debugfs: Handle errors from alloc_string_stream()

2023-11-30 Thread Rae Moar
On Mon, Oct 30, 2023 at 6:47 AM Richard Fitzgerald
 wrote:
>
> In kunit_debugfs_create_suite() give up and skip creating the debugfs
> file if any of the alloc_string_stream() calls return an error or NULL.
> Only put a value in the log pointer of kunit_suite and kunit_test if it
> is a valid pointer to a log.
>
> This prevents the potential invalid dereference reported by smatch:
>
>  lib/kunit/debugfs.c:115 kunit_debugfs_create_suite() error: 'suite->log'
> dereferencing possible ERR_PTR()
>  lib/kunit/debugfs.c:119 kunit_debugfs_create_suite() error: 'test_case->log'
> dereferencing possible ERR_PTR()

Hello!

Thanks for sending the re-sends of these patches! This patch also
looks good to me! I have one comment below but I would still be happy
with the patch as is.

Reviewed-by: Rae Moar 

Thanks!
-Rae

>
> Signed-off-by: Richard Fitzgerald 
> Reported-by: Dan Carpenter 
> Fixes: 05e2006ce493 ("kunit: Use string_stream for test log")
> ---
>  lib/kunit/debugfs.c | 30 +-
>  1 file changed, 25 insertions(+), 5 deletions(-)
>
> diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
> index 270d185737e6..9d167adfa746 100644
> --- a/lib/kunit/debugfs.c
> +++ b/lib/kunit/debugfs.c
> @@ -109,14 +109,28 @@ static const struct file_operations 
> debugfs_results_fops = {
>  void kunit_debugfs_create_suite(struct kunit_suite *suite)
>  {
> struct kunit_case *test_case;
> +   struct string_stream *stream;
>
> -   /* Allocate logs before creating debugfs representation. */
> -   suite->log = alloc_string_stream(GFP_KERNEL);
> -   string_stream_set_append_newlines(suite->log, true);
> +   /*
> +* Allocate logs before creating debugfs representation.
> +* The suite->log and test_case->log pointer are expected to be NULL
> +* if there isn't a log, so only set it if the log stream was created
> +* successfully.
> +*/

I like this new comment. Thanks!

> +   stream = alloc_string_stream(GFP_KERNEL);
> +   if (IS_ERR_OR_NULL(stream))

In response to Dan Carpenter's comment from the last version, I see
the benefits of changing IS_ERR_OR_NULL() to IS_ERR() instead because
"stream" will not be NULL. This would then also be the same as the
check in kunit_alloc_string_stream.

However, I also see the benefit of checking for NULL just in case anyways.

I'm overall happy with either solution but just wanted to bring this up.

> +   return;
> +
> +   string_stream_set_append_newlines(stream, true);
> +   suite->log = stream;
>
> kunit_suite_for_each_test_case(suite, test_case) {
> -   test_case->log = alloc_string_stream(GFP_KERNEL);
> -   string_stream_set_append_newlines(test_case->log, true);
> +   stream = alloc_string_stream(GFP_KERNEL);
> +   if (IS_ERR_OR_NULL(stream))
> +   goto err;
> +
> +   string_stream_set_append_newlines(stream, true);
> +   test_case->log = stream;
> }
>
> suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir);
> @@ -124,6 +138,12 @@ void kunit_debugfs_create_suite(struct kunit_suite 
> *suite)
> debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444,
> suite->debugfs,
> suite, &debugfs_results_fops);
> +   return;
> +
> +err:
> +   string_stream_destroy(suite->log);
> +   kunit_suite_for_each_test_case(suite, test_case)
> +   string_stream_destroy(test_case->log);
>  }
>
>  void kunit_debugfs_destroy_suite(struct kunit_suite *suite)
> --
> 2.30.2
>



[PATCH v3 1/6] kunit: move KUNIT_TABLE out of INIT_DATA

2023-12-04 Thread Rae Moar
Alter the linker section of KUNIT_TABLE to move it out of INIT_DATA and
into DATA_DATA.

Data for KUnit tests does not need to be in the init section.

In order to run tests again after boot the KUnit data cannot be labeled as
init data as the kernel could write over it.

Add a KUNIT_INIT_TABLE in the next patch for KUnit tests that test init
data/functions.

Signed-off-by: Rae Moar 
---
 include/asm-generic/vmlinux.lds.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index bae0fe4d499b..1107905d37fc 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -370,7 +370,8 @@
BRANCH_PROFILE()\
TRACE_PRINTKS() \
BPF_RAW_TP()\
-   TRACEPOINT_STR()
+   TRACEPOINT_STR()\
+   KUNIT_TABLE()
 
 /*
  * Data section helpers
@@ -699,8 +700,7 @@
THERMAL_TABLE(governor) \
EARLYCON_TABLE()\
LSM_TABLE() \
-   EARLY_LSM_TABLE()   \
-   KUNIT_TABLE()
+   EARLY_LSM_TABLE()
 
 #define INIT_TEXT  \
*(.init.text .init.text.*)  \

base-commit: b85ea95d086471afb4ad062012a4d73cd328fa86
-- 
2.43.0.rc2.451.g8631bc7472-goog




[PATCH v3 2/6] kunit: add KUNIT_INIT_TABLE to init linker section

2023-12-04 Thread Rae Moar
Add KUNIT_INIT_TABLE to the INIT_DATA linker section.

Alter the KUnit macros to create init tests:
kunit_test_init_section_suites

Update lib/kunit/executor.c to run both the suites in KUNIT_TABLE and
KUNIT_INIT_TABLE.

Signed-off-by: Rae Moar 
---
 include/asm-generic/vmlinux.lds.h |  9 -
 include/kunit/test.h  | 10 -
 include/linux/module.h|  2 +
 kernel/module/main.c  |  3 ++
 lib/kunit/executor.c  | 64 ---
 lib/kunit/test.c  | 26 +
 6 files changed, 99 insertions(+), 15 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 1107905d37fc..5dd3a61d673d 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -700,7 +700,8 @@
THERMAL_TABLE(governor) \
EARLYCON_TABLE()\
LSM_TABLE() \
-   EARLY_LSM_TABLE()
+   EARLY_LSM_TABLE()   \
+   KUNIT_INIT_TABLE()
 
 #define INIT_TEXT  \
*(.init.text .init.text.*)  \
@@ -926,6 +927,12 @@
. = ALIGN(8);   \
BOUNDED_SECTION_POST_LABEL(.kunit_test_suites, __kunit_suites, 
_start, _end)
 
+/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
+#define KUNIT_INIT_TABLE() \
+   . = ALIGN(8);   \
+   BOUNDED_SECTION_POST_LABEL(.kunit_init_test_suites, \
+   __kunit_init_suites, _start, _end)
+
 #ifdef CONFIG_BLK_DEV_INITRD
 #define INIT_RAM_FS\
. = ALIGN(4);   \
diff --git a/include/kunit/test.h b/include/kunit/test.h
index 20ed9f9275c9..06e826a0b894 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -337,6 +337,9 @@ void __kunit_test_suites_exit(struct kunit_suite **suites, 
int num_suites);
 void kunit_exec_run_tests(struct kunit_suite_set *suite_set, bool builtin);
 void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool 
include_attr);
 
+struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set 
init_suite_set,
+   struct kunit_suite_set suite_set);
+
 #if IS_BUILTIN(CONFIG_KUNIT)
 int kunit_run_all_tests(void);
 #else
@@ -371,6 +374,11 @@ static inline int kunit_run_all_tests(void)
 
 #define kunit_test_suite(suite)kunit_test_suites(&suite)
 
+#define __kunit_init_test_suites(unique_array, ...)   \
+   static struct kunit_suite *unique_array[]  \
+   __aligned(sizeof(struct kunit_suite *))\
+   __used __section(".kunit_init_test_suites") = { __VA_ARGS__ }
+
 /**
  * kunit_test_init_section_suites() - used to register one or more &struct
  *   kunit_suite containing init functions or
@@ -392,7 +400,7 @@ static inline int kunit_run_all_tests(void)
  * this manner.
  */
 #define kunit_test_init_section_suites(__suites...)\
-   __kunit_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe),\
+   __kunit_init_test_suites(__UNIQUE_ID(array),\
##__suites)
 
 #define kunit_test_init_section_suite(suite)   \
diff --git a/include/linux/module.h b/include/linux/module.h
index a98e188cf37b..9cd0009bd050 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -540,6 +540,8 @@ struct module {
struct static_call_site *static_call_sites;
 #endif
 #if IS_ENABLED(CONFIG_KUNIT)
+   int num_kunit_init_suites;
+   struct kunit_suite **kunit_init_suites;
int num_kunit_suites;
struct kunit_suite **kunit_suites;
 #endif
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 98fedfdb8db5..36681911c05a 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2199,6 +2199,9 @@ static int find_module_sections(struct module *mod, 
struct load_info *info)
mod->kunit_suites = section_objs(info, ".kunit_test_suites",
  sizeof(*mod->kunit_suites),
  &mod->num_kunit_suites);
+   mod->kunit_init_suites = section_objs(info, ".kunit_init_test_suites",
+ sizeof(*mod->kunit_init_suites),
+ &mod->num_kunit_init_suites);
 #endif
 
mod->extable = section_objs(info, "__ex_table",
diff --git a

[PATCH v3 4/6] kunit: add is_init test attribute

2023-12-04 Thread Rae Moar
Add is_init test attribute of type bool. Add to_string, get, and filter
methods to lib/kunit/attributes.c.

Mark each of the tests in the init section with the is_init=true attribute.

Add is_init to the attributes documentation.

Signed-off-by: Rae Moar 
---
 .../dev-tools/kunit/running_tips.rst  |  7 +++
 include/kunit/test.h  |  3 +
 lib/kunit/attributes.c| 60 +++
 lib/kunit/executor.c  |  6 +-
 4 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/Documentation/dev-tools/kunit/running_tips.rst 
b/Documentation/dev-tools/kunit/running_tips.rst
index 766f9cdea0fa..024e9ad1d1e9 100644
--- a/Documentation/dev-tools/kunit/running_tips.rst
+++ b/Documentation/dev-tools/kunit/running_tips.rst
@@ -428,3 +428,10 @@ This attribute indicates the name of the module associated 
with the test.
 
 This attribute is automatically saved as a string and is printed for each 
suite.
 Tests can also be filtered using this attribute.
+
+``is_init``
+
+This attribute indicates whether the test uses init data or functions.
+
+This attribute is automatically saved as a boolean and tests can also be
+filtered using this attribute.
diff --git a/include/kunit/test.h b/include/kunit/test.h
index 06e826a0b894..65583782903d 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -82,6 +82,9 @@ enum kunit_speed {
 /* Holds attributes for each test case and suite */
 struct kunit_attributes {
enum kunit_speed speed;
+
+   /* private: internal use only */
+   bool is_init;
 };
 
 /**
diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index 1b512f7e1838..ddacec6a3337 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -58,6 +58,16 @@ static const char *attr_enum_to_string(void *attr, const 
char * const str_list[]
return str_list[val];
 }
 
+static const char *attr_bool_to_string(void *attr, bool *to_free)
+{
+   bool val = (bool)attr;
+
+   *to_free = false;
+   if (val)
+   return "true";
+   return "false";
+}
+
 static const char *attr_speed_to_string(void *attr, bool *to_free)
 {
return attr_enum_to_string(attr, speed_str_list, to_free);
@@ -166,6 +176,37 @@ static int attr_string_filter(void *attr, const char 
*input, int *err)
return false;
 }
 
+static int attr_bool_filter(void *attr, const char *input, int *err)
+{
+   int i, input_int = -1;
+   long val = (long)attr;
+   const char *input_str = NULL;
+
+   for (i = 0; input[i]; i++) {
+   if (!strchr(op_list, input[i])) {
+   input_str = input + i;
+   break;
+   }
+   }
+
+   if (!input_str) {
+   *err = -EINVAL;
+   pr_err("kunit executor: filter value not found: %s\n", input);
+   return false;
+   }
+
+   if (!strcmp(input_str, "true"))
+   input_int = (int)true;
+   else if (!strcmp(input_str, "false"))
+   input_int = (int)false;
+   else {
+   *err = -EINVAL;
+   pr_err("kunit executor: invalid filter input: %s\n", input);
+   return false;
+   }
+
+   return int_filter(val, input, input_int, err);
+}
 
 /* Get Attribute Methods */
 
@@ -194,6 +235,17 @@ static void *attr_module_get(void *test_or_suite, bool 
is_test)
return (void *) "";
 }
 
+static void *attr_is_init_get(void *test_or_suite, bool is_test)
+{
+   struct kunit_suite *suite = is_test ? NULL : test_or_suite;
+   struct kunit_case *test = is_test ? test_or_suite : NULL;
+
+   if (test)
+   return ((void *) test->attr.is_init);
+   else
+   return ((void *) suite->attr.is_init);
+}
+
 /* List of all Test Attributes */
 
 static struct kunit_attr kunit_attr_list[] = {
@@ -212,6 +264,14 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_string_filter,
.attr_default = (void *)"",
.print = PRINT_SUITE,
+   },
+   {
+   .name = "is_init",
+   .get_attr = attr_is_init_get,
+   .to_string = attr_bool_to_string,
+   .filter = attr_bool_filter,
+   .attr_default = (void *)false,
+   .print = PRINT_SUITE,
}
 };
 
diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 847329c51e91..594de994161a 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -300,6 +300,7 @@ struct kunit_suite_set kunit_merge_suite_sets(struct 
kunit_suite_set init_suite_
struct kunit_suite_set total_suite_set = {NULL, NULL};
struct kunit_suite **total_suite_start = NULL;
size_t init_num_suites, num_suites, suite_size;
+   int i = 0;
 
init_num_suites = init_suite_set.end - init_su

[PATCH v3 3/6] kunit: add example suite to test init suites

2023-12-04 Thread Rae Moar
Add example_init_test_suite to allow for testing the feature of running
test suites marked as init to indicate they use init data and/or
functions.

This suite should always pass and uses a simple init function.

This suite can also be used to test the is_init attribute introduced in
the next patch.

Signed-off-by: Rae Moar 
---
 lib/kunit/kunit-example-test.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
index 6bb5c2ef6696..262a68a59800 100644
--- a/lib/kunit/kunit-example-test.c
+++ b/lib/kunit/kunit-example-test.c
@@ -287,4 +287,33 @@ static struct kunit_suite example_test_suite = {
  */
 kunit_test_suites(&example_test_suite);
 
+static int __init init_add(int x, int y)
+{
+   return (x + y);
+}
+
+/*
+ * This test should always pass. Can be used to test init suites.
+ */
+static void example_init_test(struct kunit *test)
+{
+   KUNIT_EXPECT_EQ(test, init_add(1, 1), 2);
+}
+
+static struct kunit_case example_init_test_cases[] = {
+   KUNIT_CASE(example_init_test),
+   {}
+};
+
+static struct kunit_suite example_init_test_suite = {
+   .name = "example_init",
+   .test_cases = example_init_test_cases,
+};
+
+/*
+ * This registers the test suite and marks the suite as using init data
+ * and/or functions.
+ */
+kunit_test_init_section_suites(&example_init_test_suite);
+
 MODULE_LICENSE("GPL v2");
-- 
2.43.0.rc2.451.g8631bc7472-goog




[PATCH v3 5/6] kunit: add ability to run tests after boot using debugfs

2023-12-04 Thread Rae Moar
Add functionality to run built-in tests after boot by writing to a
debugfs file.

Add a new debugfs file labeled "run" for each test suite to use for
this purpose.

As an example, write to the file using the following:

echo "any string" > /sys/kernel/debugfs/kunit//run

This will trigger the test suite to run and will print results to the
kernel log.

To guard against running tests concurrently with this feature, add a
mutex lock around running kunit. This supports the current practice of
not allowing tests to be run concurrently on the same kernel.

This new functionality could be used to design a parameter
injection feature in the future.

Signed-off-by: Rae Moar 
---

Changes since v2:
- Move resetting the log to test.c
- Add is_init attribute and patches to change linker sections to avoid
  re-running tests that use init data and functions

 lib/kunit/debugfs.c | 68 +
 lib/kunit/test.c| 10 +++
 2 files changed, 78 insertions(+)

diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
index 270d185737e6..2e0a92a0c461 100644
--- a/lib/kunit/debugfs.c
+++ b/lib/kunit/debugfs.c
@@ -8,12 +8,14 @@
 #include 
 
 #include 
+#include 
 
 #include "string-stream.h"
 #include "debugfs.h"
 
 #define KUNIT_DEBUGFS_ROOT "kunit"
 #define KUNIT_DEBUGFS_RESULTS  "results"
+#define KUNIT_DEBUGFS_RUN  "run"
 
 /*
  * Create a debugfs representation of test suites:
@@ -21,6 +23,8 @@
  * PathSemantics
  * /sys/kernel/debug/kunit//results Show results of last run for
  * testsuite
+ * /sys/kernel/debug/kunit//run Write to this file to trigger
+ * testsuite to run
  *
  */
 
@@ -99,6 +103,51 @@ static int debugfs_results_open(struct inode *inode, struct 
file *file)
return single_open(file, debugfs_print_results, suite);
 }
 
+/*
+ * Print a usage message to the debugfs "run" file
+ * (/sys/kernel/debug/kunit//run) if opened.
+ */
+static int debugfs_print_run(struct seq_file *seq, void *v)
+{
+   struct kunit_suite *suite = (struct kunit_suite *)seq->private;
+
+   seq_puts(seq, "Write to this file to trigger the test suite to run.\n");
+   seq_printf(seq, "usage: echo \"any string\" > 
/sys/kernel/debugfs/kunit/%s/run\n",
+   suite->name);
+   return 0;
+}
+
+/*
+ * The debugfs "run" file (/sys/kernel/debug/kunit//run)
+ * contains no information. Write to the file to trigger the test suite
+ * to run.
+ */
+static int debugfs_run_open(struct inode *inode, struct file *file)
+{
+   struct kunit_suite *suite;
+
+   suite = (struct kunit_suite *)inode->i_private;
+
+   return single_open(file, debugfs_print_run, suite);
+}
+
+/*
+ * Trigger a test suite to run by writing to the suite's "run" debugfs
+ * file found at: /sys/kernel/debug/kunit//run
+ *
+ * Note: what is written to this file will not be saved.
+ */
+static ssize_t debugfs_run(struct file *file,
+   const char __user *buf, size_t count, loff_t *ppos)
+{
+   struct inode *f_inode = file->f_inode;
+   struct kunit_suite *suite = (struct kunit_suite *) f_inode->i_private;
+
+   __kunit_test_suites_init(&suite, 1);
+
+   return count;
+}
+
 static const struct file_operations debugfs_results_fops = {
.open = debugfs_results_open,
.read = seq_read,
@@ -106,10 +155,22 @@ static const struct file_operations debugfs_results_fops 
= {
.release = debugfs_release,
 };
 
+static const struct file_operations debugfs_run_fops = {
+   .open = debugfs_run_open,
+   .read = seq_read,
+   .write = debugfs_run,
+   .llseek = seq_lseek,
+   .release = debugfs_release,
+};
+
 void kunit_debugfs_create_suite(struct kunit_suite *suite)
 {
struct kunit_case *test_case;
 
+   /* If suite log already allocated, do not create new debugfs files. */
+   if (suite->log)
+   return;
+
/* Allocate logs before creating debugfs representation. */
suite->log = alloc_string_stream(GFP_KERNEL);
string_stream_set_append_newlines(suite->log, true);
@@ -124,6 +185,13 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite)
debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444,
suite->debugfs,
suite, &debugfs_results_fops);
+
+   /* Do not create file to re-run test if test runs on init */
+   if (!suite->attr.is_init) {
+   debugfs_create_file(KUNIT_DEBUGFS_RUN, S_IFREG | 0644,
+   suite->debugfs,
+   suite, &debugfs_run_fops);
+   }
 }
 
 void kunit_debugfs_dest

[PATCH v3 6/6] Documentation: Add debugfs docs with run after boot

2023-12-04 Thread Rae Moar
Expand the documentation on the KUnit debugfs filesystem on the
run_manual.rst page.

Add section describing how to access results using debugfs.

Add section describing how to run tests after boot using debugfs.

Signed-off-by: Rae Moar 
---

Changes since v2:
- Add info to documentation about cleaning up data, init tests, and
  running tests concurrently

 Documentation/dev-tools/kunit/run_manual.rst | 49 ++--
 1 file changed, 45 insertions(+), 4 deletions(-)

diff --git a/Documentation/dev-tools/kunit/run_manual.rst 
b/Documentation/dev-tools/kunit/run_manual.rst
index e7b46421f247..aebb52ba9605 100644
--- a/Documentation/dev-tools/kunit/run_manual.rst
+++ b/Documentation/dev-tools/kunit/run_manual.rst
@@ -49,9 +49,50 @@ loaded.
 
 The results will appear in TAP format in ``dmesg``.
 
+debugfs
+===
+
+``debugfs`` is a file system that enables user interaction with the files to
+make kernel information available to user space (See more information at
+Documentation/filesystems/debugfs.html)
+
+By default, only the root user has access to the debugfs directory.
+
+If ``CONFIG_KUNIT_DEBUGFS`` is enabled, you can use KUnit debugfs
+filesystem to perform the following actions.
+
+Retrieve Test Results
+=
+
+You can use debugfs to retrieve KUnit test results. The test results are
+accessible from the debugfs filesystem in the following read-only file:
+
+.. code-block :: bash
+
+   /sys/kernel/debug/kunit//results
+
+The test results are available in KTAP format.
+
+Run Tests After Kernel Has Booted
+=
+
+You can use the debugfs filesystem to trigger built-in tests to run after
+boot. To run the test suite, you can use the following command to write to
+the ``/sys/kernel/debug/kunit//run`` file:
+
+.. code-block :: bash
+
+   echo "any string" > /sys/kernel/debugfs/kunit//run
+
+As a result, the test suite runs and the results are printed to the kernel
+log.
+
+However, this feature is not available with KUnit tests that use init data.
+
+Also, you cannot use this feature to run tests concurrently as there is a
+mutex lock around running KUnit tests at the same time.
+
 .. note ::
 
-   If ``CONFIG_KUNIT_DEBUGFS`` is enabled, KUnit test results will
-   be accessible from the ``debugfs`` filesystem (if mounted).
-   They will be in ``/sys/kernel/debug/kunit//results``, in
-   TAP format.
+   For test authors, to use this feature, tests will need to correctly 
initialise
+   and/or clean up any data, so the test runs correctly a second time.
-- 
2.43.0.rc2.451.g8631bc7472-goog




[PATCH] kunit: tool: fix parsing of test attributes

2023-12-05 Thread Rae Moar
Add parsing of attributes as diagnostic data. Fixes issue with test plan
being parsed incorrectly as diagnostic data when located after
suite-level attributes.

Note that if there does not exist a test plan line, the diagnostic lines
between the suite header and the first result will be saved in the suite
log rather than the first test case log.

Signed-off-by: Rae Moar 
---

Note this patch is a resend but I removed the second patch in the series
so now it is a standalone patch.

 tools/testing/kunit/kunit_parser.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/testing/kunit/kunit_parser.py 
b/tools/testing/kunit/kunit_parser.py
index 79d8832c862a..ce34be15c929 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -450,7 +450,7 @@ def parse_diagnostic(lines: LineStream) -> List[str]:
Log of diagnostic lines
"""
log = []  # type: List[str]
-   non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, TAP_START]
+   non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, 
TAP_START, TEST_PLAN]
while lines and not any(re.match(lines.peek())
for re in non_diagnostic_lines):
log.append(lines.pop())
@@ -726,6 +726,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
# test plan
test.name = "main"
ktap_line = parse_ktap_header(lines, test)
+   test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
parent_test = True
else:
@@ -737,6 +738,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
if parent_test:
# If KTAP version line and/or subtest header is found, 
attempt
# to parse test plan and print test header
+   test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
print_test_header(test)
expected_count = test.expected_count

base-commit: b85ea95d086471afb4ad062012a4d73cd328fa86
-- 
2.43.0.rc2.451.g8631bc7472-goog




[PATCH v2 1/2] kunit: tool: fix parsing of test attributes

2023-12-07 Thread Rae Moar
Add parsing of attributes as diagnostic data. Fixes issue with test plan
being parsed incorrectly as diagnostic data when located after
suite-level attributes.

Note that if there does not exist a test plan line, the diagnostic lines
between the suite header and the first result will be saved in the suite
log rather than the first test case log.

Signed-off-by: Rae Moar 
---
 tools/testing/kunit/kunit_parser.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/testing/kunit/kunit_parser.py 
b/tools/testing/kunit/kunit_parser.py
index 79d8832c862a..ce34be15c929 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -450,7 +450,7 @@ def parse_diagnostic(lines: LineStream) -> List[str]:
Log of diagnostic lines
"""
log = []  # type: List[str]
-   non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, TAP_START]
+   non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, 
TAP_START, TEST_PLAN]
while lines and not any(re.match(lines.peek())
for re in non_diagnostic_lines):
log.append(lines.pop())
@@ -726,6 +726,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
# test plan
test.name = "main"
ktap_line = parse_ktap_header(lines, test)
+   test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
parent_test = True
else:
@@ -737,6 +738,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
if parent_test:
# If KTAP version line and/or subtest header is found, 
attempt
# to parse test plan and print test header
+   test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
print_test_header(test)
expected_count = test.expected_count

base-commit: b85ea95d086471afb4ad062012a4d73cd328fa86
-- 
2.43.0.472.g3155946c3a-goog




[PATCH v2 2/2] kunit: tool: add test for parsing attributes

2023-12-07 Thread Rae Moar
Add test for parsing attributes to kunit_tool_test.py. Test checks
attributes are parsed and saved in the test logs.

This test also checks that the attributes have not interfered with the
parsing of other test information, specifically the suite header as
the test plan was being incorrectely parsed.

Signed-off-by: Rae Moar 
---
 tools/testing/kunit/kunit_tool_test.py   | 16 
 .../kunit/test_data/test_parse_attributes.log|  9 +
 2 files changed, 25 insertions(+)
 create mode 100644 tools/testing/kunit/test_data/test_parse_attributes.log

diff --git a/tools/testing/kunit/kunit_tool_test.py 
b/tools/testing/kunit/kunit_tool_test.py
index b28c1510be2e..2beb7327e53f 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -331,6 +331,22 @@ class KUnitParserTest(unittest.TestCase):
kunit_parser.parse_run_tests(file.readlines())
self.print_mock.assert_any_call(StrContains('suite (1 
subtest)'))
 
+   def test_parse_attributes(self):
+   ktap_log = test_data_path('test_parse_attributes.log')
+   with open(ktap_log) as file:
+   result = kunit_parser.parse_run_tests(file.readlines())
+
+   # Test should pass with no errors
+   self.assertEqual(result.counts, 
kunit_parser.TestCounts(passed=1, errors=0))
+   self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+
+   # Ensure suite header is parsed correctly
+   self.print_mock.assert_any_call(StrContains('suite (1 
subtest)'))
+
+   # Ensure attributes in correct test log
+   self.assertContains('# module: example', result.subtests[0].log)
+   self.assertContains('# test.speed: slow', 
result.subtests[0].subtests[0].log)
+
def test_show_test_output_on_failure(self):
output = """
KTAP version 1
diff --git a/tools/testing/kunit/test_data/test_parse_attributes.log 
b/tools/testing/kunit/test_data/test_parse_attributes.log
new file mode 100644
index ..1a13c371fe9d
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_parse_attributes.log
@@ -0,0 +1,9 @@
+KTAP version 1
+1..1
+  KTAP version 1
+  # Subtest: suite
+  # module: example
+  1..1
+  # test.speed: slow
+  ok 1 test
+ok 1 suite
\ No newline at end of file
-- 
2.43.0.472.g3155946c3a-goog




[PATCH v3 2/2] kunit: tool: add test for parsing attributes

2023-12-08 Thread Rae Moar
Add test for parsing attributes to kunit_tool_test.py. Test checks
attributes are parsed and saved in the test logs.

This test also checks that the attributes have not interfered with the
parsing of other test information, specifically the suite header as
the test plan was being incorrectely parsed.

Signed-off-by: Rae Moar 
---
 tools/testing/kunit/kunit_tool_test.py   | 16 
 .../kunit/test_data/test_parse_attributes.log|  9 +
 2 files changed, 25 insertions(+)
 create mode 100644 tools/testing/kunit/test_data/test_parse_attributes.log

diff --git a/tools/testing/kunit/kunit_tool_test.py 
b/tools/testing/kunit/kunit_tool_test.py
index b28c1510be2e..2beb7327e53f 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -331,6 +331,22 @@ class KUnitParserTest(unittest.TestCase):
kunit_parser.parse_run_tests(file.readlines())
self.print_mock.assert_any_call(StrContains('suite (1 
subtest)'))
 
+   def test_parse_attributes(self):
+   ktap_log = test_data_path('test_parse_attributes.log')
+   with open(ktap_log) as file:
+   result = kunit_parser.parse_run_tests(file.readlines())
+
+   # Test should pass with no errors
+   self.assertEqual(result.counts, 
kunit_parser.TestCounts(passed=1, errors=0))
+   self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
+
+   # Ensure suite header is parsed correctly
+   self.print_mock.assert_any_call(StrContains('suite (1 
subtest)'))
+
+   # Ensure attributes in correct test log
+   self.assertContains('# module: example', result.subtests[0].log)
+   self.assertContains('# test.speed: slow', 
result.subtests[0].subtests[0].log)
+
def test_show_test_output_on_failure(self):
output = """
KTAP version 1
diff --git a/tools/testing/kunit/test_data/test_parse_attributes.log 
b/tools/testing/kunit/test_data/test_parse_attributes.log
new file mode 100644
index ..74df125d0863
--- /dev/null
+++ b/tools/testing/kunit/test_data/test_parse_attributes.log
@@ -0,0 +1,9 @@
+KTAP version 1
+1..1
+  KTAP version 1
+  # Subtest: suite
+  # module: example
+  1..1
+  # test.speed: slow
+  ok 1 test
+ok 1 suite
-- 
2.43.0.472.g3155946c3a-goog




[PATCH v3 1/2] kunit: tool: fix parsing of test attributes

2023-12-08 Thread Rae Moar
Add parsing of attributes as diagnostic data. Fixes issue with test plan
being parsed incorrectly as diagnostic data when located after
suite-level attributes.

Note that if there does not exist a test plan line, the diagnostic lines
between the suite header and the first result will be saved in the suite
log rather than the first test case log.

Signed-off-by: Rae Moar 
---
 tools/testing/kunit/kunit_parser.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/testing/kunit/kunit_parser.py 
b/tools/testing/kunit/kunit_parser.py
index 79d8832c862a..ce34be15c929 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -450,7 +450,7 @@ def parse_diagnostic(lines: LineStream) -> List[str]:
Log of diagnostic lines
"""
log = []  # type: List[str]
-   non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, TAP_START]
+   non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, 
TAP_START, TEST_PLAN]
while lines and not any(re.match(lines.peek())
for re in non_diagnostic_lines):
log.append(lines.pop())
@@ -726,6 +726,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
# test plan
test.name = "main"
ktap_line = parse_ktap_header(lines, test)
+   test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
parent_test = True
else:
@@ -737,6 +738,7 @@ def parse_test(lines: LineStream, expected_num: int, log: 
List[str], is_subtest:
if parent_test:
# If KTAP version line and/or subtest header is found, 
attempt
# to parse test plan and print test header
+   test.log.extend(parse_diagnostic(lines))
parse_test_plan(lines, test)
print_test_header(test)
expected_count = test.expected_count

base-commit: b85ea95d086471afb4ad062012a4d73cd328fa86
-- 
2.43.0.472.g3155946c3a-goog




Re: [PATCH] kunit: test: Use an action wrapper instead of a cast

2023-12-08 Thread Rae Moar
On Wed, Dec 6, 2023 at 3:23 AM David Gow  wrote:
>
> We missed one of the casts of kfree() to kunit_action_t in kunit-test,
> which was only enabled when debugfs was in use. This could potentially
> break CFI.
>
> Use the existing wrapper function instead.
>
> Signed-off-by: David Gow 

Hello!

This looks good to me. All ready to go.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
>  lib/kunit/kunit-test.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
> index 3e9c5192d095..ee6927c60979 100644
> --- a/lib/kunit/kunit-test.c
> +++ b/lib/kunit/kunit-test.c
> @@ -559,7 +559,7 @@ static void kunit_log_test(struct kunit *test)
> KUNIT_EXPECT_TRUE(test, test->log->append_newlines);
>
> full_log = string_stream_get_string(test->log);
> -   kunit_add_action(test, (kunit_action_t *)kfree, full_log);
> +   kunit_add_action(test, kfree_wrapper, full_log);
> KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
>  strstr(full_log, "put this in log."));
> KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
> --
> 2.43.0.rc2.451.g8631bc7472-goog
>



Re: [PATCH v3 1/6] kunit: move KUNIT_TABLE out of INIT_DATA

2023-12-11 Thread Rae Moar
On Sat, Dec 9, 2023 at 2:48 AM David Gow  wrote:
>
> On Tue, 5 Dec 2023 at 06:19, Rae Moar  wrote:
> >
> > Alter the linker section of KUNIT_TABLE to move it out of INIT_DATA and
> > into DATA_DATA.
> >
> > Data for KUnit tests does not need to be in the init section.
> >
> > In order to run tests again after boot the KUnit data cannot be labeled as
> > init data as the kernel could write over it.
> >
> > Add a KUNIT_INIT_TABLE in the next patch for KUnit tests that test init
> > data/functions.
> >
> > Signed-off-by: Rae Moar 
> > ---
>
> I think this actually fixes a potential bug, as we loop through the
> list of suites after init has ended in the debugfs logic.
>
> So maybe this is:
> Fixes: 90a025a859a3 ("vmlinux.lds.h: add linker section for KUnit test 
> suites")
>
> Regardless, I'd love to get this in, even if we don't manage to get
> the rest of the series in soon.
>
> Reviewed-by: David Gow 
>
> Cheers,
> -- David

Hello!

Thanks for reviewing! I will be adding this fixes tag. Should I make
this a separate patch for the next version?

Thanks!
-Rae

>
> >  include/asm-generic/vmlinux.lds.h | 6 +++---
> >  1 file changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/include/asm-generic/vmlinux.lds.h 
> > b/include/asm-generic/vmlinux.lds.h
> > index bae0fe4d499b..1107905d37fc 100644
> > --- a/include/asm-generic/vmlinux.lds.h
> > +++ b/include/asm-generic/vmlinux.lds.h
> > @@ -370,7 +370,8 @@
> > BRANCH_PROFILE()\
> > TRACE_PRINTKS() \
> > BPF_RAW_TP()\
> > -   TRACEPOINT_STR()
> > +   TRACEPOINT_STR()\
> > +   KUNIT_TABLE()
> >
> >  /*
> >   * Data section helpers
> > @@ -699,8 +700,7 @@
> > THERMAL_TABLE(governor) \
> > EARLYCON_TABLE()\
> > LSM_TABLE() \
> > -   EARLY_LSM_TABLE()   \
> > -   KUNIT_TABLE()
> > +   EARLY_LSM_TABLE()
> >
> >  #define INIT_TEXT  \
> > *(.init.text .init.text.*)  \
> >
> > base-commit: b85ea95d086471afb4ad062012a4d73cd328fa86
> > --
> > 2.43.0.rc2.451.g8631bc7472-goog
> >



Re: [PATCH v3 6/6] Documentation: Add debugfs docs with run after boot

2023-12-11 Thread Rae Moar
On Sat, Dec 9, 2023 at 2:58 AM David Gow  wrote:
>
> On Tue, 5 Dec 2023 at 06:19, Rae Moar  wrote:
> >
> > Expand the documentation on the KUnit debugfs filesystem on the
> > run_manual.rst page.
> >
> > Add section describing how to access results using debugfs.
> >
> > Add section describing how to run tests after boot using debugfs.
> >
> > Signed-off-by: Rae Moar 
> > ---
>
> Looks good to me, some nitpicks below.
>
> The other thing I'd really want to add is some documentation on
> writing init-section suites, which covers the pitfalls better (as
> mentioned in the previous emails). Though that could be a separate
> patch if you want to keep this one debugfs-specific.
>
> Otherwise,
> Reviewed-by: David Gow 
>
> Cheers,
> -- David

Hello!

I have responded to your comments below. I would also be happy to add
documentation to the init-section suites either in this patch series
or in a future one.

Thanks!
-Rae

>
> >
> > Changes since v2:
> > - Add info to documentation about cleaning up data, init tests, and
> >   running tests concurrently
> >
> >  Documentation/dev-tools/kunit/run_manual.rst | 49 ++--
> >  1 file changed, 45 insertions(+), 4 deletions(-)
> >
> > diff --git a/Documentation/dev-tools/kunit/run_manual.rst 
> > b/Documentation/dev-tools/kunit/run_manual.rst
> > index e7b46421f247..aebb52ba9605 100644
> > --- a/Documentation/dev-tools/kunit/run_manual.rst
> > +++ b/Documentation/dev-tools/kunit/run_manual.rst
> > @@ -49,9 +49,50 @@ loaded.
> >
> >  The results will appear in TAP format in ``dmesg``.
> >
> > +debugfs
> > +===
> > +
> > +``debugfs`` is a file system that enables user interaction with the files 
> > to
> > +make kernel information available to user space (See more information at
> > +Documentation/filesystems/debugfs.html)
>
> Nit: reference debugfs.rst here, not debugfs.html -- sphinx ought to
> update the link automatically.

Thanks for catching this! I didn't realize Sphinx would update it.

>
> Also, maybe we can make this introduction a _little_ bit more
> KUnit-specific. I'd personally start by saying that KUnit can be
> accessed from userspace via the debugfs filesystem (link), usually
> mounted in /sys/kernel/debug/kunit, etc, if CONFIG_KUNIT_DEBUGFS is
> enabled.

Ok I will add this for the next version.

>
> > +
> > +By default, only the root user has access to the debugfs directory.
> > +
> > +If ``CONFIG_KUNIT_DEBUGFS`` is enabled, you can use KUnit debugfs
> > +filesystem to perform the following actions.
> > +
> > +Retrieve Test Results
> > +=
> > +
> > +You can use debugfs to retrieve KUnit test results. The test results are
> > +accessible from the debugfs filesystem in the following read-only file:
> > +
> > +.. code-block :: bash
> > +
> > +   /sys/kernel/debug/kunit//results
> > +
> > +The test results are available in KTAP format.
>
> Do we want to note that this is a separate KTAP document, and so may
> have different suite numbering from the dmesg log?

Sure! I will add this for the next version.

>
> > +
> > +Run Tests After Kernel Has Booted
> > +=
> > +
> > +You can use the debugfs filesystem to trigger built-in tests to run after
> > +boot. To run the test suite, you can use the following command to write to
> > +the ``/sys/kernel/debug/kunit//run`` file:
> > +
> > +.. code-block :: bash
> > +
> > +   echo "any string" > /sys/kernel/debugfs/kunit//run
> > +
> > +As a result, the test suite runs and the results are printed to the kernel
> > +log.
> > +
> > +However, this feature is not available with KUnit tests that use init data.
>
> Let's expand this slightly, and mention that this is because the data
> may have already been discarded, and that you can find such tests by
> either looking for the kunit_test_init_section_suites() macro or the
> is_init attribute.

Got it. I will definitely expand this more.

>
> > +
> > +Also, you cannot use this feature to run tests concurrently as there is a
> > +mutex lock around running KUnit tests at the same time.
> > +
>
> Instead of mentioning the mutex, which is an implementation detail,
> just mention that tests will either wait for other tests to complete,
> or fail having timed out.
>

I will definitely switch this out in the next version.

>
>
> >  .. note ::
> >
> > -   If ``CONFIG_KUNIT_DEBUGFS`` is enabled, KUnit test results will
> > -   be accessible from the ``debugfs`` filesystem (if mounted).
> > -   They will be in ``/sys/kernel/debug/kunit//results``, in
> > -   TAP format.
> > +   For test authors, to use this feature, tests will need to correctly 
> > initialise
> > +   and/or clean up any data, so the test runs correctly a second time.
> > --
> > 2.43.0.rc2.451.g8631bc7472-goog
> >



Re: [PATCH v3 4/6] kunit: add is_init test attribute

2023-12-11 Thread Rae Moar
On Sat, Dec 9, 2023 at 2:57 AM David Gow  wrote:
>
> On Tue, 5 Dec 2023 at 06:19, Rae Moar  wrote:
> >
> > Add is_init test attribute of type bool. Add to_string, get, and filter
> > methods to lib/kunit/attributes.c.
> >
> > Mark each of the tests in the init section with the is_init=true attribute.
> >
> > Add is_init to the attributes documentation.
> >
> > Signed-off-by: Rae Moar 
> > ---
>
> Would it be possible to not have this in kunit_attributes? I know it's
> required for the run-after-boot stuff later, but I'd love this to be
> (a) just generated at runtime, or (b) stored only at a suite or
> suite-set level. It seems like a bit of a waste to store this
> per-test-case, and to have it potentially accessible or overwritable
> by users.
>
> Otherwise, this looks good (and I appreciate the automatic setting of
> this when merging the suite sets.
>
> Maybe if we always kept the init suites in a separate set, we could
> just use pointer comparisons to generate this; otherwise let's make
> this a suite-level-only attribute (inherited by tests).
>
>
> -- David

Hello!

I did consider making is_init a field within a suite object instead
and then pointing to that in the kunit_attributes framework during
filtering, printing, etc... I will change that out in the next
version.

Thanks!
-Rae



[PATCH v4 1/6] kunit: move KUNIT_TABLE out of INIT_DATA

2023-12-12 Thread Rae Moar
Alter the linker section of KUNIT_TABLE to move it out of INIT_DATA and
into DATA_DATA.

Data for KUnit tests does not need to be in the init section.

In order to run tests again after boot the KUnit data cannot be labeled as
init data as the kernel could write over it.

Add a KUNIT_INIT_TABLE in the next patch for KUnit tests that test init
data/functions.

Signed-off-by: Rae Moar 
---
Changes since v3:
- No changes

 include/asm-generic/vmlinux.lds.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index bae0fe4d499b..1107905d37fc 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -370,7 +370,8 @@
BRANCH_PROFILE()\
TRACE_PRINTKS() \
BPF_RAW_TP()\
-   TRACEPOINT_STR()
+   TRACEPOINT_STR()\
+   KUNIT_TABLE()
 
 /*
  * Data section helpers
@@ -699,8 +700,7 @@
THERMAL_TABLE(governor) \
EARLYCON_TABLE()\
LSM_TABLE() \
-   EARLY_LSM_TABLE()   \
-   KUNIT_TABLE()
+   EARLY_LSM_TABLE()
 
 #define INIT_TEXT  \
*(.init.text .init.text.*)  \

base-commit: b285ba6f8cc1b2bfece0b4350fdb92c8780bc698
-- 
2.43.0.472.g3155946c3a-goog




[PATCH v4 3/6] kunit: add example suite to test init suites

2023-12-12 Thread Rae Moar
Add example_init_test_suite to allow for testing the feature of running
test suites marked as init to indicate they use init data and/or
functions.

This suite should always pass and uses a simple init function.

This suite can also be used to test the is_init attribute introduced in
the next patch.

Signed-off-by: Rae Moar 
---
Changes since v3:
- I ended up not changing anything as adding __init to the test gave
  a build warning. It did still work so I could add it back if wanted.

 lib/kunit/kunit-example-test.c | 37 ++
 1 file changed, 37 insertions(+)

diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
index 6bb5c2ef6696..18495778de7c 100644
--- a/lib/kunit/kunit-example-test.c
+++ b/lib/kunit/kunit-example-test.c
@@ -287,4 +287,41 @@ static struct kunit_suite example_test_suite = {
  */
 kunit_test_suites(&example_test_suite);
 
+static int __init init_add(int x, int y)
+{
+   return (x + y);
+}
+
+/*
+ * This test should always pass. Can be used to test init suites.
+ */
+static void example_init_test(struct kunit *test)
+{
+   KUNIT_EXPECT_EQ(test, init_add(1, 1), 2);
+}
+
+/*
+ * The kunit_case struct cannot be marked as __initdata as this will be
+ * used in debugfs to retrieve results after test has run
+ */
+static struct kunit_case example_init_test_cases[] = {
+   KUNIT_CASE(example_init_test),
+   {}
+};
+
+/*
+ * The kunit_suite struct cannot be marked as __initdata as this will be
+ * used in debugfs to retrieve results after test has run
+ */
+static struct kunit_suite example_init_test_suite = {
+   .name = "example_init",
+   .test_cases = example_init_test_cases,
+};
+
+/*
+ * This registers the test suite and marks the suite as using init data
+ * and/or functions.
+ */
+kunit_test_init_section_suites(&example_init_test_suite);
+
 MODULE_LICENSE("GPL v2");
-- 
2.43.0.472.g3155946c3a-goog




[PATCH v4 2/6] kunit: add KUNIT_INIT_TABLE to init linker section

2023-12-12 Thread Rae Moar
Add KUNIT_INIT_TABLE to the INIT_DATA linker section.

Alter the KUnit macros to create init tests:
kunit_test_init_section_suites

Update lib/kunit/executor.c to run both the suites in KUNIT_TABLE and
KUNIT_INIT_TABLE.

Signed-off-by: Rae Moar 
---
Changes since v3:
- Add to comments in test.h for kunit_test_init_section_suites macro to
  note init tests cannot be run after boot and the structs cannot be
  marked with __initdata

 include/asm-generic/vmlinux.lds.h |  9 -
 include/kunit/test.h  | 30 +--
 include/linux/module.h|  2 +
 kernel/module/main.c  |  3 ++
 lib/kunit/executor.c  | 64 ---
 lib/kunit/test.c  | 26 +
 6 files changed, 109 insertions(+), 25 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 1107905d37fc..5dd3a61d673d 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -700,7 +700,8 @@
THERMAL_TABLE(governor) \
EARLYCON_TABLE()\
LSM_TABLE() \
-   EARLY_LSM_TABLE()
+   EARLY_LSM_TABLE()   \
+   KUNIT_INIT_TABLE()
 
 #define INIT_TEXT  \
*(.init.text .init.text.*)  \
@@ -926,6 +927,12 @@
. = ALIGN(8);   \
BOUNDED_SECTION_POST_LABEL(.kunit_test_suites, __kunit_suites, 
_start, _end)
 
+/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
+#define KUNIT_INIT_TABLE() \
+   . = ALIGN(8);   \
+   BOUNDED_SECTION_POST_LABEL(.kunit_init_test_suites, \
+   __kunit_init_suites, _start, _end)
+
 #ifdef CONFIG_BLK_DEV_INITRD
 #define INIT_RAM_FS\
. = ALIGN(4);   \
diff --git a/include/kunit/test.h b/include/kunit/test.h
index 20ed9f9275c9..fe79cd736e94 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -337,6 +337,9 @@ void __kunit_test_suites_exit(struct kunit_suite **suites, 
int num_suites);
 void kunit_exec_run_tests(struct kunit_suite_set *suite_set, bool builtin);
 void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool 
include_attr);
 
+struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set 
init_suite_set,
+   struct kunit_suite_set suite_set);
+
 #if IS_BUILTIN(CONFIG_KUNIT)
 int kunit_run_all_tests(void);
 #else
@@ -371,6 +374,11 @@ static inline int kunit_run_all_tests(void)
 
 #define kunit_test_suite(suite)kunit_test_suites(&suite)
 
+#define __kunit_init_test_suites(unique_array, ...)   \
+   static struct kunit_suite *unique_array[]  \
+   __aligned(sizeof(struct kunit_suite *))\
+   __used __section(".kunit_init_test_suites") = { __VA_ARGS__ }
+
 /**
  * kunit_test_init_section_suites() - used to register one or more &struct
  *   kunit_suite containing init functions or
@@ -378,21 +386,21 @@ static inline int kunit_run_all_tests(void)
  *
  * @__suites: a statically allocated list of &struct kunit_suite.
  *
- * This functions identically as kunit_test_suites() except that it suppresses
- * modpost warnings for referencing functions marked __init or data marked
- * __initdata; this is OK because currently KUnit only runs tests upon boot
- * during the init phase or upon loading a module during the init phase.
+ * This functions similar to kunit_test_suites() except that it compiles the
+ * list of suites during init phase.
+ *
+ * This macro also suffixes the array and suite declarations it makes with
+ * _probe; so that modpost suppresses warnings about referencing init data
+ * for symbols named in this manner.
  *
- * NOTE TO KUNIT DEVS: If we ever allow KUnit tests to be run after boot, these
- * tests must be excluded.
+ * Note: these init tests are not able to be run after boot so there is no
+ * "run" debugfs file generated for these tests.
  *
- * The only thing this macro does that's different from kunit_test_suites is
- * that it suffixes the array and suite declarations it makes with _probe;
- * modpost suppresses warnings about referencing init data for symbols named in
- * this manner.
+ * Also, do not mark the suite or test case structs with __initdata because
+ * they will be used after the init phase with debugfs.
  */
 #define kunit_test_init_section_suites(__suites...)\
- 

[PATCH v4 4/6] kunit: add is_init test attribute

2023-12-12 Thread Rae Moar
Add is_init test attribute of type bool. Add to_string, get, and filter
methods to lib/kunit/attributes.c.

Mark each of the tests in the init section with the is_init=true attribute.

Add is_init to the attributes documentation.

Signed-off-by: Rae Moar 
---
Changes since v3:
- Move the attribute from kunit_attributes to a suite field.

 .../dev-tools/kunit/running_tips.rst  |  7 +++
 include/kunit/test.h  |  1 +
 lib/kunit/attributes.c| 60 +++
 lib/kunit/executor.c  |  6 +-
 4 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/Documentation/dev-tools/kunit/running_tips.rst 
b/Documentation/dev-tools/kunit/running_tips.rst
index 766f9cdea0fa..024e9ad1d1e9 100644
--- a/Documentation/dev-tools/kunit/running_tips.rst
+++ b/Documentation/dev-tools/kunit/running_tips.rst
@@ -428,3 +428,10 @@ This attribute indicates the name of the module associated 
with the test.
 
 This attribute is automatically saved as a string and is printed for each 
suite.
 Tests can also be filtered using this attribute.
+
+``is_init``
+
+This attribute indicates whether the test uses init data or functions.
+
+This attribute is automatically saved as a boolean and tests can also be
+filtered using this attribute.
diff --git a/include/kunit/test.h b/include/kunit/test.h
index fe79cd736e94..b163b9984b33 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -253,6 +253,7 @@ struct kunit_suite {
struct dentry *debugfs;
struct string_stream *log;
int suite_init_err;
+   bool is_init;
 };
 
 /* Stores an array of suites, end points one past the end */
diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index 1b512f7e1838..2cf04cc09372 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -58,6 +58,16 @@ static const char *attr_enum_to_string(void *attr, const 
char * const str_list[]
return str_list[val];
 }
 
+static const char *attr_bool_to_string(void *attr, bool *to_free)
+{
+   bool val = (bool)attr;
+
+   *to_free = false;
+   if (val)
+   return "true";
+   return "false";
+}
+
 static const char *attr_speed_to_string(void *attr, bool *to_free)
 {
return attr_enum_to_string(attr, speed_str_list, to_free);
@@ -166,6 +176,37 @@ static int attr_string_filter(void *attr, const char 
*input, int *err)
return false;
 }
 
+static int attr_bool_filter(void *attr, const char *input, int *err)
+{
+   int i, input_int = -1;
+   long val = (long)attr;
+   const char *input_str = NULL;
+
+   for (i = 0; input[i]; i++) {
+   if (!strchr(op_list, input[i])) {
+   input_str = input + i;
+   break;
+   }
+   }
+
+   if (!input_str) {
+   *err = -EINVAL;
+   pr_err("kunit executor: filter value not found: %s\n", input);
+   return false;
+   }
+
+   if (!strcmp(input_str, "true"))
+   input_int = (int)true;
+   else if (!strcmp(input_str, "false"))
+   input_int = (int)false;
+   else {
+   *err = -EINVAL;
+   pr_err("kunit executor: invalid filter input: %s\n", input);
+   return false;
+   }
+
+   return int_filter(val, input, input_int, err);
+}
 
 /* Get Attribute Methods */
 
@@ -194,6 +235,17 @@ static void *attr_module_get(void *test_or_suite, bool 
is_test)
return (void *) "";
 }
 
+static void *attr_is_init_get(void *test_or_suite, bool is_test)
+{
+   struct kunit_suite *suite = is_test ? NULL : test_or_suite;
+   struct kunit_case *test = is_test ? test_or_suite : NULL;
+
+   if (test)
+   return ((void *) NULL);
+   else
+   return ((void *) suite->is_init);
+}
+
 /* List of all Test Attributes */
 
 static struct kunit_attr kunit_attr_list[] = {
@@ -212,6 +264,14 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_string_filter,
.attr_default = (void *)"",
.print = PRINT_SUITE,
+   },
+   {
+   .name = "is_init",
+   .get_attr = attr_is_init_get,
+   .to_string = attr_bool_to_string,
+   .filter = attr_bool_filter,
+   .attr_default = (void *)false,
+   .print = PRINT_SUITE,
}
 };
 
diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 847329c51e91..717b9599036b 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -300,6 +300,7 @@ struct kunit_suite_set kunit_merge_suite_sets(struct 
kunit_suite_set init_suite_
struct kunit_suite_set total_suite_set = {NULL, NULL};
struct kunit_suite **total_suite_start = NULL;
size_t init_num_suites, num_suites, suite_size;
+   int i =

[PATCH v4 5/6] kunit: add ability to run tests after boot using debugfs

2023-12-12 Thread Rae Moar
Add functionality to run built-in tests after boot by writing to a
debugfs file.

Add a new debugfs file labeled "run" for each test suite to use for
this purpose.

As an example, write to the file using the following:

echo "any string" > /sys/kernel/debugfs/kunit//run

This will trigger the test suite to run and will print results to the
kernel log.

To guard against running tests concurrently with this feature, add a
mutex lock around running kunit. This supports the current practice of
not allowing tests to be run concurrently on the same kernel.

This new functionality could be used to design a parameter
injection feature in the future.

Signed-off-by: Rae Moar 
---
Changes since v4:
- Rebased series causing a few small changes in debugfs.c in this patch

 lib/kunit/debugfs.c | 68 +
 lib/kunit/test.c| 10 +++
 2 files changed, 78 insertions(+)

diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
index 382706dfb47d..d548750a325a 100644
--- a/lib/kunit/debugfs.c
+++ b/lib/kunit/debugfs.c
@@ -8,12 +8,14 @@
 #include 
 
 #include 
+#include 
 
 #include "string-stream.h"
 #include "debugfs.h"
 
 #define KUNIT_DEBUGFS_ROOT "kunit"
 #define KUNIT_DEBUGFS_RESULTS  "results"
+#define KUNIT_DEBUGFS_RUN  "run"
 
 /*
  * Create a debugfs representation of test suites:
@@ -21,6 +23,8 @@
  * PathSemantics
  * /sys/kernel/debug/kunit//results Show results of last run for
  * testsuite
+ * /sys/kernel/debug/kunit//run Write to this file to trigger
+ * testsuite to run
  *
  */
 
@@ -101,6 +105,51 @@ static int debugfs_results_open(struct inode *inode, 
struct file *file)
return single_open(file, debugfs_print_results, suite);
 }
 
+/*
+ * Print a usage message to the debugfs "run" file
+ * (/sys/kernel/debug/kunit//run) if opened.
+ */
+static int debugfs_print_run(struct seq_file *seq, void *v)
+{
+   struct kunit_suite *suite = (struct kunit_suite *)seq->private;
+
+   seq_puts(seq, "Write to this file to trigger the test suite to run.\n");
+   seq_printf(seq, "usage: echo \"any string\" > 
/sys/kernel/debugfs/kunit/%s/run\n",
+   suite->name);
+   return 0;
+}
+
+/*
+ * The debugfs "run" file (/sys/kernel/debug/kunit//run)
+ * contains no information. Write to the file to trigger the test suite
+ * to run.
+ */
+static int debugfs_run_open(struct inode *inode, struct file *file)
+{
+   struct kunit_suite *suite;
+
+   suite = (struct kunit_suite *)inode->i_private;
+
+   return single_open(file, debugfs_print_run, suite);
+}
+
+/*
+ * Trigger a test suite to run by writing to the suite's "run" debugfs
+ * file found at: /sys/kernel/debug/kunit//run
+ *
+ * Note: what is written to this file will not be saved.
+ */
+static ssize_t debugfs_run(struct file *file,
+   const char __user *buf, size_t count, loff_t *ppos)
+{
+   struct inode *f_inode = file->f_inode;
+   struct kunit_suite *suite = (struct kunit_suite *) f_inode->i_private;
+
+   __kunit_test_suites_init(&suite, 1);
+
+   return count;
+}
+
 static const struct file_operations debugfs_results_fops = {
.open = debugfs_results_open,
.read = seq_read,
@@ -108,11 +157,23 @@ static const struct file_operations debugfs_results_fops 
= {
.release = debugfs_release,
 };
 
+static const struct file_operations debugfs_run_fops = {
+   .open = debugfs_run_open,
+   .read = seq_read,
+   .write = debugfs_run,
+   .llseek = seq_lseek,
+   .release = debugfs_release,
+};
+
 void kunit_debugfs_create_suite(struct kunit_suite *suite)
 {
struct kunit_case *test_case;
struct string_stream *stream;
 
+   /* If suite log already allocated, do not create new debugfs files. */
+   if (suite->log)
+   return;
+
/*
 * Allocate logs before creating debugfs representation.
 * The suite->log and test_case->log pointer are expected to be NULL
@@ -140,6 +201,13 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite)
debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444,
suite->debugfs,
suite, &debugfs_results_fops);
+
+   /* Do not create file to re-run test if test runs on init */
+   if (!suite->is_init) {
+   debugfs_create_file(KUNIT_DEBUGFS_RUN, S_IFREG | 0644,
+   suite->debugfs,
+   suite, &debugfs_run_fops);
+   }
return;
 
 err:
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 6c082911a85f..a52fcb9a4457 100644

[PATCH v4 6/6] Documentation: Add debugfs docs with run after boot

2023-12-12 Thread Rae Moar
Expand the documentation on the KUnit debugfs filesystem on the
run_manual.rst page.

Add section describing how to access results using debugfs.

Add section describing how to run tests after boot using debugfs.

Signed-off-by: Rae Moar 
---
Changes since v3:
- Change the introduction of the debugfs section
- Add detail to not being able to run concurrently or run with init data

 Documentation/dev-tools/kunit/run_manual.rst | 51 ++--
 1 file changed, 47 insertions(+), 4 deletions(-)

diff --git a/Documentation/dev-tools/kunit/run_manual.rst 
b/Documentation/dev-tools/kunit/run_manual.rst
index e7b46421f247..699d92885075 100644
--- a/Documentation/dev-tools/kunit/run_manual.rst
+++ b/Documentation/dev-tools/kunit/run_manual.rst
@@ -49,9 +49,52 @@ loaded.
 
 The results will appear in TAP format in ``dmesg``.
 
+debugfs
+===
+
+KUnit can be accessed from userspace via the debugfs filesystem (See more
+information about debugfs at Documentation/filesystems/debugfs.rst).
+
+If ``CONFIG_KUNIT_DEBUGFS`` is enabled, the KUnit debugfs filesystem is
+mounted at /sys/kernel/debug/kunit. You can use this filesystem to perform
+the following actions.
+
+Retrieve Test Results
+=
+
+You can use debugfs to retrieve KUnit test results. The test results are
+accessible from the debugfs filesystem in the following read-only file:
+
+.. code-block :: bash
+
+   /sys/kernel/debug/kunit//results
+
+The test results are printed in a KTAP document. Note this document is separate
+to the kernel log and thus, may have different test suite numbering.
+
+Run Tests After Kernel Has Booted
+=
+
+You can use the debugfs filesystem to trigger built-in tests to run after
+boot. To run the test suite, you can use the following command to write to
+the ``/sys/kernel/debug/kunit//run`` file:
+
+.. code-block :: bash
+
+   echo "any string" > /sys/kernel/debugfs/kunit//run
+
+As a result, the test suite runs and the results are printed to the kernel
+log.
+
+However, this feature is not available with KUnit suites that use init data,
+because init data may have been discarded after the kernel boots. KUnit
+suites that use init data should be defined using the
+kunit_test_init_section_suites() macro.
+
+Also, you cannot use this feature to run tests concurrently. Instead a test
+will wait to run until other tests have completed or failed.
+
 .. note ::
 
-   If ``CONFIG_KUNIT_DEBUGFS`` is enabled, KUnit test results will
-   be accessible from the ``debugfs`` filesystem (if mounted).
-   They will be in ``/sys/kernel/debug/kunit//results``, in
-   TAP format.
+   For test authors, to use this feature, tests will need to correctly 
initialise
+   and/or clean up any data, so the test runs correctly a second time.
-- 
2.43.0.472.g3155946c3a-goog




[PATCH v5 1/6] kunit: move KUNIT_TABLE out of INIT_DATA

2023-12-13 Thread Rae Moar
Alter the linker section of KUNIT_TABLE to move it out of INIT_DATA and
into DATA_DATA.

Data for KUnit tests does not need to be in the init section.

In order to run tests again after boot the KUnit data cannot be labeled as
init data as the kernel could write over it.

Add a KUNIT_INIT_TABLE in the next patch for KUnit tests that test init
data/functions.

Reviewed-by: David Gow 
Signed-off-by: Rae Moar 
---
 include/asm-generic/vmlinux.lds.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index bae0fe4d499b..1107905d37fc 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -370,7 +370,8 @@
BRANCH_PROFILE()\
TRACE_PRINTKS() \
BPF_RAW_TP()\
-   TRACEPOINT_STR()
+   TRACEPOINT_STR()\
+   KUNIT_TABLE()
 
 /*
  * Data section helpers
@@ -699,8 +700,7 @@
THERMAL_TABLE(governor) \
EARLYCON_TABLE()\
LSM_TABLE() \
-   EARLY_LSM_TABLE()   \
-   KUNIT_TABLE()
+   EARLY_LSM_TABLE()
 
 #define INIT_TEXT  \
*(.init.text .init.text.*)  \

base-commit: b285ba6f8cc1b2bfece0b4350fdb92c8780bc698
-- 
2.43.0.472.g3155946c3a-goog




[PATCH v5 3/6] kunit: add example suite to test init suites

2023-12-13 Thread Rae Moar
Add example_init_test_suite to allow for testing the feature of running
test suites marked as init to indicate they use init data and/or
functions.

This suite should always pass and uses a simple init function.

This suite can also be used to test the is_init attribute introduced in
the next patch.

Signed-off-by: Rae Moar 
---
Changes since v4:
- Mark test as __init and then set cases as __refdata to supress modpost
  warnings

 lib/kunit/kunit-example-test.c | 37 ++
 1 file changed, 37 insertions(+)

diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
index 6bb5c2ef6696..d2f7a3c62c18 100644
--- a/lib/kunit/kunit-example-test.c
+++ b/lib/kunit/kunit-example-test.c
@@ -287,4 +287,41 @@ static struct kunit_suite example_test_suite = {
  */
 kunit_test_suites(&example_test_suite);
 
+static int __init init_add(int x, int y)
+{
+   return (x + y);
+}
+
+/*
+ * This test should always pass. Can be used to test init suites.
+ */
+static void __init example_init_test(struct kunit *test)
+{
+   KUNIT_EXPECT_EQ(test, init_add(1, 1), 2);
+}
+
+/*
+ * The kunit_case struct cannot be marked as __initdata as this will be
+ * used in debugfs to retrieve results after test has run
+ */
+static struct kunit_case __refdata example_init_test_cases[] = {
+   KUNIT_CASE(example_init_test),
+   {}
+};
+
+/*
+ * The kunit_suite struct cannot be marked as __initdata as this will be
+ * used in debugfs to retrieve results after test has run
+ */
+static struct kunit_suite example_init_test_suite = {
+   .name = "example_init",
+   .test_cases = example_init_test_cases,
+};
+
+/*
+ * This registers the test suite and marks the suite as using init data
+ * and/or functions.
+ */
+kunit_test_init_section_suites(&example_init_test_suite);
+
 MODULE_LICENSE("GPL v2");
-- 
2.43.0.472.g3155946c3a-goog




[PATCH v5 2/6] kunit: add KUNIT_INIT_TABLE to init linker section

2023-12-13 Thread Rae Moar
Add KUNIT_INIT_TABLE to the INIT_DATA linker section.

Alter the KUnit macros to create init tests:
kunit_test_init_section_suites

Update lib/kunit/executor.c to run both the suites in KUNIT_TABLE and
KUNIT_INIT_TABLE.

Reviewed-by: David Gow 
Signed-off-by: Rae Moar 
---
 include/asm-generic/vmlinux.lds.h |  9 -
 include/kunit/test.h  | 30 +--
 include/linux/module.h|  2 +
 kernel/module/main.c  |  3 ++
 lib/kunit/executor.c  | 64 ---
 lib/kunit/test.c  | 26 +
 6 files changed, 109 insertions(+), 25 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 1107905d37fc..5dd3a61d673d 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -700,7 +700,8 @@
THERMAL_TABLE(governor) \
EARLYCON_TABLE()\
LSM_TABLE() \
-   EARLY_LSM_TABLE()
+   EARLY_LSM_TABLE()   \
+   KUNIT_INIT_TABLE()
 
 #define INIT_TEXT  \
*(.init.text .init.text.*)  \
@@ -926,6 +927,12 @@
. = ALIGN(8);   \
BOUNDED_SECTION_POST_LABEL(.kunit_test_suites, __kunit_suites, 
_start, _end)
 
+/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
+#define KUNIT_INIT_TABLE() \
+   . = ALIGN(8);   \
+   BOUNDED_SECTION_POST_LABEL(.kunit_init_test_suites, \
+   __kunit_init_suites, _start, _end)
+
 #ifdef CONFIG_BLK_DEV_INITRD
 #define INIT_RAM_FS\
. = ALIGN(4);   \
diff --git a/include/kunit/test.h b/include/kunit/test.h
index 20ed9f9275c9..fe79cd736e94 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -337,6 +337,9 @@ void __kunit_test_suites_exit(struct kunit_suite **suites, 
int num_suites);
 void kunit_exec_run_tests(struct kunit_suite_set *suite_set, bool builtin);
 void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool 
include_attr);
 
+struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set 
init_suite_set,
+   struct kunit_suite_set suite_set);
+
 #if IS_BUILTIN(CONFIG_KUNIT)
 int kunit_run_all_tests(void);
 #else
@@ -371,6 +374,11 @@ static inline int kunit_run_all_tests(void)
 
 #define kunit_test_suite(suite)kunit_test_suites(&suite)
 
+#define __kunit_init_test_suites(unique_array, ...)   \
+   static struct kunit_suite *unique_array[]  \
+   __aligned(sizeof(struct kunit_suite *))\
+   __used __section(".kunit_init_test_suites") = { __VA_ARGS__ }
+
 /**
  * kunit_test_init_section_suites() - used to register one or more &struct
  *   kunit_suite containing init functions or
@@ -378,21 +386,21 @@ static inline int kunit_run_all_tests(void)
  *
  * @__suites: a statically allocated list of &struct kunit_suite.
  *
- * This functions identically as kunit_test_suites() except that it suppresses
- * modpost warnings for referencing functions marked __init or data marked
- * __initdata; this is OK because currently KUnit only runs tests upon boot
- * during the init phase or upon loading a module during the init phase.
+ * This functions similar to kunit_test_suites() except that it compiles the
+ * list of suites during init phase.
+ *
+ * This macro also suffixes the array and suite declarations it makes with
+ * _probe; so that modpost suppresses warnings about referencing init data
+ * for symbols named in this manner.
  *
- * NOTE TO KUNIT DEVS: If we ever allow KUnit tests to be run after boot, these
- * tests must be excluded.
+ * Note: these init tests are not able to be run after boot so there is no
+ * "run" debugfs file generated for these tests.
  *
- * The only thing this macro does that's different from kunit_test_suites is
- * that it suffixes the array and suite declarations it makes with _probe;
- * modpost suppresses warnings about referencing init data for symbols named in
- * this manner.
+ * Also, do not mark the suite or test case structs with __initdata because
+ * they will be used after the init phase with debugfs.
  */
 #define kunit_test_init_section_suites(__suites...)\
-   __kunit_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe),\
+   __kunit_init_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe), \
 

[PATCH v5 4/6] kunit: add is_init test attribute

2023-12-13 Thread Rae Moar
Add is_init test attribute of type bool. Add to_string, get, and filter
methods to lib/kunit/attributes.c.

Mark each of the tests in the init section with the is_init=true attribute.

Add is_init to the attributes documentation.

Reviewed-by: David Gow 
Signed-off-by: Rae Moar 
---
 .../dev-tools/kunit/running_tips.rst  |  7 +++
 include/kunit/test.h  |  1 +
 lib/kunit/attributes.c| 60 +++
 lib/kunit/executor.c  |  6 +-
 4 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/Documentation/dev-tools/kunit/running_tips.rst 
b/Documentation/dev-tools/kunit/running_tips.rst
index 766f9cdea0fa..024e9ad1d1e9 100644
--- a/Documentation/dev-tools/kunit/running_tips.rst
+++ b/Documentation/dev-tools/kunit/running_tips.rst
@@ -428,3 +428,10 @@ This attribute indicates the name of the module associated 
with the test.
 
 This attribute is automatically saved as a string and is printed for each 
suite.
 Tests can also be filtered using this attribute.
+
+``is_init``
+
+This attribute indicates whether the test uses init data or functions.
+
+This attribute is automatically saved as a boolean and tests can also be
+filtered using this attribute.
diff --git a/include/kunit/test.h b/include/kunit/test.h
index fe79cd736e94..b163b9984b33 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -253,6 +253,7 @@ struct kunit_suite {
struct dentry *debugfs;
struct string_stream *log;
int suite_init_err;
+   bool is_init;
 };
 
 /* Stores an array of suites, end points one past the end */
diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index 1b512f7e1838..2cf04cc09372 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -58,6 +58,16 @@ static const char *attr_enum_to_string(void *attr, const 
char * const str_list[]
return str_list[val];
 }
 
+static const char *attr_bool_to_string(void *attr, bool *to_free)
+{
+   bool val = (bool)attr;
+
+   *to_free = false;
+   if (val)
+   return "true";
+   return "false";
+}
+
 static const char *attr_speed_to_string(void *attr, bool *to_free)
 {
return attr_enum_to_string(attr, speed_str_list, to_free);
@@ -166,6 +176,37 @@ static int attr_string_filter(void *attr, const char 
*input, int *err)
return false;
 }
 
+static int attr_bool_filter(void *attr, const char *input, int *err)
+{
+   int i, input_int = -1;
+   long val = (long)attr;
+   const char *input_str = NULL;
+
+   for (i = 0; input[i]; i++) {
+   if (!strchr(op_list, input[i])) {
+   input_str = input + i;
+   break;
+   }
+   }
+
+   if (!input_str) {
+   *err = -EINVAL;
+   pr_err("kunit executor: filter value not found: %s\n", input);
+   return false;
+   }
+
+   if (!strcmp(input_str, "true"))
+   input_int = (int)true;
+   else if (!strcmp(input_str, "false"))
+   input_int = (int)false;
+   else {
+   *err = -EINVAL;
+   pr_err("kunit executor: invalid filter input: %s\n", input);
+   return false;
+   }
+
+   return int_filter(val, input, input_int, err);
+}
 
 /* Get Attribute Methods */
 
@@ -194,6 +235,17 @@ static void *attr_module_get(void *test_or_suite, bool 
is_test)
return (void *) "";
 }
 
+static void *attr_is_init_get(void *test_or_suite, bool is_test)
+{
+   struct kunit_suite *suite = is_test ? NULL : test_or_suite;
+   struct kunit_case *test = is_test ? test_or_suite : NULL;
+
+   if (test)
+   return ((void *) NULL);
+   else
+   return ((void *) suite->is_init);
+}
+
 /* List of all Test Attributes */
 
 static struct kunit_attr kunit_attr_list[] = {
@@ -212,6 +264,14 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_string_filter,
.attr_default = (void *)"",
.print = PRINT_SUITE,
+   },
+   {
+   .name = "is_init",
+   .get_attr = attr_is_init_get,
+   .to_string = attr_bool_to_string,
+   .filter = attr_bool_filter,
+   .attr_default = (void *)false,
+   .print = PRINT_SUITE,
}
 };
 
diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 847329c51e91..717b9599036b 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -300,6 +300,7 @@ struct kunit_suite_set kunit_merge_suite_sets(struct 
kunit_suite_set init_suite_
struct kunit_suite_set total_suite_set = {NULL, NULL};
struct kunit_suite **total_suite_start = NULL;
size_t init_num_suites, num_suites, suite_size;
+   int i = 0;
 
init_num_suites = init_suite_set.end - init_suite

[PATCH v5 5/6] kunit: add ability to run tests after boot using debugfs

2023-12-13 Thread Rae Moar
Add functionality to run built-in tests after boot by writing to a
debugfs file.

Add a new debugfs file labeled "run" for each test suite to use for
this purpose.

As an example, write to the file using the following:

echo "any string" > /sys/kernel/debugfs/kunit//run

This will trigger the test suite to run and will print results to the
kernel log.

To guard against running tests concurrently with this feature, add a
mutex lock around running kunit. This supports the current practice of
not allowing tests to be run concurrently on the same kernel.

This new functionality could be used to design a parameter
injection feature in the future.

Reviewed-by: David Gow 
Signed-off-by: Rae Moar 
---
 lib/kunit/debugfs.c | 68 +
 lib/kunit/test.c| 10 +++
 2 files changed, 78 insertions(+)

diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
index 382706dfb47d..d548750a325a 100644
--- a/lib/kunit/debugfs.c
+++ b/lib/kunit/debugfs.c
@@ -8,12 +8,14 @@
 #include 
 
 #include 
+#include 
 
 #include "string-stream.h"
 #include "debugfs.h"
 
 #define KUNIT_DEBUGFS_ROOT "kunit"
 #define KUNIT_DEBUGFS_RESULTS  "results"
+#define KUNIT_DEBUGFS_RUN  "run"
 
 /*
  * Create a debugfs representation of test suites:
@@ -21,6 +23,8 @@
  * PathSemantics
  * /sys/kernel/debug/kunit//results Show results of last run for
  * testsuite
+ * /sys/kernel/debug/kunit//run Write to this file to trigger
+ * testsuite to run
  *
  */
 
@@ -101,6 +105,51 @@ static int debugfs_results_open(struct inode *inode, 
struct file *file)
return single_open(file, debugfs_print_results, suite);
 }
 
+/*
+ * Print a usage message to the debugfs "run" file
+ * (/sys/kernel/debug/kunit//run) if opened.
+ */
+static int debugfs_print_run(struct seq_file *seq, void *v)
+{
+   struct kunit_suite *suite = (struct kunit_suite *)seq->private;
+
+   seq_puts(seq, "Write to this file to trigger the test suite to run.\n");
+   seq_printf(seq, "usage: echo \"any string\" > 
/sys/kernel/debugfs/kunit/%s/run\n",
+   suite->name);
+   return 0;
+}
+
+/*
+ * The debugfs "run" file (/sys/kernel/debug/kunit//run)
+ * contains no information. Write to the file to trigger the test suite
+ * to run.
+ */
+static int debugfs_run_open(struct inode *inode, struct file *file)
+{
+   struct kunit_suite *suite;
+
+   suite = (struct kunit_suite *)inode->i_private;
+
+   return single_open(file, debugfs_print_run, suite);
+}
+
+/*
+ * Trigger a test suite to run by writing to the suite's "run" debugfs
+ * file found at: /sys/kernel/debug/kunit//run
+ *
+ * Note: what is written to this file will not be saved.
+ */
+static ssize_t debugfs_run(struct file *file,
+   const char __user *buf, size_t count, loff_t *ppos)
+{
+   struct inode *f_inode = file->f_inode;
+   struct kunit_suite *suite = (struct kunit_suite *) f_inode->i_private;
+
+   __kunit_test_suites_init(&suite, 1);
+
+   return count;
+}
+
 static const struct file_operations debugfs_results_fops = {
.open = debugfs_results_open,
.read = seq_read,
@@ -108,11 +157,23 @@ static const struct file_operations debugfs_results_fops 
= {
.release = debugfs_release,
 };
 
+static const struct file_operations debugfs_run_fops = {
+   .open = debugfs_run_open,
+   .read = seq_read,
+   .write = debugfs_run,
+   .llseek = seq_lseek,
+   .release = debugfs_release,
+};
+
 void kunit_debugfs_create_suite(struct kunit_suite *suite)
 {
struct kunit_case *test_case;
struct string_stream *stream;
 
+   /* If suite log already allocated, do not create new debugfs files. */
+   if (suite->log)
+   return;
+
/*
 * Allocate logs before creating debugfs representation.
 * The suite->log and test_case->log pointer are expected to be NULL
@@ -140,6 +201,13 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite)
debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444,
suite->debugfs,
suite, &debugfs_results_fops);
+
+   /* Do not create file to re-run test if test runs on init */
+   if (!suite->is_init) {
+   debugfs_create_file(KUNIT_DEBUGFS_RUN, S_IFREG | 0644,
+   suite->debugfs,
+   suite, &debugfs_run_fops);
+   }
return;
 
 err:
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 6c082911a85f..a52fcb9a4457 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -13,6 +13,7 @@
 #i

[PATCH v5 6/6] Documentation: Add debugfs docs with run after boot

2023-12-13 Thread Rae Moar
Expand the documentation on the KUnit debugfs filesystem on the
run_manual.rst page.

Add section describing how to access results using debugfs.

Add section describing how to run tests after boot using debugfs.

Reviewed-by: David Gow 
Signed-off-by: Rae Moar 
---
 Documentation/dev-tools/kunit/run_manual.rst | 51 ++--
 1 file changed, 47 insertions(+), 4 deletions(-)

diff --git a/Documentation/dev-tools/kunit/run_manual.rst 
b/Documentation/dev-tools/kunit/run_manual.rst
index e7b46421f247..699d92885075 100644
--- a/Documentation/dev-tools/kunit/run_manual.rst
+++ b/Documentation/dev-tools/kunit/run_manual.rst
@@ -49,9 +49,52 @@ loaded.
 
 The results will appear in TAP format in ``dmesg``.
 
+debugfs
+===
+
+KUnit can be accessed from userspace via the debugfs filesystem (See more
+information about debugfs at Documentation/filesystems/debugfs.rst).
+
+If ``CONFIG_KUNIT_DEBUGFS`` is enabled, the KUnit debugfs filesystem is
+mounted at /sys/kernel/debug/kunit. You can use this filesystem to perform
+the following actions.
+
+Retrieve Test Results
+=
+
+You can use debugfs to retrieve KUnit test results. The test results are
+accessible from the debugfs filesystem in the following read-only file:
+
+.. code-block :: bash
+
+   /sys/kernel/debug/kunit//results
+
+The test results are printed in a KTAP document. Note this document is separate
+to the kernel log and thus, may have different test suite numbering.
+
+Run Tests After Kernel Has Booted
+=
+
+You can use the debugfs filesystem to trigger built-in tests to run after
+boot. To run the test suite, you can use the following command to write to
+the ``/sys/kernel/debug/kunit//run`` file:
+
+.. code-block :: bash
+
+   echo "any string" > /sys/kernel/debugfs/kunit//run
+
+As a result, the test suite runs and the results are printed to the kernel
+log.
+
+However, this feature is not available with KUnit suites that use init data,
+because init data may have been discarded after the kernel boots. KUnit
+suites that use init data should be defined using the
+kunit_test_init_section_suites() macro.
+
+Also, you cannot use this feature to run tests concurrently. Instead a test
+will wait to run until other tests have completed or failed.
+
 .. note ::
 
-   If ``CONFIG_KUNIT_DEBUGFS`` is enabled, KUnit test results will
-   be accessible from the ``debugfs`` filesystem (if mounted).
-   They will be in ``/sys/kernel/debug/kunit//results``, in
-   TAP format.
+   For test authors, to use this feature, tests will need to correctly 
initialise
+   and/or clean up any data, so the test runs correctly a second time.
-- 
2.43.0.472.g3155946c3a-goog




Re: [PATCH v4 5/5] drm/tests: Switch to kunit devices

2023-12-15 Thread Rae Moar
On Fri, Dec 15, 2023 at 2:39 AM  wrote:
>
> From: Maxime Ripard 
>
> Kunit recently gained helpers to create test managed devices. This means
> that we no longer have to roll our own helpers in KMS and we can reuse
> them.

Hello!

This looks good to me. Thanks!

Reviewed-by: Rae Moar 

-Rae

>
> Signed-off-by: Maxime Ripard 
> Tested-by: David Gow 
> Signed-off-by: David Gow 
> ---
>  drivers/gpu/drm/tests/drm_kunit_helpers.c | 66 
> ++-
>  1 file changed, 3 insertions(+), 63 deletions(-)
>
> diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c 
> b/drivers/gpu/drm/tests/drm_kunit_helpers.c
> index c251e6b34de0..ca4f8e4c5d5d 100644
> --- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
> +++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
> @@ -5,6 +5,7 @@
>  #include 
>  #include 
>
> +#include 
>  #include 
>
>  #include 
> @@ -15,28 +16,6 @@
>  static const struct drm_mode_config_funcs drm_mode_config_funcs = {
>  };
>
> -static int fake_probe(struct platform_device *pdev)
> -{
> -   return 0;
> -}
> -
> -static struct platform_driver fake_platform_driver = {
> -   .probe  = fake_probe,
> -   .driver = {
> -   .name   = KUNIT_DEVICE_NAME,
> -   },
> -};
> -
> -KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_platform_driver_unregister,
> -   platform_driver_unregister,
> -   struct platform_driver *);
> -KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_platform_device_put,
> -   platform_device_put,
> -   struct platform_device *);
> -KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_platform_device_del,
> -   platform_device_del,
> -   struct platform_device *);
> -
>  /**
>   * drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
>   * @test: The test context object
> @@ -54,34 +33,7 @@ 
> KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_platform_device_del,
>   */
>  struct device *drm_kunit_helper_alloc_device(struct kunit *test)
>  {
> -   struct platform_device *pdev;
> -   int ret;
> -
> -   ret = platform_driver_register(&fake_platform_driver);
> -   KUNIT_ASSERT_EQ(test, ret, 0);
> -
> -   ret = kunit_add_action_or_reset(test,
> -   
> kunit_action_platform_driver_unregister,
> -   &fake_platform_driver);
> -   KUNIT_ASSERT_EQ(test, ret, 0);
> -
> -   pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
> -   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
> -
> -   ret = kunit_add_action_or_reset(test,
> -   kunit_action_platform_device_put,
> -   pdev);
> -   KUNIT_ASSERT_EQ(test, ret, 0);
> -
> -   ret = platform_device_add(pdev);
> -   KUNIT_ASSERT_EQ(test, ret, 0);
> -
> -   ret = kunit_add_action_or_reset(test,
> -   kunit_action_platform_device_del,
> -   pdev);
> -   KUNIT_ASSERT_EQ(test, ret, 0);
> -
> -   return &pdev->dev;
> +   return kunit_device_register(test, KUNIT_DEVICE_NAME);
>  }
>  EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
>
> @@ -94,19 +46,7 @@ EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
>   */
>  void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
>  {
> -   struct platform_device *pdev = to_platform_device(dev);
> -
> -   kunit_release_action(test,
> -kunit_action_platform_device_del,
> -pdev);
> -
> -   kunit_release_action(test,
> -kunit_action_platform_device_put,
> -pdev);
> -
> -   kunit_release_action(test,
> -kunit_action_platform_driver_unregister,
> -&fake_platform_driver);
> +   kunit_device_unregister(test, dev);
>  }
>  EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
>
>
> --
> 2.43.0.472.g3155946c3a-goog
>



Re: [PATCH] kunit: Fix NULL-dereference in kunit_init_suite() if suite->log is NULL

2023-12-19 Thread Rae Moar
On Mon, Dec 18, 2023 at 10:17 AM Richard Fitzgerald
 wrote:
>
> suite->log must be checked for NULL before passing it to
> string_stream_clear(). This was done in kunit_init_test() but was missing
> from kunit_init_suite().
>
> Signed-off-by: Richard Fitzgerald 
> Fixes: 6d696c4695c5 ("kunit: add ability to run tests after boot using 
> debugfs")

Hello!

This looks good! Thanks! Sorry I did not catch this earlier.

Reviewed-by: Rae Moar 

-Rae

> ---
>  lib/kunit/test.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index e803d998e855..ea7f0913e55a 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -658,7 +658,9 @@ static void kunit_init_suite(struct kunit_suite *suite)
> kunit_debugfs_create_suite(suite);
> suite->status_comment[0] = '\0';
> suite->suite_init_err = 0;
> -   string_stream_clear(suite->log);
> +
> +   if (suite->log)
> +   string_stream_clear(suite->log);
>  }
>
>  bool kunit_enabled(void)
> --
> 2.30.2
>



Re: [PATCH 1/2] kunit: Allow passing function pointer to kunit_activate_static_stub()

2023-12-19 Thread Rae Moar
On Mon, Dec 18, 2023 at 11:10 AM Richard Fitzgerald
 wrote:
>
> Swap the arguments to typecheck_fn() in kunit_activate_static_stub()
> so that real_fn_addr can be either the function itself or a pointer
> to that function.
>
> This is useful to simplify redirecting static functions in a module.
> Having to pass the actual function meant that it must be exported
> from the module. Either making the 'static' and EXPORT_SYMBOL*()
> conditional (which makes the code messy), or change it to always
> exported (which increases the export namespace and prevents the
> compiler inlining a trivial stub function in non-test builds).
>
> With the original definition of kunit_activate_static_stub() the
> address of real_fn_addr was passed to typecheck_fn() as the type to
> be passed. This meant that if real_fn_addr was a pointer-to-function
> it would resolve to a ** instead of a *, giving an error like this:
>
>error: initialization of ‘int (**)(int)’ from incompatible pointer
>type ‘int (*)(int)’ [-Werror=incompatible-pointer-types]
>kunit_activate_static_stub(test, add_one_fn_ptr, subtract_one);
>   | ^~~~
>./include/linux/typecheck.h:21:25: note: in definition of macro
>‘typecheck_fn’
>21 | ({ typeof(type) __tmp = function; \
>
> Swapping the arguments to typecheck_fn makes it take the type of a
> pointer to the replacement function. Either a function or a pointer
> to function can be assigned to that. For example:
>
> static int some_function(int x)
> {
> /* whatever */
> }
>
> int (* some_function_ptr)(int) = some_function;
>
> static int replacement(int x)
> {
> /* whatever */
> }
>
> Then:
>   kunit_activate_static_stub(test, some_function, replacement);
> yields:
>   typecheck_fn(typeof(&replacement), some_function);
>
> and:
>   kunit_activate_static_stub(test, some_function_ptr, replacement);
> yields:
>   typecheck_fn(typeof(&replacement), some_function_ptr);
>
> The two typecheck_fn() then resolve to:
>
>   int (*__tmp)(int) = some_function;
> and
>   int (*__tmp)(int) = some_function_ptr;
>
> Both of these are valid. In the first case the compiler inserts
> an implicit '&' to take the address of the supplied function, and
> in the second case the RHS is already a pointer to the same type.
>
> Signed-off-by: Richard Fitzgerald 

Hello!

This seems fine to me. I have tested it and the reasoning behind this
seems sensible. However, let's see what David thinks when he returns
to office as he is the expert on static stubbing.

Reviewed-by: Rae Moar 

-Rae

> ---
>  include/kunit/static_stub.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/kunit/static_stub.h b/include/kunit/static_stub.h
> index 85315c80b303..bf940322dfc0 100644
> --- a/include/kunit/static_stub.h
> +++ b/include/kunit/static_stub.h
> @@ -93,7 +93,7 @@ void __kunit_activate_static_stub(struct kunit *test,
>   * The redirection can be disabled again with kunit_deactivate_static_stub().
>   */
>  #define kunit_activate_static_stub(test, real_fn_addr, replacement_addr) do 
> {  \
> -   typecheck_fn(typeof(&real_fn_addr), replacement_addr);
>   \
> +   typecheck_fn(typeof(&replacement_addr), real_fn_addr);
>   \
> __kunit_activate_static_stub(test, real_fn_addr, replacement_addr);   
>   \
>  } while (0)
>
> --
> 2.30.2
>



Re: [PATCH 2/2] kunit: Add example of kunit_activate_static_stub() with pointer-to-function

2023-12-19 Thread Rae Moar
On Mon, Dec 18, 2023 at 11:10 AM Richard Fitzgerald
 wrote:
>
> Adds a variant of example_static_stub_test() that shows use of a
> pointer-to-function with kunit_activate_static_stub().
>
> A const pointer to the add_one() function is declared. This
> pointer-to-function is passed to kunit_activate_static_stub() and
> kunit_deactivate_static_stub() instead of passing add_one directly.
>
> Signed-off-by: Richard Fitzgerald 

Hello!

This test looks good to me. However, I had issues applying this patch
so I think it needs rebasing due to the newest additions to
kselftest/kunit. But otherwise this patch looks good other than my
very small comment below.

Thanks!
-Rae

> ---
>  lib/kunit/kunit-example-test.c | 27 +++
>  1 file changed, 27 insertions(+)
>
> diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
> index d2f7a3c62c18..9e57f341dc37 100644
> --- a/lib/kunit/kunit-example-test.c
> +++ b/lib/kunit/kunit-example-test.c
> @@ -168,6 +168,8 @@ static int subtract_one(int i)
> return i - 1;
>  }
>
> +static int (* const add_one_fn_ptr)(int i) = add_one;

This is a bit of a nit but could you add a brief comment above this
pointer definition? This would then match the commenting on the other
functions in kunit-example-test and provide more context for those
looking at the example tests.

> +
>  /*
>   * This test shows the use of static stubs.
>   */
> @@ -187,6 +189,30 @@ static void example_static_stub_test(struct kunit *test)
> KUNIT_EXPECT_EQ(test, add_one(1), 2);
>  }
>
> +/*
> + * This test shows the use of static stubs when the function being
> + * replaced is provided as a pointer-to-function instead of the
> + * actual function. This is useful for providing access to static
> + * functions in a module by exporting a pointer to that function
> + * instead of having to change the static function to a non-static
> + * exported function.
> + */
> +static void example_static_stub_using_fn_ptr_test(struct kunit *test)
> +{
> +   /* By default, function is not stubbed. */
> +   KUNIT_EXPECT_EQ(test, add_one(1), 2);
> +
> +   /* Replace add_one() with subtract_one(). */
> +   kunit_activate_static_stub(test, add_one_fn_ptr, subtract_one);
> +
> +   /* add_one() is now replaced. */
> +   KUNIT_EXPECT_EQ(test, add_one(1), 0);
> +
> +   /* Return add_one() to normal. */
> +   kunit_deactivate_static_stub(test, add_one_fn_ptr);
> +   KUNIT_EXPECT_EQ(test, add_one(1), 2);
> +}
> +
>  static const struct example_param {
> int value;
>  } example_params_array[] = {
> @@ -245,6 +271,7 @@ static struct kunit_case example_test_cases[] = {
> KUNIT_CASE(example_mark_skipped_test),
> KUNIT_CASE(example_all_expect_macros_test),
> KUNIT_CASE(example_static_stub_test),
> +   KUNIT_CASE(example_static_stub_using_fn_ptr_test),
> KUNIT_CASE_PARAM(example_params_test, example_gen_params),
> KUNIT_CASE_SLOW(example_slow_test),
> {}
> --
> 2.30.2
>



Re: [PATCH v3] kunit: run test suites only after module initialization completes

2024-01-05 Thread Rae Moar
On Wed, Dec 6, 2023 at 10:07 AM Marco Pagani  wrote:
>
> Commit 2810c1e99867 ("kunit: Fix wild-memory-access bug in
> kunit_free_suite_set()") fixed a wild-memory-access bug that could have
> happened during the loading phase of test suites built and executed as
> loadable modules. However, it also introduced a problematic side effect
> that causes test suites modules to crash when they attempt to register
> fake devices.
>
> When a module is loaded, it traverses the MODULE_STATE_UNFORMED and
> MODULE_STATE_COMING states before reaching the normal operating state
> MODULE_STATE_LIVE. Finally, when the module is removed, it moves to
> MODULE_STATE_GOING before being released. However, if the loading
> function load_module() fails between complete_formation() and
> do_init_module(), the module goes directly from MODULE_STATE_COMING to
> MODULE_STATE_GOING without passing through MODULE_STATE_LIVE.
>
> This behavior was causing kunit_module_exit() to be called without
> having first executed kunit_module_init(). Since kunit_module_exit() is
> responsible for freeing the memory allocated by kunit_module_init()
> through kunit_filter_suites(), this behavior was resulting in a
> wild-memory-access bug.
>
> Commit 2810c1e99867 ("kunit: Fix wild-memory-access bug in
> kunit_free_suite_set()") fixed this issue by running the tests when the
> module is still in MODULE_STATE_COMING. However, modules in that state
> are not fully initialized, lacking sysfs kobjects. Therefore, if a test
> module attempts to register a fake device, it will inevitably crash.
>
> This patch proposes a different approach to fix the original
> wild-memory-access bug while restoring the normal module execution flow
> by making kunit_module_exit() able to detect if kunit_module_init() has
> previously initialized the tests suite set. In this way, test modules
> can once again register fake devices without crashing.
>
> This behavior is achieved by checking whether mod->kunit_suites is a
> virtual or direct mapping address. If it is a virtual address, then
> kunit_module_init() has allocated the suite_set in kunit_filter_suites()
> using kmalloc_array(). On the contrary, if mod->kunit_suites is still
> pointing to the original address that was set when looking up the
> .kunit_test_suites section of the module, then the loading phase has
> failed and there's no memory to be freed.
>

Hello,

I have tested this change and it looks good to me!

Although, it no longer applies cleanly on the kselftest/kunit branch
so it will need to be rebased.

So besides the need for a rebase,
Tested-by: Rae Moar 

Thanks for the fix!
Rae

> v3:
> - add a comment to clarify why the start address is checked
> v2:
> - add include 
>
> Fixes: 2810c1e99867 ("kunit: Fix wild-memory-access bug in 
> kunit_free_suite_set()")
> Tested-by: Richard Fitzgerald 
> Reviewed-by: Javier Martinez Canillas 
> Signed-off-by: Marco Pagani 
> ---
>  lib/kunit/test.c | 14 +++---
>  1 file changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index 7aceb07a1af9..3263e0d5e0f6 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -16,6 +16,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>
>  #include "debugfs.h"
>  #include "hooks-impl.h"
> @@ -775,12 +776,19 @@ static void kunit_module_exit(struct module *mod)
> };
> const char *action = kunit_action();
>
> +   /*
> +* Check if the start address is a valid virtual address to detect
> +* if the module load sequence has failed and the suite set has not
> +* been initialized and filtered.
> +*/
> +   if (!suite_set.start || !virt_addr_valid(suite_set.start))
> +   return;
> +
> if (!action)
> __kunit_test_suites_exit(mod->kunit_suites,
>  mod->num_kunit_suites);
>
> -   if (suite_set.start)
> -   kunit_free_suite_set(suite_set);
> +   kunit_free_suite_set(suite_set);
>  }
>
>  static int kunit_module_notify(struct notifier_block *nb, unsigned long val,
> @@ -790,12 +798,12 @@ static int kunit_module_notify(struct notifier_block 
> *nb, unsigned long val,
>
> switch (val) {
> case MODULE_STATE_LIVE:
> +   kunit_module_init(mod);
> break;
> case MODULE_STATE_GOING:
> kunit_module_exit(mod);
> break;
> case MODULE_STATE_COMING:
> -   kunit_module_init(mod);
> break;
> case MODULE_STATE_UNFORMED:
> break;
>
> base-commit: 33cc938e65a98f1d29d0a18403dbbee050dcad9a
> --
> 2.43.0
>



Re: [PATCH] kunit: Fix a NULL vs IS_ERR() bug

2024-01-10 Thread Rae Moar
On Wed, Jan 10, 2024 at 1:55 PM Dan Carpenter  wrote:
>
> The kunit_device_register() function doesn't return NULL, it returns
> error pointers.  Change the KUNIT_ASSERT_NOT_NULL() to check for
> ERR_OR_NULL().
>
> Fixes: d03c720e03bd ("kunit: Add APIs for managing devices")
> Signed-off-by: Dan Carpenter 

This change looks good to me! Thanks!
-Rae

Reviewed-by: Rae Moar 

> ---
> It's a pity that there isn't a KUNIT_ASSERT_NOT_ERR_PTR() macro...
>
>  lib/kunit/kunit-test.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
> index c4259d910356..f7980ef236a3 100644
> --- a/lib/kunit/kunit-test.c
> +++ b/lib/kunit/kunit-test.c
> @@ -720,7 +720,7 @@ static void kunit_device_cleanup_test(struct kunit *test)
> long action_was_run = 0;
>
> test_device = kunit_device_register(test, "my_device");
> -   KUNIT_ASSERT_NOT_NULL(test, test_device);
> +   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_device);
>
> /* Add an action to verify cleanup. */
> devm_add_action(test_device, test_dev_action, &action_was_run);
> --
> 2.43.0
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/39b4278f-35d2-4071-a3aa-ec49705272af%40moroto.mountain.



Re: [PATCH] kunit: device: Fix a NULL vs IS_ERR() check in init()

2024-01-10 Thread Rae Moar
On Wed, Jan 10, 2024 at 1:55 PM Dan Carpenter  wrote:
>
> The root_device_register() function does not return NULL, it returns
> error pointers.  Fix the check to match.
>
> Fixes: d03c720e03bd ("kunit: Add APIs for managing devices")
> Signed-off-by: Dan Carpenter 

This change looks good to me! We could check for IS_ERR_OR_NULL
instead but this change is more correct and is also how others check
root_device_register().

Reviewed-by: Rae Moar 

Thanks!
Rae


> ---
>  lib/kunit/device.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/lib/kunit/device.c b/lib/kunit/device.c
> index f5371287b375..074c6dd2e36a 100644
> --- a/lib/kunit/device.c
> +++ b/lib/kunit/device.c
> @@ -45,8 +45,8 @@ int kunit_bus_init(void)
> int error;
>
> kunit_bus_device = root_device_register("kunit");
> -   if (!kunit_bus_device)
> -   return -ENOMEM;
> +   if (IS_ERR(kunit_bus_device))
> +   return PTR_ERR(kunit_bus_device);
>
> error = bus_register(&kunit_bus_type);
> if (error)
> --
> 2.43.0
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/dd938a86-38d9-4d62-abd0-1df80395fbbd%40moroto.mountain.



Re: [PATCH] MAINTAINERS: kunit: Add Rae Moar as a reviewer

2024-01-16 Thread Rae Moar
On Thu, Jan 11, 2024 at 6:50 PM David Gow  wrote:
>
> Rae has been shouldering a lot of the KUnit review burden for the last
> year, and will continue to do so in the future. Thanks!

Thanks David! Happy to review this one!

Reviewed-by: Rae Moar 

>
> Signed-off-by: David Gow 
> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f8efcb72ad4b..2316d89806dd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11599,6 +11599,7 @@ F:  fs/smb/server/
>  KERNEL UNIT TESTING FRAMEWORK (KUnit)
>  M: Brendan Higgins 
>  M: David Gow 
> +R: Rae Moar 
>  L: linux-kselftest@vger.kernel.org
>  L: kunit-...@googlegroups.com
>  S: Maintained
> --
> 2.43.0.275.g3460e3d667-goog
>



Re: [PATCH] kunit: Mark filter_glob param as rw

2024-01-18 Thread Rae Moar
On Thu, Jan 11, 2024 at 7:13 PM Lucas De Marchi
 wrote:
>
> By allowing the filter_glob parameter to be written to, it's possible to
> tweak the testsuites that will be executed on new module loads. This
> makes it easier to run specific tests without having to reload kunit and
> provides a way to filter tests on real HW even if kunit is builtin.
> Example for xe driver:
>
> 1) Run just 1 test
> # echo -n xe_bo > /sys/module/kunit/parameters/filter_glob
> # modprobe -r xe_live_test
> # modprobe xe_live_test
> # ls /sys/kernel/debug/kunit/
> xe_bo
>
> 2) Run all tests
> # echo \* > /sys/module/kunit/parameters/filter_glob
> # modprobe -r xe_live_test
> # modprobe xe_live_test
> # ls /sys/kernel/debug/kunit/
> xe_bo  xe_dma_buf  xe_migrate  xe_mocs
>
> References: 
> https://lore.kernel.org/intel-xe/dzacvbdditbneiu3e3fmstjmttcbne44yspumpkd6sjn56jqpk@vxu7sksbqrp6/
> Signed-off-by: Lucas De Marchi 

Hello!

I have tested this and this looks good to me. I agree this is very
helpful and I wonder if we should do the same with the other module
parameters (filter, filter_action).

It did worry me to make filter_glob writable due to the recent patch
that requires the output of filtering to be a valid virtual address
but I think there is a sufficient amount of checking of filter_glob.

Thanks!
-Rae

Reviewed-by: Rae Moar 




> ---
>  lib/kunit/executor.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
> index 1236b3cd2fbb..30ed9d321c19 100644
> --- a/lib/kunit/executor.c
> +++ b/lib/kunit/executor.c
> @@ -31,7 +31,7 @@ static char *filter_glob_param;
>  static char *filter_param;
>  static char *filter_action_param;
>
> -module_param_named(filter_glob, filter_glob_param, charp, 0400);
> +module_param_named(filter_glob, filter_glob_param, charp, 0600);
>  MODULE_PARM_DESC(filter_glob,
> "Filter which KUnit test suites/tests run at boot-time, e.g. 
> list* or list*.*del_test");
>  module_param_named(filter, filter_param, charp, 0400);
> --
> 2.40.1
>
> --
> You received this message because you are subscribed to the Google Groups 
> "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to kunit-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/kunit-dev/20240112001240.1710962-1-lucas.demarchi%40intel.com.



[KTAP V2 PATCH v2] ktap_v2: add test metadata

2024-01-26 Thread Rae Moar
Add specification for test metadata to the KTAP v2 spec.

KTAP v1 only specifies the output format of very basic test information:
test result and test name. Any additional test information either gets
added to general diagnostic data or is not included in the output at all.

The purpose of KTAP metadata is to create a framework to include and
easily identify additional important test information in KTAP.

KTAP metadata could include any test information that is pertinent for
user interaction before or after the running of the test. For example,
the test file path or the test speed.

Since this includes a large variety of information, this specification
will recognize notable types of KTAP metadata to ensure consistent format
across test frameworks. See the full list of types in the specification.

Example of KTAP Metadata:

 KTAP version 2
 # ktap_test: main
 # ktap_arch: uml
 1..1
 KTAP version 2
 # ktap_test: suite_1
 # ktap_subsystem: example
 # ktap_test_file: lib/test.c
 1..2
 ok 1 test_1
 # ktap_test: test_2
 # ktap_speed: very_slow
 # custom_is_flaky: true
 ok 2 test_2
 ok 1 test_suite

The changes to the KTAP specification outline the format, location, and
different types of metadata.

Here is a link to a version of the KUnit parser that is able to parse test
metadata lines for KTAP version 2. Note this includes test metadata
lines for the main level of KTAP.

Link: https://kunit-review.googlesource.com/c/linux/+/5889

Signed-off-by: Rae Moar 
---
 Documentation/dev-tools/ktap.rst | 163 ++-
 1 file changed, 159 insertions(+), 4 deletions(-)

diff --git a/Documentation/dev-tools/ktap.rst b/Documentation/dev-tools/ktap.rst
index ff77f4aaa6ef..4480eaf5bbc3 100644
--- a/Documentation/dev-tools/ktap.rst
+++ b/Documentation/dev-tools/ktap.rst
@@ -17,19 +17,20 @@ KTAP test results describe a series of tests (which may be 
nested: i.e., test
 can have subtests), each of which can contain both diagnostic data -- e.g., log
 lines -- and a final result. The test structure and results are
 machine-readable, whereas the diagnostic data is unstructured and is there to
-aid human debugging.
+aid human debugging. One exception to this is test metadata lines - a type
+of diagnostic lines. Test metadata is used to identify important supplemental
+test information and can be machine-readable.
 
 KTAP output is built from four different types of lines:
 - Version lines
 - Plan lines
 - Test case result lines
-- Diagnostic lines
+- Diagnostic lines (including test metadata)
 
 In general, valid KTAP output should also form valid TAP output, but some
 information, in particular nested test results, may be lost. Also note that
 there is a stagnant draft specification for TAP14, KTAP diverges from this in
-a couple of places (notably the "Subtest" header), which are described where
-relevant later in this document.
+a couple of places, which are described where relevant later in this document.
 
 Version lines
 -
@@ -166,6 +167,154 @@ even if they do not start with a "#": this is to capture 
any other useful
 kernel output which may help debug the test. It is nevertheless recommended
 that tests always prefix any diagnostic output they have with a "#" character.
 
+KTAP metadata lines
+---
+
+KTAP metadata lines are a subset of diagnostic lines that are used to include
+and easily identify important supplemental test information in KTAP.
+
+.. code-block:: none
+
+   # _: 
+
+The  indicates where to find the specification for the type of
+metadata. The metadata types listed below use the prefix "ktap" (See Types of
+KTAP Metadata).
+
+Types that are instead specified by an individual test framework use the
+framework name as the prefix. For example, a metadata type documented by the
+kselftest specification would use the prefix "kselftest". Any metadata type
+that is not listed in a specification must use the prefix "custom". Note the
+prefix must not include spaces or the characters ":" or "_".
+
+The format of  and  varies based on the type. See the
+individual specification. For "custom" types the  can be any
+string excluding ":", spaces, or newline characters and the  can be any
+string.
+
+**Location:**
+
+The first KTAP metadata entry for a test must be "# ktap_test: ",
+which acts as a header to associate metadata with the correct test.
+
+For test cases, the location of the metadata is between the prior test result
+line and the current test result line. For test suites, the location of the
+metadata is between the suite's version line and test plan line. See the
+example below.
+
+KTAP metadata for a test does not need to be contiguous. For example, a kernel
+warning or other diagnostic output could interrupt metadata lines. However, it
+is recommended to keep a test's metadata lines togeth

Re: [PATCH] kunit: device: Unregister the kunit_bus on shutdown

2024-02-02 Thread Rae Moar
On Thu, Feb 1, 2024 at 1:06 AM David Gow  wrote:
>
> If KUnit is built as a module, and it's unloaded, the kunit_bus is not
> unregistered. This causes an error if it's then re-loaded later, as we
> try to re-register the bus.
>
> Unregister the bus and root_device on shutdown, if it looks valid.
>
> In addition, be more specific about the value of kunit_bus_device. It
> is:
> - a valid struct device* if the kunit_bus initialised correctly.
> - an ERR_PTR if it failed to initialise.
> - NULL before initialisation and after shutdown.
>
> Fixes: d03c720e03bd ("kunit: Add APIs for managing devices")
> Signed-off-by: David Gow 

Hello,

I have tested this with modules and it looks good to me!

Thanks!
-Rae

Reviewed-by: Rae Moar 

> ---
>
> This will hopefully resolve some of the issues linked to from:
> https://lore.kernel.org/intel-gfx/dm4pr11mb614179cb9c387842d8e8bb40b9...@dm4pr11mb6141.namprd11.prod.outlook.com/
>
> ---
>  lib/kunit/device-impl.h |  2 ++
>  lib/kunit/device.c  | 14 ++
>  lib/kunit/test.c|  3 +++
>  3 files changed, 19 insertions(+)
>
> diff --git a/lib/kunit/device-impl.h b/lib/kunit/device-impl.h
> index 54bd55836405..5fcd48ff0f36 100644
> --- a/lib/kunit/device-impl.h
> +++ b/lib/kunit/device-impl.h
> @@ -13,5 +13,7 @@
>
>  // For internal use only -- registers the kunit_bus.
>  int kunit_bus_init(void);
> +// For internal use only -- unregisters the kunit_bus.
> +void kunit_bus_shutdown(void);
>
>  #endif //_KUNIT_DEVICE_IMPL_H
> diff --git a/lib/kunit/device.c b/lib/kunit/device.c
> index 074c6dd2e36a..644a38a1f5b1 100644
> --- a/lib/kunit/device.c
> +++ b/lib/kunit/device.c
> @@ -54,6 +54,20 @@ int kunit_bus_init(void)
> return error;
>  }
>
> +/* Unregister the 'kunit_bus' in case the KUnit module is unloaded. */
> +void kunit_bus_shutdown(void)
> +{
> +   /* Make sure the bus exists before we unregister it. */
> +   if (IS_ERR_OR_NULL(kunit_bus_device))
> +   return;
> +
> +   bus_unregister(&kunit_bus_type);
> +
> +   root_device_unregister(kunit_bus_device);
> +
> +   kunit_bus_device = NULL;
> +}
> +
>  /* Release a 'fake' KUnit device. */
>  static void kunit_device_release(struct device *d)
>  {
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index 31a5a992e646..1d1475578515 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -928,6 +928,9 @@ static void __exit kunit_exit(void)
>  #ifdef CONFIG_MODULES
> unregister_module_notifier(&kunit_mod_nb);
>  #endif
> +
> +   kunit_bus_shutdown();
> +
> kunit_debugfs_cleanup();
>  }
>  module_exit(kunit_exit);
> --
> 2.43.0.429.g432eaa2c6b-goog
>



Re: [KTAP V2 PATCH v2] ktap_v2: add test metadata

2024-02-05 Thread Rae Moar
On Wed, Jan 31, 2024 at 5:22 PM Bird, Tim  wrote:
>
>
>
> > -Original Message-----
> > From: Rae Moar 
> > Add specification for test metadata to the KTAP v2 spec.
> >
> > KTAP v1 only specifies the output format of very basic test information:
> > test result and test name. Any additional test information either gets
> > added to general diagnostic data or is not included in the output at all.
> >
> > The purpose of KTAP metadata is to create a framework to include and
> > easily identify additional important test information in KTAP.
> >
> > KTAP metadata could include any test information that is pertinent for
> > user interaction before or after the running of the test. For example,
> > the test file path or the test speed.
> >
> > Since this includes a large variety of information, this specification
> > will recognize notable types of KTAP metadata to ensure consistent format
> > across test frameworks. See the full list of types in the specification.
> >
> > Example of KTAP Metadata:
> >
> >  KTAP version 2
> >  # ktap_test: main
> >  # ktap_arch: uml
> >  1..1
> >  KTAP version 2
> >  # ktap_test: suite_1
> >  # ktap_subsystem: example
> >  # ktap_test_file: lib/test.c
> >  1..2
> >  ok 1 test_1
> >  # ktap_test: test_2
> >  # ktap_speed: very_slow
> >  # custom_is_flaky: true
> >  ok 2 test_2
> >  ok 1 test_suite
> >
> > The changes to the KTAP specification outline the format, location, and
> > different types of metadata.
> >
> > Here is a link to a version of the KUnit parser that is able to parse test
> > metadata lines for KTAP version 2. Note this includes test metadata
> > lines for the main level of KTAP.
> >
> > Link: https://kunit-review.googlesource.com/c/linux/+/5889
> >
> > Signed-off-by: Rae Moar 
> > ---
> >  Documentation/dev-tools/ktap.rst | 163 ++-
> >  1 file changed, 159 insertions(+), 4 deletions(-)
> >
> > diff --git a/Documentation/dev-tools/ktap.rst 
> > b/Documentation/dev-tools/ktap.rst
> > index ff77f4aaa6ef..4480eaf5bbc3 100644
> > --- a/Documentation/dev-tools/ktap.rst
> > +++ b/Documentation/dev-tools/ktap.rst
> > @@ -17,19 +17,20 @@ KTAP test results describe a series of tests (which may 
> > be nested: i.e., test
> >  can have subtests), each of which can contain both diagnostic data -- 
> > e.g., log
> >  lines -- and a final result. The test structure and results are
> >  machine-readable, whereas the diagnostic data is unstructured and is there 
> > to
> > -aid human debugging.
> > +aid human debugging. One exception to this is test metadata lines - a type
> > +of diagnostic lines. Test metadata is used to identify important 
> > supplemental
> > +test information and can be machine-readable.
> >
> >  KTAP output is built from four different types of lines:
> >  - Version lines
> >  - Plan lines
> >  - Test case result lines
> > -- Diagnostic lines
> > +- Diagnostic lines (including test metadata)
> >
> >  In general, valid KTAP output should also form valid TAP output, but some
> >  information, in particular nested test results, may be lost. Also note that
> >  there is a stagnant draft specification for TAP14, KTAP diverges from this 
> > in
> > -a couple of places (notably the "Subtest" header), which are described 
> > where
> > -relevant later in this document.
> > +a couple of places, which are described where relevant later in this 
> > document.
> >
> >  Version lines
> >  -
> > @@ -166,6 +167,154 @@ even if they do not start with a "#": this is to 
> > capture any other useful
> >  kernel output which may help debug the test. It is nevertheless recommended
> >  that tests always prefix any diagnostic output they have with a "#" 
> > character.
> >
> > +KTAP metadata lines
> > +---
> > +
> > +KTAP metadata lines are a subset of diagnostic lines that are used to 
> > include
> > +and easily identify important supplemental test information in KTAP.
> > +
> > +.. code-block:: none
> > +
> > + # _: 
> > +
> > +The  indicates where to find the specification for the type of
> > +metadata. The metadata types listed below use the prefix "ktap" (See Types 
> > of
> > +KTAP Metadata).
> > +
> > +Types that are instead specified by an individual test framework

Re: [KTAP V2 PATCH v2] ktap_v2: add test metadata

2024-02-05 Thread Rae Moar
On Sat, Feb 3, 2024 at 1:50 AM David Gow  wrote:
>
> On Sat, 27 Jan 2024 at 06:15, Rae Moar  wrote:
> >
> > Add specification for test metadata to the KTAP v2 spec.
> >
> > KTAP v1 only specifies the output format of very basic test information:
> > test result and test name. Any additional test information either gets
> > added to general diagnostic data or is not included in the output at all.
> >
> > The purpose of KTAP metadata is to create a framework to include and
> > easily identify additional important test information in KTAP.
> >
> > KTAP metadata could include any test information that is pertinent for
> > user interaction before or after the running of the test. For example,
> > the test file path or the test speed.
> >
> > Since this includes a large variety of information, this specification
> > will recognize notable types of KTAP metadata to ensure consistent format
> > across test frameworks. See the full list of types in the specification.
> >
> > Example of KTAP Metadata:
> >
> >  KTAP version 2
> >  # ktap_test: main
> >  # ktap_arch: uml
> >  1..1
> >  KTAP version 2
> >  # ktap_test: suite_1
> >  # ktap_subsystem: example
> >  # ktap_test_file: lib/test.c
> >  1..2
> >  ok 1 test_1
> >  # ktap_test: test_2
> >  # ktap_speed: very_slow
> >  # custom_is_flaky: true
> >  ok 2 test_2
> >  ok 1 test_suite
>
> This 'test_suite' name doesn't match the 'suite_1' name above.
>

Hello!

Thanks for your review of this documentation. And sorry about that
typo. I will change that in the next version.

> It also could be clearer that it's supposed to match 'suite_1', not
> 'main', due to the indentation difference. Maybe we should add an
> explicit note pointing that out?

This is a good point. I will add a note in the specification example.

>
> >
> > The changes to the KTAP specification outline the format, location, and
> > different types of metadata.
> >
> > Here is a link to a version of the KUnit parser that is able to parse test
> > metadata lines for KTAP version 2. Note this includes test metadata
> > lines for the main level of KTAP.
> >
> > Link: https://kunit-review.googlesource.com/c/linux/+/5889
>
> I tested this, and it works well. I think there's a couple of changes
> we'd want for a more useful set of KUnit parser changes (namely the
> option to support non ktap_ prefixes, as well as an actual way of
> using this data), but I'll leave those for a future review of that
> patch -- it's not relevant to this spec.

Thanks for testing this! My thought was to only support ktap_ prefixes
in the parser for now and we could add on others as needed. I will
make a separate patch series for this once KTAP Metadata goes through.

>
> >
> > Signed-off-by: Rae Moar 
> > ---
>
> I like this: it covers all of the requirements we have in KUnit, as
> well as a few things we'd like to add.
>
> Is there anything obviously missing for this to work with other
> usecases? Are there any other examples of metadata people want to
> capture?
>

Yes, I am also curious about what other use cases people are
interested in as well?

> For me, this is
> Reviewed-by: David Gow 
>
> >  Documentation/dev-tools/ktap.rst | 163 ++-
> >  1 file changed, 159 insertions(+), 4 deletions(-)
> >
> > diff --git a/Documentation/dev-tools/ktap.rst 
> > b/Documentation/dev-tools/ktap.rst
> > index ff77f4aaa6ef..4480eaf5bbc3 100644
> > --- a/Documentation/dev-tools/ktap.rst
> > +++ b/Documentation/dev-tools/ktap.rst
> > @@ -17,19 +17,20 @@ KTAP test results describe a series of tests (which may 
> > be nested: i.e., test
> >  can have subtests), each of which can contain both diagnostic data -- 
> > e.g., log
> >  lines -- and a final result. The test structure and results are
> >  machine-readable, whereas the diagnostic data is unstructured and is there 
> > to
> > -aid human debugging.
> > +aid human debugging. One exception to this is test metadata lines - a type
> > +of diagnostic lines. Test metadata is used to identify important 
> > supplemental
> > +test information and can be machine-readable.
> >
> >  KTAP output is built from four different types of lines:
> >  - Version lines
> >  - Plan lines
> >  - Test case result lines
> > -- Diagnostic lines
> > +- Diagnostic lines (including test metadata)
> >
> >  In general, valid KTAP output should also fo

Re: [KTAP V2 PATCH v2] ktap_v2: add test metadata

2024-02-05 Thread Rae Moar
On Sun, Feb 4, 2024 at 8:03 AM Kees Cook  wrote:
>
>
>
> On January 26, 2024 11:14:26 PM GMT+01:00, Rae Moar  wrote:
> > KTAP version 2
> > # ktap_test: main
> > # ktap_arch: uml
> > 1..1
> > KTAP version 2
> > # ktap_test: suite_1
> > # ktap_subsystem: example
> > # ktap_test_file: lib/test.c
>
> I think it's a mistake to mix "diagnostics" lines with semantic lines. Since 
> the diagnostic prefix is [# ] (hash space) how about make the test metadata 
> lines be [#:] (hash colon). For example:
>
>
>  1..2
>  ok 1 test_1
>  #:ktap_test: test_2
>  #:ktap_speed: very_slow
>  #:custom_is_flaky: true
>  # format-free stuff goes here
>  ok 2 test_2
> ...

Hello!

I really like this idea. The reason I chose the diagnostic line format
was to make it easier for existing parsers to parse the KTAP Metadata
lines. However, if it won't be too much of an issue for current
parsers, I think this idea would be better. So I am happy to change
this in the next version if there are no complaints.

>
> > ok 1 test_suite
> >
> >The changes to the KTAP specification outline the format, location, and
> >different types of metadata.
> >
> >Here is a link to a version of the KUnit parser that is able to parse test
> >metadata lines for KTAP version 2. Note this includes test metadata
> >lines for the main level of KTAP.
> >
> >Link: https://kunit-review.googlesource.com/c/linux/+/5889
> >
> >Signed-off-by: Rae Moar 
> >---
> > Documentation/dev-tools/ktap.rst | 163 ++-
> > 1 file changed, 159 insertions(+), 4 deletions(-)
> >
> >diff --git a/Documentation/dev-tools/ktap.rst 
> >b/Documentation/dev-tools/ktap.rst
> >index ff77f4aaa6ef..4480eaf5bbc3 100644
> >--- a/Documentation/dev-tools/ktap.rst
> >+++ b/Documentation/dev-tools/ktap.rst
> >@@ -17,19 +17,20 @@ KTAP test results describe a series of tests (which may 
> >be nested: i.e., test
> > can have subtests), each of which can contain both diagnostic data -- e.g., 
> > log
> > lines -- and a final result. The test structure and results are
> > machine-readable, whereas the diagnostic data is unstructured and is there 
> > to
>
> We even say it's unstructured... :)
>
>
> >+prefix must not include spaces or the characters ":" or "_".
>
> Why not _?

My thought here was that the first "_" character in the KTAP Metadata
line would indicate the separation between the prefix and metadata
type. So the prefix could not contain "_". This makes it easier to
parse. I'm inclined to keep this but also willing to change it if
there is a proposed prefix that contains "_".

Thanks!
-Rae

>
> --
> Kees Cook



Re: [PATCH] kunit: device: Unregister the kunit_bus on shutdown

2024-02-07 Thread Rae Moar
On Wed, Feb 7, 2024 at 8:36 AM Jani Nikula  wrote:
>
> On Fri, 02 Feb 2024, Rae Moar  wrote:
> > On Thu, Feb 1, 2024 at 1:06 AM David Gow  wrote:
> >>
> >> If KUnit is built as a module, and it's unloaded, the kunit_bus is not
> >> unregistered. This causes an error if it's then re-loaded later, as we
> >> try to re-register the bus.
> >>
> >> Unregister the bus and root_device on shutdown, if it looks valid.
> >>
> >> In addition, be more specific about the value of kunit_bus_device. It
> >> is:
> >> - a valid struct device* if the kunit_bus initialised correctly.
> >> - an ERR_PTR if it failed to initialise.
> >> - NULL before initialisation and after shutdown.
> >>
> >> Fixes: d03c720e03bd ("kunit: Add APIs for managing devices")
> >> Signed-off-by: David Gow 
> >
> > Hello,
> >
> > I have tested this with modules and it looks good to me!
> >
> > Thanks!
> > -Rae
> >
> > Reviewed-by: Rae Moar 
>
> Thanks for the patch and review!
>
> Is this on its way to some v6.8-rc's? The regression in -rc1 is hurting
> our CI.

Hello!

This patch has been accepted on the kselftest/kunit-fixes branch
(https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git/commit/?h=kunit-fixes&id=829388b725f8d266ccec32a2f446717d8693eaba)
and is heading towards a future v6.8-rc.

Thanks!
-Rae

>
>
> Thanks,
> Jani.
>
>
> --
> Jani Nikula, Intel



[KTAP V2 PATCH v3] ktap_v2: add test metadata

2024-02-15 Thread Rae Moar
Add specification for test metadata to the KTAP v2 spec.

KTAP v1 only specifies the output format of very basic test information:
test result and test name. Any additional test information either gets
added to general diagnostic data or is not included in the output at all.

The purpose of KTAP metadata is to create a framework to include and
easily identify additional important test information in KTAP.

KTAP metadata could include any test information that is pertinent for
user interaction before or after the running of the test. For example,
the test file path or the test speed.

Since this includes a large variety of information, this specification
will recognize notable types of KTAP metadata to ensure consistent format
across test frameworks. See the full list of types in the specification.

Example of KTAP Metadata:

 KTAP version 2
 #:ktap_test: main
 #:ktap_arch: uml
 1..1
 KTAP version 2
 #:ktap_test: suite_1
 #:ktap_subsystem: example
 #:ktap_test_file: lib/test.c
 1..2
 ok 1 test_1
 #:ktap_test: test_2
 #:ktap_speed: very_slow
 # test_2 has begun
 #:custom_is_flaky: true
 ok 2 test_2
 # suite_1 has passed
 ok 1 suite_1

The changes to the KTAP specification outline the format, location, and
different types of metadata.

Reviewed-by: David Gow 
Signed-off-by: Rae Moar 
---
Changes since v2:
- Change format of metadata line from "# prefix_type: value" to
  "#:prefix_type: value".
- Add examples of edge cases, such as diagnostic information interrupting
  metadata lines and lines in the wrong location, to the example in the
  specification.
- Add current list of accepted prefixes.
- Add notes on indentation and generated files.
- Fix a few typos.

 Documentation/dev-tools/ktap.rst | 182 ++-
 1 file changed, 178 insertions(+), 4 deletions(-)

diff --git a/Documentation/dev-tools/ktap.rst b/Documentation/dev-tools/ktap.rst
index ff77f4aaa6ef..42a7e50b9270 100644
--- a/Documentation/dev-tools/ktap.rst
+++ b/Documentation/dev-tools/ktap.rst
@@ -17,19 +17,22 @@ KTAP test results describe a series of tests (which may be 
nested: i.e., test
 can have subtests), each of which can contain both diagnostic data -- e.g., log
 lines -- and a final result. The test structure and results are
 machine-readable, whereas the diagnostic data is unstructured and is there to
-aid human debugging.
+aid human debugging. Since version 2, tests can also contain metadata which
+consists of important supplemental test information and can be
+machine-readable.
+
+KTAP output is built from five different types of lines:
 
-KTAP output is built from four different types of lines:
 - Version lines
 - Plan lines
 - Test case result lines
 - Diagnostic lines
+- Metadata lines
 
 In general, valid KTAP output should also form valid TAP output, but some
 information, in particular nested test results, may be lost. Also note that
 there is a stagnant draft specification for TAP14, KTAP diverges from this in
-a couple of places (notably the "Subtest" header), which are described where
-relevant later in this document.
+a couple of places, which are described where relevant later in this document.
 
 Version lines
 -
@@ -166,6 +169,171 @@ even if they do not start with a "#": this is to capture 
any other useful
 kernel output which may help debug the test. It is nevertheless recommended
 that tests always prefix any diagnostic output they have with a "#" character.
 
+KTAP metadata lines
+---
+
+KTAP metadata lines are used to include and easily identify important
+supplemental test information in KTAP. These lines may appear similar to
+diagnostic lines. The format of metadata lines is below:
+
+.. code-block:: none
+
+   #:_: 
+
+The  indicates where to find the specification for the type of
+metadata, such as the name of a test framework or "ktap" to indicate this
+specification. The list of currently approved prefixes and where to find the
+documentation of the metadata types is below. Note any metadata type that does
+not use a prefix from the list below must use the prefix "custom".
+
+Current List of Approved Prefixes:
+
+- ``ktap``: See Types of KTAP Metadata below for the list of metadata types.
+
+The format of  and  varies based on the type. See the
+individual specification. For "custom" types the  can be any
+string excluding ":", spaces, or newline characters and the  can be any
+string.
+
+**Location:**
+
+The first KTAP metadata line for a test must be "#:ktap_test: ",
+which acts as a header to associate metadata with the correct test. Metadata
+for the main KTAP level uses the test name "main".
+
+For test cases, the location of the metadata is between the prior test result
+line and the current test result line. For test suites, the location of the
+metadata is between the suite's version line an

Re: [PATCH 1/9] kunit: test: Log the correct filter string in executor_test

2024-02-22 Thread Rae Moar
On Wed, Feb 21, 2024 at 4:28 AM David Gow  wrote:
>
> KUnit's executor_test logs the filter string in KUNIT_ASSERT_EQ_MSG(),
> but passed a random character from the filter, rather than the whole
> string.
>
> This was found by annotating KUNIT_ASSERT_EQ_MSG() to let gcc validate
> the format string.
>
> Fixes: 76066f93f1df ("kunit: add tests for filtering attributes")
> Signed-off-by: David Gow 

Hello!

This change looks good to me. Thanks for fixing this mistake.

Thanks!
-Rae

Reviewed-by: Rae Moar 

> ---
>  lib/kunit/executor_test.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
> index 22d4ee86dbed..3f7f967e3688 100644
> --- a/lib/kunit/executor_test.c
> +++ b/lib/kunit/executor_test.c
> @@ -129,7 +129,7 @@ static void parse_filter_attr_test(struct kunit *test)
> GFP_KERNEL);
> for (j = 0; j < filter_count; j++) {
> parsed_filters[j] = kunit_next_attr_filter(&filter, &err);
> -   KUNIT_ASSERT_EQ_MSG(test, err, 0, "failed to parse filter 
> '%s'", filters[j]);
> +   KUNIT_ASSERT_EQ_MSG(test, err, 0, "failed to parse filter 
> from '%s'", filters);
> }
>
> KUNIT_EXPECT_STREQ(test, kunit_attr_filter_name(parsed_filters[0]), 
> "speed");
> --
> 2.44.0.rc0.258.g7320e95886-goog
>



[PATCH] kunit: tool: add parsing of all files in directory

2024-02-22 Thread Rae Moar
Add ability to parse all files within a directory. Additionally add the
ability to parse all results in the KUnit debugfs repository.

How to parse all files in directory:

./tools/testing/kunit/kunit.py parse [directory path]

How to parse KUnit debugfs repository:

./tools/testing/kunit/kunit.py parse debugfs

For each file, the parser outputs the file name, results, and test
summary. At the end of all parsing, the parser outputs a total summary
line.

This feature can be easily tested on the tools/testing/kunit/test_data/
directory.

Signed-off-by: Rae Moar 
---
 tools/testing/kunit/kunit.py | 45 ++--
 1 file changed, 33 insertions(+), 12 deletions(-)

diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index bc74088c458a..827e6dac40ae 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -511,19 +511,40 @@ def exec_handler(cli_args: argparse.Namespace) -> None:
 
 
 def parse_handler(cli_args: argparse.Namespace) -> None:
-   if cli_args.file is None:
+   parsed_files = []
+   total_test = kunit_parser.Test()
+   total_test.status = kunit_parser.TestStatus.SUCCESS
+   if cli_args.file_path is None:
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:
+   elif cli_args.file_path == "debugfs":
+   for (root, _, files) in os.walk("/sys/kernel/debug/kunit"):
+   for file in files:
+   if file == "results":
+   parsed_files.append(os.path.join(root, 
file))
+   elif os.path.isdir(cli_args.file_path):
+   for (root, _, files) in os.walk(cli_args.file_path):
+   for file in files:
+   parsed_files.append(os.path.join(root, file))
+   elif os.path.isfile(cli_args.file_path):
+   parsed_files.append(cli_args.file_path)
+
+   for file in parsed_files:
+   print(file)
+   with open(file, 'r', errors='backslashreplace') as f:
kunit_output = f.read().splitlines()
-   # We know nothing about how the result was created!
-   metadata = kunit_json.Metadata()
-   request = KunitParseRequest(raw_output=cli_args.raw_output,
-   json=cli_args.json)
-   result, _ = parse_tests(request, metadata, kunit_output)
-   if result.status != KunitStatus.SUCCESS:
-   sys.exit(1)
+   # We know nothing about how the result was created!
+   metadata = kunit_json.Metadata()
+   request = KunitParseRequest(raw_output=cli_args.raw_output,
+   json=cli_args.json)
+   _, test = parse_tests(request, metadata, kunit_output)
+   total_test.subtests.append(test)
+
+   if len(parsed_files) > 1: # if more than one file was parsed output 
total summary
+   print('All files parsed.')
+   stdout.print_with_timestamp(kunit_parser.DIVIDER)
+   kunit_parser.bubble_up_test_results(total_test)
+   kunit_parser.print_summary_line(total_test)
 
 
 subcommand_handlers_map = {
@@ -569,8 +590,8 @@ def main(argv: Sequence[str]) -> None:
help='Parses KUnit results from a 
file, '
'and parses formatted results.')
add_parse_opts(parse_parser)
-   parse_parser.add_argument('file',
- help='Specifies the file to read results 
from.',
+   parse_parser.add_argument('file_path',
+ help='Specifies the file path to read results 
from.',
  type=str, nargs='?', metavar='input_file')
 
cli_args = parser.parse_args(massage_argv(argv))

base-commit: 08c454e26daab6f843e5883fb96f680f11784fa6
-- 
2.44.0.rc0.258.g7320e95886-goog




Re: [PATCH] kunit: tool: add parsing of all files in directory

2024-02-27 Thread Rae Moar
On Thu, Feb 22, 2024 at 6:37 PM Daniel Latypov  wrote:
>
> On Thu, Feb 22, 2024 at 2:18 PM Rae Moar  wrote:
> >
> > Add ability to parse all files within a directory. Additionally add the
> > ability to parse all results in the KUnit debugfs repository.
>
> Nice, I'd been hoping for this.
> It's enough to pull me back in for a bit :)
>
> 
>
> >  tools/testing/kunit/kunit.py | 45 ++--
> >  1 file changed, 33 insertions(+), 12 deletions(-)
> >
> > diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
> > index bc74088c458a..827e6dac40ae 100755
> > --- a/tools/testing/kunit/kunit.py
> > +++ b/tools/testing/kunit/kunit.py
> > @@ -511,19 +511,40 @@ def exec_handler(cli_args: argparse.Namespace) -> 
> > None:
> >
> >
> >  def parse_handler(cli_args: argparse.Namespace) -> None:
> > -   if cli_args.file is None:
> > +   parsed_files = []
>
> optional: can we annotate the type?
>   parsed_files = []  # type: List[str]

Hi Daniel!

Yes, happy to make this change for the next version.

>
> > +   total_test = kunit_parser.Test()
> > +   total_test.status = kunit_parser.TestStatus.SUCCESS
> > +   if cli_args.file_path is None:
> > sys.stdin.reconfigure(errors='backslashreplace')  # type: 
> > ignore
> > kunit_output = sys.stdin  # type: Iterable[str]
>
> This branch no longer does anything, since we only parse what's in
> `parsed_files`
>
> E.g. if you try
> $ kunit.py parse $FILENAME
> it'll work whereas
> $ kunit.py parse < $FILENAME
> will do nothing
>
> We'll need to rework the control flow somehow

Ahh I see. Thanks for bringing this to my attention! I will change
this for the next version.

>
> > -   else:
> > -   with open(cli_args.file, 'r', errors='backslashreplace') as 
> > f:
> > +   elif cli_args.file_path == "debugfs":
> > +   for (root, _, files) in os.walk("/sys/kernel/debug/kunit"):
> > +   for file in files:
> > +   if file == "results":
> > +   
> > parsed_files.append(os.path.join(root, file))
> > +   elif os.path.isdir(cli_args.file_path):
> > +   for (root, _, files) in os.walk(cli_args.file_path):
> > +   for file in files:
> > +   parsed_files.append(os.path.join(root, 
> > file))
>
> just a note here, we could make this a bit terser via
>   parsed_files.extend(os.path.join(root, f) for f in files)
>
> and the debugfs branch could be rendered as
>   parsed_files.extend(os.path.join(root, f) for f in files if f == "results")
>

Will do.

> > +   elif os.path.isfile(cli_args.file_path):
> > +   parsed_files.append(cli_args.file_path)
>
> nit: should there be an `else` here that prints a warning?
>
> Example that would trigger this case and silently do nothing
> $ mkfifo /tmp/example_fifo
> $ ./tools/testing/kunit/kunit.py parse /tmp/example_fifo
> 
>

Yep you are definitely right I will add one here.

>
> 
>
> > @@ -569,8 +590,8 @@ def main(argv: Sequence[str]) -> None:
> > help='Parses KUnit results from 
> > a file, '
> > 'and parses formatted results.')
> > add_parse_opts(parse_parser)
> > -   parse_parser.add_argument('file',
> > - help='Specifies the file to read results 
> > from.',
> > +   parse_parser.add_argument('file_path',
> > + help='Specifies the file path to read 
> > results from.',
>
> Should this mention that the make `debugfs` string works?
>
> >   type=str, nargs='?', metavar='input_file')
>
> Tangent: would it be useful to allow the user to pass in multiple
> files now and set this to nargs='*'?
>
> E.g.
> $ kunit.py parse /my/dir/some_prefix*
>
> It would also let people implement their own version of the debugfs logic via
> $ find /other/debugfs/dir -name 'results' | xargs kunit.py parse
>
> That could be useful if the user has recursively copied off the
> debugfs from a test machine and wants to inspect it elsewhere, for
> example.
>

Oh this is an interesting idea. I will play around with it!

Thanks for looking this patch over!
-Rae

> Thanks,
> Daniel



[PATCH v2] kunit: tool: add ability to parse multiple files

2024-03-06 Thread Rae Moar
Add ability to parse multiple files. Additionally add the
ability to parse all results in the KUnit debugfs repository.

How to parse multiple files:

./tools/testing/kunit/kunit.py parse results.log results2.log

How to parse all files in directory:

./tools/testing/kunit/kunit.py parse directory_path/*

How to parse KUnit debugfs repository:

./tools/testing/kunit/kunit.py parse debugfs

For each file, the parser outputs the file name, results, and test
summary. At the end of all parsing, the parser outputs a total summary
line.

This feature can be easily tested on the tools/testing/kunit/test_data/
directory.

Signed-off-by: Rae Moar 
---
Changes since v1:
- Annotate type of parsed_files
- Add ability to input file name from stdin again
- Make for loops a bit terser
- Add no output warning
- Change feature to take in multiple fields rather than a directory.
  Currently nonrecursive. Let me know if people would prefer this as
  recursive.

 tools/testing/kunit/kunit.py | 45 +---
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index bc74088c458a..df804a118aa5 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -511,19 +511,37 @@ def exec_handler(cli_args: argparse.Namespace) -> None:
 
 
 def parse_handler(cli_args: argparse.Namespace) -> None:
-   if cli_args.file is None:
+   parsed_files = [] # type: List[str]
+   total_test = kunit_parser.Test()
+   total_test.status = kunit_parser.TestStatus.SUCCESS
+   if cli_args.files is None:
sys.stdin.reconfigure(errors='backslashreplace')  # type: ignore
-   kunit_output = sys.stdin  # type: Iterable[str]
+   parsed_files.append(sys.stdin)
+   elif cli_args.files[0] == "debugfs" and len(cli_args.files) == 1:
+   for (root, _, files) in os.walk("/sys/kernel/debug/kunit"):
+   parsed_files.extend(os.path.join(root, f) for f in 
files if f == "results")
else:
-   with open(cli_args.file, 'r', errors='backslashreplace') as f:
+   parsed_files.extend(f for f in cli_args.files if 
os.path.isfile(f))
+
+   if len(parsed_files) == 0:
+   print("No output found.")
+
+   for file in parsed_files:
+   print(file)
+   with open(file, 'r', errors='backslashreplace') as f:
kunit_output = f.read().splitlines()
-   # We know nothing about how the result was created!
-   metadata = kunit_json.Metadata()
-   request = KunitParseRequest(raw_output=cli_args.raw_output,
-   json=cli_args.json)
-   result, _ = parse_tests(request, metadata, kunit_output)
-   if result.status != KunitStatus.SUCCESS:
-   sys.exit(1)
+   # We know nothing about how the result was created!
+   metadata = kunit_json.Metadata()
+   request = KunitParseRequest(raw_output=cli_args.raw_output,
+   json=cli_args.json)
+   _, test = parse_tests(request, metadata, kunit_output)
+   total_test.subtests.append(test)
+
+   if len(parsed_files) > 1: # if more than one file was parsed output 
total summary
+   print('All files parsed.')
+   stdout.print_with_timestamp(kunit_parser.DIVIDER)
+   kunit_parser.bubble_up_test_results(total_test)
+   kunit_parser.print_summary_line(total_test)
 
 
 subcommand_handlers_map = {
@@ -569,9 +587,10 @@ def main(argv: Sequence[str]) -> None:
help='Parses KUnit results from a 
file, '
'and parses formatted results.')
add_parse_opts(parse_parser)
-   parse_parser.add_argument('file',
- help='Specifies the file to read results 
from.',
- type=str, nargs='?', metavar='input_file')
+   parse_parser.add_argument('files',
+ help='List of file paths to read results from 
or keyword'
+   '"debugfs" to read all results 
from the debugfs directory.',
+ type=str, nargs='*', metavar='input_files')
 
cli_args = parser.parse_args(massage_argv(argv))
 

base-commit: 806cb2270237ce2ec672a407d66cee17a07d3aa2
-- 
2.44.0.278.ge034bb2e1d-goog




[PATCH v3] kunit: tool: add ability to parse multiple files

2024-03-07 Thread Rae Moar
Add ability to parse multiple files. Additionally add the
ability to parse all results in the KUnit debugfs repository.

How to parse multiple files:

./tools/testing/kunit/kunit.py parse results.log results2.log

How to parse all files in directory:

./tools/testing/kunit/kunit.py parse directory_path/*

How to parse KUnit debugfs repository:

./tools/testing/kunit/kunit.py parse debugfs

For each file, the parser outputs the file name, results, and test
summary. At the end of all parsing, the parser outputs a total summary
line.

This feature can be easily tested on the tools/testing/kunit/test_data/
directory.

Signed-off-by: Rae Moar 
---
Changes since v2:
- Fixed bug with input from command line. I changed this to use
  input(). Daniel, let me know if this works for you.
- Add more specific warning messages

 tools/testing/kunit/kunit.py | 56 +---
 1 file changed, 40 insertions(+), 16 deletions(-)

diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index bc74088c458a..1aa3d736d80c 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -511,19 +511,42 @@ def exec_handler(cli_args: argparse.Namespace) -> None:
 
 
 def parse_handler(cli_args: argparse.Namespace) -> None:
-   if cli_args.file is None:
-   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()
-   # We know nothing about how the result was created!
-   metadata = kunit_json.Metadata()
-   request = KunitParseRequest(raw_output=cli_args.raw_output,
-   json=cli_args.json)
-   result, _ = parse_tests(request, metadata, kunit_output)
-   if result.status != KunitStatus.SUCCESS:
-   sys.exit(1)
+   parsed_files = cli_args.files # type: List[str]
+   total_test = kunit_parser.Test()
+   total_test.status = kunit_parser.TestStatus.SUCCESS
+   if not parsed_files:
+   parsed_files.append(input("File path: "))
+
+   if parsed_files[0] == "debugfs" and len(parsed_files) == 1:
+   parsed_files.pop()
+   for (root, _, files) in os.walk("/sys/kernel/debug/kunit"):
+   parsed_files.extend(os.path.join(root, f) for f in 
files if f == "results")
+
+   if not parsed_files:
+   print("No files found.")
+
+   for file in parsed_files:
+   if os.path.isfile(file):
+   print(file)
+   with open(file, 'r', errors='backslashreplace') as f:
+   kunit_output = f.read().splitlines()
+   # We know nothing about how the result was created!
+   metadata = kunit_json.Metadata()
+   request = 
KunitParseRequest(raw_output=cli_args.raw_output,
+   json=cli_args.json)
+   _, test = parse_tests(request, metadata, kunit_output)
+   total_test.subtests.append(test)
+   elif os.path.isdir(file):
+   print("Ignoring directory ", file)
+   else:
+   print("Could not find ", file)
+
+   if len(parsed_files) > 1: # if more than one file was parsed output 
total summary
+   print('All files parsed.')
+   if not request.raw_output:
+   stdout.print_with_timestamp(kunit_parser.DIVIDER)
+   kunit_parser.bubble_up_test_results(total_test)
+   kunit_parser.print_summary_line(total_test)
 
 
 subcommand_handlers_map = {
@@ -569,9 +592,10 @@ def main(argv: Sequence[str]) -> None:
help='Parses KUnit results from a 
file, '
'and parses formatted results.')
add_parse_opts(parse_parser)
-   parse_parser.add_argument('file',
- help='Specifies the file to read results 
from.',
- type=str, nargs='?', metavar='input_file')
+   parse_parser.add_argument('files',
+ help='List of file paths to read results from 
or keyword'
+   '"debugfs" to read all results 
from the debugfs directory.',
+ type=str, nargs='*', metavar='input_files')
 
cli_args = parser.parse_args(massage_argv(argv))
 

base-commit: 806cb2270237ce2ec672a407d66cee17a07d3aa2
-- 
2.44.0.278.ge034bb2e1d-goog




Re: [PATCH v3] kunit: tool: add ability to parse multiple files

2024-03-18 Thread Rae Moar
On Fri, Mar 15, 2024 at 7:16 PM Daniel Latypov  wrote:
>
> On Thu, Mar 7, 2024 at 2:29 PM Rae Moar  wrote:
> >
> > Add ability to parse multiple files. Additionally add the
> > ability to parse all results in the KUnit debugfs repository.
> >
> > How to parse multiple files:
> >
> > ./tools/testing/kunit/kunit.py parse results.log results2.log
> >
> > How to parse all files in directory:
> >
> > ./tools/testing/kunit/kunit.py parse directory_path/*
> >
> > How to parse KUnit debugfs repository:
> >
> > ./tools/testing/kunit/kunit.py parse debugfs
> >
> > For each file, the parser outputs the file name, results, and test
> > summary. At the end of all parsing, the parser outputs a total summary
> > line.
> >
> > This feature can be easily tested on the tools/testing/kunit/test_data/
> > directory.
> >
> > Signed-off-by: Rae Moar 
> > ---
> > Changes since v2:
> > - Fixed bug with input from command line. I changed this to use
> >   input(). Daniel, let me know if this works for you.
>
> Oops, sorry for the delay.

Hi!

No worries at all. Thanks for the review!

>
> Hmm, it seems to be treating the stdin lines like file names
>
> $ ./tools/testing/kunit/kunit.py parse <
> ./tools/testing/kunit/test_data/test_config_printk_time.log
> File path: Could not find  [0.06] printk: console [mc-1] enabled
>
> Oh, I see, we're prompting the user via
>   input("File path: ")
> ?
>
> I'm not necessarily against such a change, but I would personally
> prefer the old behavior of being able to read ktap from stdin
> directly.
> As a user, I'd also prefer to only type out filenames as arguments
> where I can get autocomplete, so `input()` here wouldn't help me
> personally.
>
> Applying a hackish patch like this [1] on top gets the behavior I'd
> personally expect:
> $ ./tools/testing/kunit/kunit.py parse <
> ./tools/testing/kunit/test_data/test_config_printk_time.log
> /dev/stdin
> ...
> [16:01:50] Testing complete. Ran 10 tests: passed: 10
>
> I'd mentioned in the previous version that we could have parsed files
> contain a `Union[str, TextIO]` and then read from the `sys.stdin` file
> object directly.
> But having it blindly open `/dev/stdin` seems to work just the same,
> if we want to keep our list simpler and just hold strings.
>

I definitely see why the change to stdin would be better. My original
change to input() was to keep it simple. But I really like the change
listed below. I will go ahead and implement that.

> [1] this just also re-orders the `os.path.isdir()` check as mentioned
> below, which simplifies things
> diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
> index 1aa3d736d80c..311d107bd684 100755
> --- a/tools/testing/kunit/kunit.py
> +++ b/tools/testing/kunit/kunit.py
> @@ -515,18 +515,18 @@ def parse_handler(cli_args: argparse.Namespace) -> None:
> total_test = kunit_parser.Test()
> total_test.status = kunit_parser.TestStatus.SUCCESS
> if not parsed_files:
> -   parsed_files.append(input("File path: "))
> -
> -   if parsed_files[0] == "debugfs" and len(parsed_files) == 1:
> +   parsed_files.append('/dev/stdin')
> +   elif len(parsed_files) == 1 and parsed_files[0] == "debugfs":
> parsed_files.pop()
> for (root, _, files) in os.walk("/sys/kernel/debug/kunit"):
> parsed_files.extend(os.path.join(root, f) for
> f in files if f == "results")
> -
> -   if not parsed_files:
> -   print("No files found.")
> +   if not parsed_files:
> +   print("No files found.")
>
> for file in parsed_files:
> -   if os.path.isfile(file):
> +   if os.path.isdir(file):
> +   print("Ignoring directory ", file)
> +   elif os.path.exists(file):
> print(file)
> with open(file, 'r', errors='backslashreplace') as f:
> kunit_output = f.read().splitlines()
> @@ -536,8 +536,6 @@ def parse_handler(cli_args: argparse.Namespace) -> None:
> json=cli_args.json)
> _, test = parse_tests(request, metadata, kunit_output)
> total_test.subtests.append(test)
> -   elif os.path.isdir(file):
> -   print("Ignoring director

[PATCH v4] kunit: tool: add ability to parse multiple files

2024-03-18 Thread Rae Moar
Add ability to parse multiple files. Additionally add the
ability to parse all results in the KUnit debugfs repository.

How to parse multiple files:

./tools/testing/kunit/kunit.py parse results.log results2.log

How to parse all files in directory:

./tools/testing/kunit/kunit.py parse directory_path/*

How to parse KUnit debugfs repository:

./tools/testing/kunit/kunit.py parse debugfs

For each file, the parser outputs the file name, results, and test
summary. At the end of all parsing, the parser outputs a total summary
line.

This feature can be easily tested on the tools/testing/kunit/test_data/
directory.

Signed-off-by: Rae Moar 
---
Changes since v3:
- Changing from input() to stdin
- Add checking for non-regular files
- Spacing fix
- Small printing fix

 tools/testing/kunit/kunit.py | 54 +---
 1 file changed, 38 insertions(+), 16 deletions(-)

diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index bc74088c458a..641b8ca83e3e 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -511,19 +511,40 @@ def exec_handler(cli_args: argparse.Namespace) -> None:
 
 
 def parse_handler(cli_args: argparse.Namespace) -> None:
-   if cli_args.file is None:
-   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()
-   # We know nothing about how the result was created!
-   metadata = kunit_json.Metadata()
-   request = KunitParseRequest(raw_output=cli_args.raw_output,
-   json=cli_args.json)
-   result, _ = parse_tests(request, metadata, kunit_output)
-   if result.status != KunitStatus.SUCCESS:
-   sys.exit(1)
+   parsed_files = cli_args.files # type: List[str]
+   total_test = kunit_parser.Test()
+   total_test.status = kunit_parser.TestStatus.SUCCESS
+   if not parsed_files:
+   parsed_files.append('/dev/stdin')
+   elif len(parsed_files) == 1 and parsed_files[0] == "debugfs":
+   parsed_files.pop()
+   for (root, _, files) in os.walk("/sys/kernel/debug/kunit"):
+   parsed_files.extend(os.path.join(root, f) for f in 
files if f == "results")
+   if not parsed_files:
+   print("No files found.")
+
+   for file in parsed_files:
+   if os.path.isdir(file):
+   print(f'Ignoring directory "{file}"')
+   elif os.path.exists(file):
+   print(file)
+   with open(file, 'r', errors='backslashreplace') as f:
+   kunit_output = f.read().splitlines()
+   # We know nothing about how the result was created!
+   metadata = kunit_json.Metadata()
+   request = 
KunitParseRequest(raw_output=cli_args.raw_output,
+   json=cli_args.json)
+   _, test = parse_tests(request, metadata, kunit_output)
+   total_test.subtests.append(test)
+   else:
+   print(f'Could not find "{file}"')
+
+   if len(parsed_files) > 1: # if more than one file was parsed output 
total summary
+   print('All files parsed.')
+   if not request.raw_output:
+   stdout.print_with_timestamp(kunit_parser.DIVIDER)
+   kunit_parser.bubble_up_test_results(total_test)
+   kunit_parser.print_summary_line(total_test)
 
 
 subcommand_handlers_map = {
@@ -569,9 +590,10 @@ def main(argv: Sequence[str]) -> None:
help='Parses KUnit results from a 
file, '
'and parses formatted results.')
add_parse_opts(parse_parser)
-   parse_parser.add_argument('file',
- help='Specifies the file to read results 
from.',
- type=str, nargs='?', metavar='input_file')
+   parse_parser.add_argument('files',
+ help='List of file paths to read results from 
or keyword'
+ '"debugfs" to read all results from the 
debugfs directory.',
+ type=str, nargs='*', metavar='input_files')
 
cli_args = parser.parse_args(massage_argv(argv))
 

base-commit: 806cb2270237ce2ec672a407d66cee17a07d3aa2
-- 
2.44.0.291.gc1ea87d7ee-goog




Re: [PATCH] kunit: bail out early in __kunit_test_suites_init() if there are no suites to test

2024-03-21 Thread Rae Moar
On Thu, Mar 21, 2024 at 10:32 AM Scott Mayhew  wrote:
>
> Commit c72a870926c2 added a mutex to prevent kunit tests from running
> concurrently.  Unfortunately that mutex gets locked during module load
> regardless of whether the module actually has any kunit tests.  This
> causes a problem for kunit tests that might need to load other kernel
> modules (e.g. gss_krb5_test loading the camellia module).
>
> So check to see if there are actually any tests to run before locking
> the kunit_run_lock mutex.
>
> Fixes: c72a870926c2 ("kunit: add ability to run tests after boot using 
> debugfs")
> Reported-by: Nico Pache 
> Signed-off-by: Scott Mayhew 

Hi!

Sorry about this bug. Thanks for the patch! We should definitely add this check.

Reviewed-by: Rae Moar 

Thanks!

-Rae

> ---
>  lib/kunit/test.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index 1d1475578515..b8514dbb337c 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -712,6 +712,9 @@ int __kunit_test_suites_init(struct kunit_suite * const * 
> const suites, int num_
>  {
> unsigned int i;
>
> +   if (num_suites == 0)
> +   return 0;
> +
> if (!kunit_enabled() && num_suites > 0) {
> pr_info("kunit: disabled\n");
> return 0;
> --
> 2.43.0
>



Re: [PATCH] kunit: configs: Enable CONFIG_DAMON_DBGFS_DEPRECATED for --alltests

2024-03-27 Thread Rae Moar
On Tue, Mar 26, 2024 at 6:07 AM David Gow  wrote:
>
> This is required, as CONFIG_DAMON_DEBUGFS is enabled, and --alltests UML
> builds will fail due to the missing config option otherwise.
>
> Fixes: f4cba4bf6777 ("mm/damon: rename CONFIG_DAMON_DBGFS to 
> DAMON_DBGFS_DEPRECATED")
> Signed-off-by: David Gow 

Hello!

This looks good to me. And it takes away the issue with
CONFIG_DAMON_DBGFS. But since this is deprecated now, should we move
to the DAMON sysfs tests instead in the future? No need to let that
stall this patch though.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
>
> This is breaking all UML alltests builds, so we'd like to fix it sooner
> rather than later. SeongJae, would you rather take this yourself, or can
> we push it alongside any other KUnit fixes?
>
> Johannes: Does this conflict with the CONFIG_NETDEVICES / CONFIG_WLAN
> fixes to all_tests.config? I'd assume not, but I'm happy to take them
> via KUnit if you'd prefer anyway.
>
> Thanks,
> -- David
>
> ---
>  tools/testing/kunit/configs/all_tests.config | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/tools/testing/kunit/configs/all_tests.config 
> b/tools/testing/kunit/configs/all_tests.config
> index aa5ec149f96c..f388742cf266 100644
> --- a/tools/testing/kunit/configs/all_tests.config
> +++ b/tools/testing/kunit/configs/all_tests.config
> @@ -38,6 +38,7 @@ CONFIG_DAMON_VADDR=y
>  CONFIG_DAMON_PADDR=y
>  CONFIG_DEBUG_FS=y
>  CONFIG_DAMON_DBGFS=y
> +CONFIG_DAMON_DBGFS_DEPRECATED=y
>
>  CONFIG_REGMAP_BUILD=y
>
> --
> 2.44.0.396.g6e790dbe36-goog
>



[KTAP V2 PATCH v4] ktap_v2: add test metadata

2024-04-03 Thread Rae Moar
Add specification for test metadata to the KTAP v2 spec.

KTAP v1 only specifies the output format of very basic test information:
test result and test name. Any additional test information either gets
added to general diagnostic data or is not included in the output at all.

The purpose of KTAP metadata is to create a framework to include and
easily identify additional important test information in KTAP.

KTAP metadata could include any test information that is pertinent for
user interaction before or after the running of the test. For example,
the test file path or the test speed.

Since this includes a large variety of information, this specification
will recognize notable types of KTAP metadata to ensure consistent format
across test frameworks. See the full list of types in the specification.

Example of KTAP Metadata:

 KTAP version 2
 #:ktap_test: main
 #:ktap_arch: uml
 1..1
 KTAP version 2
 #:ktap_test: suite_1
 #:ktap_subsystem: example
 #:ktap_test_file: lib/test.c
 1..2
 ok 1 test_1
 #:ktap_test: test_2
 #:ktap_speed: very_slow
 # test_2 has begun
 #:custom_is_flaky: true
 ok 2 test_2
 # suite_1 has passed
 ok 1 suite_1

The changes to the KTAP specification outline the format, location, and
different types of metadata.

Reviewed-by: Kees Cook 
Reviewed-by: David Gow 
Signed-off-by: Rae Moar 
---
Note this version is in reponse to comments made off the list asking for
more explanation on inheritance and edge cases.

Changes since v3:
- Add two metadata ktap_config and ktap_id
- Add section on metadata inheritance
- Add edge case examples

 Documentation/dev-tools/ktap.rst | 248 ++-
 1 file changed, 244 insertions(+), 4 deletions(-)

diff --git a/Documentation/dev-tools/ktap.rst b/Documentation/dev-tools/ktap.rst
index ff77f4aaa6ef..55bc43cd5aea 100644
--- a/Documentation/dev-tools/ktap.rst
+++ b/Documentation/dev-tools/ktap.rst
@@ -17,19 +17,22 @@ KTAP test results describe a series of tests (which may be 
nested: i.e., test
 can have subtests), each of which can contain both diagnostic data -- e.g., log
 lines -- and a final result. The test structure and results are
 machine-readable, whereas the diagnostic data is unstructured and is there to
-aid human debugging.
+aid human debugging. Since version 2, tests can also contain metadata which
+consists of important supplemental test information and can be
+machine-readable.
+
+KTAP output is built from five different types of lines:
 
-KTAP output is built from four different types of lines:
 - Version lines
 - Plan lines
 - Test case result lines
 - Diagnostic lines
+- Metadata lines
 
 In general, valid KTAP output should also form valid TAP output, but some
 information, in particular nested test results, may be lost. Also note that
 there is a stagnant draft specification for TAP14, KTAP diverges from this in
-a couple of places (notably the "Subtest" header), which are described where
-relevant later in this document.
+a couple of places, which are described where relevant later in this document.
 
 Version lines
 -
@@ -166,6 +169,237 @@ even if they do not start with a "#": this is to capture 
any other useful
 kernel output which may help debug the test. It is nevertheless recommended
 that tests always prefix any diagnostic output they have with a "#" character.
 
+KTAP metadata lines
+---
+
+KTAP metadata lines are used to include and easily identify important
+supplemental test information in KTAP. These lines may appear similar to
+diagnostic lines. The format of metadata lines is below:
+
+.. code-block:: none
+
+   #:_: 
+
+The  indicates where to find the specification for the type of
+metadata, such as the name of a test framework or "ktap" to indicate this
+specification. The list of currently approved prefixes and where to find the
+documentation of the metadata types is below. Note any metadata type that does
+not use a prefix from the list below must use the prefix "custom".
+
+Current List of Approved Prefixes:
+
+- ``ktap``: See Types of KTAP Metadata below for the list of metadata types.
+
+The format of  and  varies based on the type. See the
+individual specification. For "custom" types the  can be any
+string excluding ":", spaces, or newline characters and the  can be any
+string.
+
+**Location:**
+
+The first KTAP metadata line for a test must be "#:ktap_test: ",
+which acts as a header to associate metadata with the correct test. Metadata
+for the main KTAP level uses the test name "main". A test's metadata ends
+with a "ktap_test" line for a different test.
+
+For test cases, the location of the metadata is between the prior test result
+line and the current test result line. For test suites, the location of the
+metadata is between the suite's version line and test plan line. For the main
+level,

Re: [PATCH] kunit/usercopy: Add missing MODULE_DESCRIPTION()

2024-06-20 Thread Rae Moar
On Wed, Jun 19, 2024 at 4:27 PM Kees Cook  wrote:
>
> From: Jeff Johnson 
>
> Fix warning seen with:
>
> $ make allmodconfig && make W=1 C=1 lib/usercopy_kunit.ko
> WARNING: modpost: missing MODULE_DESCRIPTION() in lib/usercopy_kunit.o
>
> Signed-off-by: Jeff Johnson 
> Signed-off-by: Kees Cook 

Hi!

This looks good to me.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
> At Jeff's reminder, I've split this out of:
> https://lore.kernel.org/all/20240601-md-lib-test-v1-1-a728620e3...@quicinc.com/
> since the file got renamed.
> ---
> Cc: Shuah Khan 
> Cc: Jeff Johnson 
> Cc: Brendan Higgins 
> Cc: David Gow 
> Cc: Rae Moar 
> Cc: "Gustavo A. R. Silva" 
> Cc: Andrew Morton 
> Cc: linux-kselftest@vger.kernel.org
> Cc: kunit-...@googlegroups.com
> Cc: linux-harden...@vger.kernel.org
> Cc: linux...@kvack.org
> ---
>  lib/usercopy_kunit.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/lib/usercopy_kunit.c b/lib/usercopy_kunit.c
> index e819561a540d..77fa00a13df7 100644
> --- a/lib/usercopy_kunit.c
> +++ b/lib/usercopy_kunit.c
> @@ -331,4 +331,5 @@ static struct kunit_suite usercopy_test_suite = {
>
>  kunit_test_suites(&usercopy_test_suite);
>  MODULE_AUTHOR("Kees Cook ");
> +MODULE_DESCRIPTION("Kernel module for testing copy_to/from_user 
> infrastructure");
>  MODULE_LICENSE("GPL");
> --
> 2.34.1
>



Re: [PATCH v2] kunit/usercopy: Disable testing on !CONFIG_MMU

2024-06-20 Thread Rae Moar
On Wed, Jun 19, 2024 at 4:25 PM Kees Cook  wrote:
>
> Since arch_pick_mmap_layout() is an inline for non-MMU systems, disable
> this test there.
>
> Reported-by: kernel test robot 
> Closes: 
> https://lore.kernel.org/oe-kbuild-all/202406160505.ubge6tmy-...@intel.com/
> Signed-off-by: Kees Cook 

Hello!

This looks good to me. And seems to fix the problem. Thanks for the fix!

Reviewed-by: Rae Moar 

-Rae

> ---
> Resending as v2 with Shuah in To:
> ---
> Cc: Shuah Khan 
> Cc: Brendan Higgins 
> Cc: David Gow 
> Cc: Rae Moar 
> Cc: "Gustavo A. R. Silva" 
> Cc: Andrew Morton 
> Cc: linux-kselftest@vger.kernel.org
> Cc: kunit-...@googlegroups.com
> Cc: linux-harden...@vger.kernel.org
> Cc: linux...@kvack.org
> ---
>  lib/kunit/user_alloc.c | 4 
>  lib/usercopy_kunit.c   | 5 +
>  mm/util.c  | 2 ++
>  3 files changed, 11 insertions(+)
>
> diff --git a/lib/kunit/user_alloc.c b/lib/kunit/user_alloc.c
> index 76d3d1345ed7..ae935df09a5e 100644
> --- a/lib/kunit/user_alloc.c
> +++ b/lib/kunit/user_alloc.c
> @@ -30,6 +30,10 @@ static int kunit_attach_mm(void)
> if (current->mm)
> return 0;
>
> +   /* arch_pick_mmap_layout() is only sane with MMU systems. */
> +   if (!IS_ENABLED(CONFIG_MMU))
> +   return -EINVAL;
> +
> mm = mm_alloc();
> if (!mm)
> return -ENOMEM;
> diff --git a/lib/usercopy_kunit.c b/lib/usercopy_kunit.c
> index 45f1e558c464..e819561a540d 100644
> --- a/lib/usercopy_kunit.c
> +++ b/lib/usercopy_kunit.c
> @@ -290,6 +290,11 @@ static int usercopy_test_init(struct kunit *test)
> struct usercopy_test_priv *priv;
> unsigned long user_addr;
>
> +   if (!IS_ENABLED(CONFIG_MMU)) {
> +   kunit_skip(test, "Userspace allocation testing not available 
> on non-MMU systems");
> +   return 0;
> +   }
> +
> priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
> test->priv = priv;
> diff --git a/mm/util.c b/mm/util.c
> index df37c47d9374..e70e8e439258 100644
> --- a/mm/util.c
> +++ b/mm/util.c
> @@ -484,7 +484,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm, struct 
> rlimit *rlim_stack)
> clear_bit(MMF_TOPDOWN, &mm->flags);
>  }
>  #endif
> +#ifdef CONFIG_MMU
>  EXPORT_SYMBOL_IF_KUNIT(arch_pick_mmap_layout);
> +#endif
>
>  /**
>   * __account_locked_vm - account locked pages to an mm's locked_vm
> --
> 2.34.1
>



Re: [PATCH v2 1/5] kunit: string-stream: export non-static functions

2024-06-21 Thread Rae Moar
On Tue, Jun 18, 2024 at 1:03 PM Ivan Orlov  wrote:
>
> Export non-static functions from the string-stream.c file into the KUnit
> namespace in order to be able to access them from the KUnit core tests
> (when they are loaded as modules).
>
> Reviewed-by: David Gow 
> Signed-off-by: Ivan Orlov 

Hello!

This looks good to me.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
> V1 -> V2:
> - No changes
>
>  lib/kunit/string-stream.c | 12 +++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
> index 54f4fdcbfac8..a5e3339854da 100644
> --- a/lib/kunit/string-stream.c
> +++ b/lib/kunit/string-stream.c
> @@ -10,7 +10,7 @@
>  #include 
>  #include 
>  #include 
> -
> +#include 
>  #include "string-stream.h"
>
>
> @@ -86,6 +86,7 @@ int string_stream_vadd(struct string_stream *stream,
>
> return 0;
>  }
> +EXPORT_SYMBOL_IF_KUNIT(string_stream_vadd);
>
>  int string_stream_add(struct string_stream *stream, const char *fmt, ...)
>  {
> @@ -98,6 +99,7 @@ int string_stream_add(struct string_stream *stream, const 
> char *fmt, ...)
>
> return result;
>  }
> +EXPORT_SYMBOL_IF_KUNIT(string_stream_add);
>
>  void string_stream_clear(struct string_stream *stream)
>  {
> @@ -113,6 +115,7 @@ void string_stream_clear(struct string_stream *stream)
> stream->length = 0;
> spin_unlock(&stream->lock);
>  }
> +EXPORT_SYMBOL_IF_KUNIT(string_stream_clear);
>
>  char *string_stream_get_string(struct string_stream *stream)
>  {
> @@ -131,6 +134,7 @@ char *string_stream_get_string(struct string_stream 
> *stream)
>
> return buf;
>  }
> +EXPORT_SYMBOL_IF_KUNIT(string_stream_get_string);
>
>  int string_stream_append(struct string_stream *stream,
>  struct string_stream *other)
> @@ -148,11 +152,13 @@ int string_stream_append(struct string_stream *stream,
>
> return ret;
>  }
> +EXPORT_SYMBOL_IF_KUNIT(string_stream_append);
>
>  bool string_stream_is_empty(struct string_stream *stream)
>  {
> return list_empty(&stream->fragments);
>  }
> +EXPORT_SYMBOL_IF_KUNIT(string_stream_is_empty);
>
>  struct string_stream *alloc_string_stream(gfp_t gfp)
>  {
> @@ -168,6 +174,7 @@ struct string_stream *alloc_string_stream(gfp_t gfp)
>
> return stream;
>  }
> +EXPORT_SYMBOL_IF_KUNIT(alloc_string_stream);
>
>  void string_stream_destroy(struct string_stream *stream)
>  {
> @@ -179,6 +186,7 @@ void string_stream_destroy(struct string_stream *stream)
> string_stream_clear(stream);
> kfree(stream);
>  }
> +EXPORT_SYMBOL_IF_KUNIT(string_stream_destroy);
>
>  static void resource_free_string_stream(void *p)
>  {
> @@ -200,8 +208,10 @@ struct string_stream *kunit_alloc_string_stream(struct 
> kunit *test, gfp_t gfp)
>
> return stream;
>  }
> +EXPORT_SYMBOL_IF_KUNIT(kunit_alloc_string_stream);
>
>  void kunit_free_string_stream(struct kunit *test, struct string_stream 
> *stream)
>  {
> kunit_release_action(test, resource_free_string_stream, (void 
> *)stream);
>  }
> +EXPORT_SYMBOL_IF_KUNIT(kunit_free_string_stream);
> --
> 2.34.1
>



Re: [PATCH v2 2/5] kunit: kunit-test: Remove stub for log tests

2024-06-21 Thread Rae Moar
On Tue, Jun 18, 2024 at 1:03 PM Ivan Orlov  wrote:
>
> Since now we are exporting string-stream functions into the KUnit
> namespace, we can safely use them in kunit-test when it is compiled as
> a module as well. So, remove the stubs used when kunit-test is compiled
> as a module. Import the KUnit namespace in the test.
>
> Reviewed-by: David Gow 
> Signed-off-by: Ivan Orlov 

Hello!

This seems good to me.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
> V1 -> V2:
> - No changes
>
>  lib/kunit/kunit-test.c | 18 +-
>  1 file changed, 1 insertion(+), 17 deletions(-)
>
> diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
> index 37e02be1e710..d86f7cb3b3e4 100644
> --- a/lib/kunit/kunit-test.c
> +++ b/lib/kunit/kunit-test.c
> @@ -577,12 +577,6 @@ static struct kunit_suite kunit_resource_test_suite = {
> .test_cases = kunit_resource_test_cases,
>  };
>
> -/*
> - * Log tests call string_stream functions, which aren't exported. So only
> - * build this code if this test is built-in.
> - */
> -#if IS_BUILTIN(CONFIG_KUNIT_TEST)
> -
>  /* This avoids a cast warning if kfree() is passed direct to 
> kunit_add_action(). */
>  KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
>
> @@ -637,17 +631,6 @@ static void kunit_log_newline_test(struct kunit *test)
> kunit_skip(test, "only useful when debugfs is enabled");
> }
>  }
> -#else
> -static void kunit_log_test(struct kunit *test)
> -{
> -   kunit_skip(test, "Log tests only run when built-in");
> -}
> -
> -static void kunit_log_newline_test(struct kunit *test)
> -{
> -   kunit_skip(test, "Log tests only run when built-in");
> -}
> -#endif /* IS_BUILTIN(CONFIG_KUNIT_TEST) */
>
>  static struct kunit_case kunit_log_test_cases[] = {
> KUNIT_CASE(kunit_log_test),
> @@ -872,4 +855,5 @@ kunit_test_suites(&kunit_try_catch_test_suite, 
> &kunit_resource_test_suite,
>   &kunit_fault_test_suite);
>
>  MODULE_DESCRIPTION("KUnit test for core test infrastructure");
> +MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
>  MODULE_LICENSE("GPL v2");
> --
> 2.34.1
>



Re: [PATCH v2 3/5] kunit: string-stream-test: Make it a separate module

2024-06-21 Thread Rae Moar
On Tue, Jun 18, 2024 at 1:03 PM Ivan Orlov  wrote:
>
> Currently, the only way to build string-stream-test is by setting
> CONFIG_KUNIT_TEST=y. However, CONFIG_KUNIT_TEST is a config option for
> a different test (`kunit-test.c`).
>
> Introduce a new Kconfig entry in order to be able to build the
> string-stream-test test as a separate module. Import the KUnit namespace
> in the test so we could have string-stream functions accessible.
>
> Reviewed-by: David Gow 
> Signed-off-by: Ivan Orlov 

Hello!

This is looking good to me other than the module description as noted
by Jeff. That could be a separate patch since the rest of the series
is looking good.

There is the checkpatch warning on the module description. But as
David mentioned, the description looks ok to me. If there is a new
version of this patch, it may be worth trying to get rid of the
warning by lengthening the description.

But I am happy with this patch as is.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
> V1 -> V2:
> - No changes
>
>  lib/kunit/Kconfig  | 8 
>  lib/kunit/Makefile | 2 +-
>  lib/kunit/string-stream-test.c | 2 ++
>  3 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig
> index 34d7242d526d..b0713c0f9265 100644
> --- a/lib/kunit/Kconfig
> +++ b/lib/kunit/Kconfig
> @@ -45,6 +45,14 @@ config KUNIT_TEST
>   purposes by developers interested in testing that KUnit works as
>   expected.
>
> +config KUNIT_STRING_STREAM_TEST
> +   tristate "KUnit test for string-stream" if !KUNIT_ALL_TESTS
> +   default KUNIT_ALL_TESTS
> +   help
> + Enables the KUnit test for the string-stream (C++ stream style 
> string
> + builder used in KUnit for building messages). For the string-stream
> + implementation, see lib/kunit/string-stream.c.
> +
>  config KUNIT_EXAMPLE_TEST
> tristate "Example test for KUnit" if !KUNIT_ALL_TESTS
> default KUNIT_ALL_TESTS
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 30f6bbf04a4a..478beb536dc9 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -19,10 +19,10 @@ endif
>  obj-y +=   hooks.o
>
>  obj-$(CONFIG_KUNIT_TEST) +=kunit-test.o
> +obj-$(CONFIG_KUNIT_STRING_STREAM_TEST) += string-stream-test.o
>
>  # string-stream-test compiles built-in only.
>  ifeq ($(CONFIG_KUNIT_TEST),y)
> -obj-$(CONFIG_KUNIT_TEST) +=string-stream-test.o
>  obj-$(CONFIG_KUNIT_TEST) +=assert_test.o
>  endif
>
> diff --git a/lib/kunit/string-stream-test.c b/lib/kunit/string-stream-test.c
> index 7511442ea98f..d03cac934e04 100644
> --- a/lib/kunit/string-stream-test.c
> +++ b/lib/kunit/string-stream-test.c
> @@ -534,3 +534,5 @@ static struct kunit_suite string_stream_test_suite = {
> .init = string_stream_test_init,
>  };
>  kunit_test_suites(&string_stream_test_suite);
> +MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
> +MODULE_LICENSE("GPL");
> --
> 2.34.1
>



Re: [PATCH v2 4/5] kunit: assert_test: Prepare to be merged into kunit-test.c

2024-06-21 Thread Rae Moar
On Tue, Jun 18, 2024 at 1:03 PM Ivan Orlov  wrote:
>
> Add 'kunit_assert_' prefix for 'is_literal' and 'is_str_literal'
> functions. This way we will be sure that we are not exporting ambiguous
> symbols into the KUnit namespace.
>
> Export these (and other) functions from assert into the KUnit namespace,
> so we could use them in the tests (and cover them as well).
>
> Signed-off-by: Ivan Orlov 

Hi!

This looks good to me. I am happy with the changes since v1.

Reviewed-by: Rae Moar 

Thanks for your work on this!
-Rae

> ---
> V1 -> V2:
> - Besides exporting the non-static functions from assert.c into the
> KUnit namespace, rename some of them as well (add kunit_assert_ prefix
> to make their names less ambiguous).
>
>  include/kunit/assert.h  |  4 ++--
>  lib/kunit/assert.c  | 19 +--
>  lib/kunit/assert_test.c | 40 
>  3 files changed, 35 insertions(+), 28 deletions(-)
>
> diff --git a/include/kunit/assert.h b/include/kunit/assert.h
> index 7e7490a74b13..3994acc520ae 100644
> --- a/include/kunit/assert.h
> +++ b/include/kunit/assert.h
> @@ -221,8 +221,8 @@ void kunit_mem_assert_format(const struct kunit_assert 
> *assert,
>  #if IS_ENABLED(CONFIG_KUNIT)
>  void kunit_assert_print_msg(const struct va_format *message,
> struct string_stream *stream);
> -bool is_literal(const char *text, long long value);
> -bool is_str_literal(const char *text, const char *value);
> +bool kunit_assert_is_literal(const char *text, long long value);
> +bool kunit_assert_is_str_literal(const char *text, const char *value);
>  void kunit_assert_hexdump(struct string_stream *stream,
>   const void *buf,
>   const void *compared_buf,
> diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c
> index 867aa5c4bccf..62b86bf5603e 100644
> --- a/lib/kunit/assert.c
> +++ b/lib/kunit/assert.c
> @@ -38,6 +38,7 @@ void kunit_assert_print_msg(const struct va_format *message,
> if (message->fmt)
> string_stream_add(stream, "\n%pV", message);
>  }
> +EXPORT_SYMBOL_IF_KUNIT(kunit_assert_print_msg);
>
>  void kunit_fail_assert_format(const struct kunit_assert *assert,
>   const struct va_format *message,
> @@ -91,7 +92,8 @@ void kunit_ptr_not_err_assert_format(const struct 
> kunit_assert *assert,
>  EXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format);
>
>  /* Checks if `text` is a literal representing `value`, e.g. "5" and 5 */
> -VISIBLE_IF_KUNIT bool is_literal(const char *text, long long value)
> +VISIBLE_IF_KUNIT
> +bool kunit_assert_is_literal(const char *text, long long value)
>  {
> char *buffer;
> int len;
> @@ -112,6 +114,7 @@ VISIBLE_IF_KUNIT bool is_literal(const char *text, long 
> long value)
>
> return ret;
>  }
> +EXPORT_SYMBOL_IF_KUNIT(kunit_assert_is_literal);
>
>  void kunit_binary_assert_format(const struct kunit_assert *assert,
> const struct va_format *message,
> @@ -127,12 +130,12 @@ void kunit_binary_assert_format(const struct 
> kunit_assert *assert,
>   binary_assert->text->left_text,
>   binary_assert->text->operation,
>   binary_assert->text->right_text);
> -   if (!is_literal(binary_assert->text->left_text, 
> binary_assert->left_value))
> +   if (!kunit_assert_is_literal(binary_assert->text->left_text, 
> binary_assert->left_value))
> string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld 
> (0x%llx)\n",
>   binary_assert->text->left_text,
>   binary_assert->left_value,
>   binary_assert->left_value);
> -   if (!is_literal(binary_assert->text->right_text, 
> binary_assert->right_value))
> +   if (!kunit_assert_is_literal(binary_assert->text->right_text, 
> binary_assert->right_value))
> string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld 
> (0x%llx)",
>   binary_assert->text->right_text,
>   binary_assert->right_value,
> @@ -168,7 +171,8 @@ EXPORT_SYMBOL_GPL(kunit_binary_ptr_assert_format);
>  /* Checks if KUNIT_EXPECT_STREQ() args were string literals.
>   * Note: `text` will have ""s where as `value` will not.
>   */
> -VISIBLE_IF_KUNIT bool is_str_literal(const char *text, const char *value)
> +VISIBLE_IF_KUNIT
> +bool kunit_assert_is_s

Re: [PATCH v2 5/5] kunit: Merge assertion test into kunit-test.c

2024-06-21 Thread Rae Moar
On Tue, Jun 18, 2024 at 1:03 PM Ivan Orlov  wrote:
>
> Since assert_test covers the part of the KUnit core (the assertion
> formatting functions), I believe it would be better to have it merged
> into kunit-test (as it is done for other tests for the KUnit core).
>
> Signed-off-by: Ivan Orlov 

Hello!

This looks good to me. I don't know if it was necessary to move the
assert tests but I definitely see the reasoning. Happy with this as it
is. There are a few checkpatch warnings I have mentioned below but I
think the use case makes it necessary.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
> V1 -> V2:
> - Update considering the changes in the previous patch (use
> kunit_assert_ prefixed functions)
>
>  lib/kunit/Makefile  |   5 -
>  lib/kunit/assert_test.c | 388 
>  lib/kunit/kunit-test.c  | 379 ++-
>  3 files changed, 378 insertions(+), 394 deletions(-)
>  delete mode 100644 lib/kunit/assert_test.c
>
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 478beb536dc9..18e506b897a6 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -21,9 +21,4 @@ obj-y +=  hooks.o
>  obj-$(CONFIG_KUNIT_TEST) +=kunit-test.o
>  obj-$(CONFIG_KUNIT_STRING_STREAM_TEST) += string-stream-test.o
>
> -# string-stream-test compiles built-in only.
> -ifeq ($(CONFIG_KUNIT_TEST),y)
> -obj-$(CONFIG_KUNIT_TEST) +=assert_test.o
> -endif
> -
>  obj-$(CONFIG_KUNIT_EXAMPLE_TEST) +=kunit-example-test.o
> diff --git a/lib/kunit/assert_test.c b/lib/kunit/assert_test.c
> deleted file mode 100644
> index 4999233180d6..
> --- a/lib/kunit/assert_test.c
> +++ /dev/null
> @@ -1,388 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-or-later
> -/*
> - * KUnit test for the assertion formatting functions.
> - * Author: Ivan Orlov 
> - */
> -#include 
> -#include "string-stream.h"
> -
> -#define TEST_PTR_EXPECTED_BUF_SIZE 32
> -#define HEXDUMP_TEST_BUF_LEN 5
> -#define ASSERT_TEST_EXPECT_CONTAIN(test, str, substr) 
> KUNIT_EXPECT_TRUE(test, strstr(str, substr))
> -#define ASSERT_TEST_EXPECT_NCONTAIN(test, str, substr) 
> KUNIT_EXPECT_FALSE(test, strstr(str, substr))
> -
> -static void kunit_test_assert_is_literal(struct kunit *test)
> -{
> -   KUNIT_EXPECT_TRUE(test, kunit_assert_is_literal("5", 5));
> -   KUNIT_EXPECT_TRUE(test, kunit_assert_is_literal("0", 0));
> -   KUNIT_EXPECT_TRUE(test, kunit_assert_is_literal("1234567890", 
> 1234567890));
> -   KUNIT_EXPECT_TRUE(test, kunit_assert_is_literal("-1234567890", 
> -1234567890));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_literal("05", 5));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_literal("", 0));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_literal("-0", 0));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_literal("12#45", 1245));
> -}
> -
> -static void kunit_test_assert_is_str_literal(struct kunit *test)
> -{
> -   KUNIT_EXPECT_TRUE(test, kunit_assert_is_str_literal("\"Hello, 
> World!\"", "Hello, World!"));
> -   KUNIT_EXPECT_TRUE(test, kunit_assert_is_str_literal("\"\"", ""));
> -   KUNIT_EXPECT_TRUE(test, kunit_assert_is_str_literal("\"\"\"", "\""));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_str_literal("", ""));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_str_literal("\"", "\""));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_str_literal("\"Abacaba", 
> "Abacaba"));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_str_literal("Abacaba\"", 
> "Abacaba"));
> -   KUNIT_EXPECT_FALSE(test, kunit_assert_is_str_literal("\"Abacaba\"", 
> "\"Abacaba\""));
> -}
> -
> -KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
> -
> -/* this function is used to get a "char *" string from the string stream and 
> defer its cleanup  */
> -static char *get_str_from_stream(struct kunit *test, struct string_stream 
> *stream)
> -{
> -   char *str = string_stream_get_string(stream);
> -
> -   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, str);
> -   kunit_add_action(test, kfree_wrapper, (void *)str);
> -
> -   return str;
> -}
> -
> -static void kunit_test_assert_prologue(struct kunit *test)
> -{
> -   struct string_stream *stream;
> -   char *str;
> -   const struct kunit_loc location = {
&

Re: [RFC] ktap_v2: KTAP specification transition method

2024-07-02 Thread Rae Moar
Hello everyone,

It has been a few months since there has been activity regarding the
second version of KTAP. I wanted to bring this topic back up to the
surface.

Currently, Frank has compiled a list of KTAPv2 patches here at this
link: https://elinux.org/Test_Results_Format_Notes#KTAP_version_2

I am interested in starting the process of accepting these patches as
changes to the KTAP documentation as KTAPv2.

First, a decision that needs to be made is which branch should be used
to accept these changes. Frank has a git repository for KTAPv2.
However, it is my understanding he has retired. As a reviewer of
KUnit, I am happy to take the patches in through the KUnit branch.
Would this work for everyone?

Second, we need to finalize the changes. A current list of proposed
KTAPv2 patches is as follows:

[PATCH v3 0/2] begin KTAP spec v2 process
[PATCH v3 1/2] ktap_v2: change version to 2-rc in KTAP specification
[PATCH v3 2/2] ktap_v2: change "version 1" to "version 2" in examples
[KTAP V2 PATCH] ktap_v2: add skip test result
[KTAP V2 PATCH v4] ktap_v2: add test metadata

Note the patch on adding a skip test result has not yet been reviewed.
So please take a look at this change if interested.

As a rule, for any feature of KTAPv1 that is replaced in KTAPv2, it
will stay in the documentation as allowed but deprecated to allow a
smooth transition.

If this process sounds good to people, I will try to get discussions
going on current patches and ask for reviews. My goal is by the end of
the summer, I can apply the approved patches and send them through a
chosen branch (potentially KUnit, as discussed above).

Let me know what you think. Thanks!
-Rae


On Sun, Mar 26, 2023 at 7:25 PM Frank Rowand  wrote:
>
> In the middle of the thread about a patch to add the skip test result,
> I suggested documenting the process of deprecating the KTAP v1 Specification
> method of marking a skipped test:
>
>   
> https://lore.kernel.org/all/490271eb-1429-2217-6e38-837c6e5e3...@gmail.com/T/#u
>
> In a reply to that email I suggested that we ought to have a process to 
> transition
> the KTAP Specification from v1 to v2, and possibly v3 and future.
>
> This email is meant to be the root of that discussion.
>
> My initial thinking is that there are at least three different types of 
> project
> and/or community that may have different needs in this area.
>
> Type 1 - project controls both the test output generation and the test output
> parsing tool.  Both generation and parsing code are in the same repository
> and/or synchronized versions are distributed together.
>
> Devicetree unittests are an example of Type 1.  I plan to maintain changes
> of test output to KTAP v2 format in coordination with updating the parser
> to process KTAP v2 data.
>
> Type 2 - project controls both the test output generation and the test output
> parsing tool.  The test output generation and a parser modifications may be
> controlled by the project BUT there are one or more external testing projects
> that (1) may have their own parsers, and (2) may have a single framework that
> tests multiple versions of the tests.
>
> I think that kselftest and kunit tests are probably examples of Type 2.  I 
> also
> think that DT unittests will become a Type 2 project as a result of converting
> to KTAP v2 data.
>
> Type 3 - project may create and maintain some tests, but is primarily a 
> consumer
> of tests created by other projects.  Type 3 projects typically have a single
> framework that is able to execute and process multiple versions of the tests.
>
> The Fuego test project is an example of Type 3.
>
> Maybe adding all of this complexity of different Types in my initial thinking
> was silly -- maybe everything in this topic is governed by the more complex
> Type 3.
>
> My thinking was that the three different Types of project would be impacted
> in different ways by transition plans.  Type 3 would be the most impacted,
> so I wanted to be sure that any transition plan especially considered their
> needs.
>
> There is an important aspect of the KTAP format that might ease the transition
> from one version to another: All KTAP formatted results begin with a "version
> line", so as soon as a parser has processed the first line of a test, it can
> apply the appropriate KTAP Specification version to all subsequent lines of
> test output.  A parser implementation could choose to process all versions,
> could choose to invoke a version specific parser, or some other approach
> all together.
>
> In the "add skip test results" thread, I suggested deprecating the v1
> method of marking a skipped test in v2, with a scheduled removal of
> the v1 method in v3.  But since the KTAP format version is available
> in the very first line of test output, is it necessary to do a slow
> deprecation and removal over two versions?
>
> One argument to doing a two version deprecation/removal process is that
> a parser that is one version older the the test output _might_ be able

[PATCH] kunit: add test duration attribute

2024-07-16 Thread Rae Moar
Add a new test duration attribute to print the duration of a test run.

Example:
 KTAP version 1
# Subtest: memcpy
# module: memcpy_kunit
1..4
# memcpy_large_test.speed: slow
# memcpy_large_test.duration: 1.134787584s
ok 1 memcpy_large_test
...

This attribute is printed for each test (excluding parameterized tests).

Add documentation for this new attribute to KUnit docs.

In order to save the timespec64 object, add the ability to save a memory
allocated object to the attributes framework.

Signed-off-by: Rae Moar 
---
 .../dev-tools/kunit/running_tips.rst  |  7 +++
 include/kunit/attributes.h|  5 ++
 include/kunit/test.h  |  1 +
 lib/kunit/attributes.c| 61 ++-
 lib/kunit/test.c  | 25 ++--
 5 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/Documentation/dev-tools/kunit/running_tips.rst 
b/Documentation/dev-tools/kunit/running_tips.rst
index bd689db6fdd2..a528d92e5d8f 100644
--- a/Documentation/dev-tools/kunit/running_tips.rst
+++ b/Documentation/dev-tools/kunit/running_tips.rst
@@ -446,3 +446,10 @@ This attribute indicates whether the test uses init data 
or functions.
 
 This attribute is automatically saved as a boolean and tests can also be
 filtered using this attribute.
+
+``duration``
+
+This attribute indicates the length of time in seconds of the test execution.
+
+This attribute is automatically saved as a timespec64 and printed for each test
+(excluding parameterized tests).
diff --git a/include/kunit/attributes.h b/include/kunit/attributes.h
index bc76a0b786d2..89ca54ef380d 100644
--- a/include/kunit/attributes.h
+++ b/include/kunit/attributes.h
@@ -18,6 +18,11 @@ struct kunit_attr_filter {
char *input;
 };
 
+/*
+ * Frees all of a test's allocated attributes.
+ */
+void kunit_free_attr(void *test_or_suite, bool is_test);
+
 /*
  * Returns the name of the filter's attribute.
  */
diff --git a/include/kunit/test.h b/include/kunit/test.h
index ec61cad6b71d..dca78d9bd3f6 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -82,6 +82,7 @@ enum kunit_speed {
 /* Holds attributes for each test case and suite */
 struct kunit_attributes {
enum kunit_speed speed;
+   struct timespec64 *duration;
 };
 
 /**
diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index 2cf04cc09372..b9fd6c686d65 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -40,6 +40,7 @@ struct kunit_attr {
int (*filter)(void *attr, const char *input, int *err);
void *attr_default;
enum print_ops print;
+   bool to_free;
 };
 
 /* String Lists for enum Attributes */
@@ -79,8 +80,29 @@ static const char *attr_string_to_string(void *attr, bool 
*to_free)
return (char *) attr;
 }
 
+static const char *attr_duration_to_string(void *attr, bool *to_free)
+{
+   int string_max_len = 20;
+   char *str = kmalloc(string_max_len, GFP_KERNEL);
+   struct timespec64 *val = (struct timespec64 *)attr;
+
+   *to_free = true;
+
+   /* Check if duration will overflow string */
+   if (val->tv_sec >= 100)
+   str = "Greater than or equal to 100s";
+   else
+   sprintf(str, "%lld.%09lds", val->tv_sec, val->tv_nsec);
+   return str;
+}
+
 /* Filter Methods */
 
+static int attr_default_filter(void *attr, const char *input, int *err)
+{
+   return false;
+}
+
 static const char op_list[] = "<>!=";
 
 /*
@@ -246,8 +268,20 @@ static void *attr_is_init_get(void *test_or_suite, bool 
is_test)
return ((void *) suite->is_init);
 }
 
+static void *attr_duration_get(void *test_or_suite, bool is_test)
+{
+   struct kunit_case *test = is_test ? test_or_suite : NULL;
+
+   if (test && !test->generate_params)
+   return ((void *) test->attr.duration);
+   else
+   return ((void *) NULL);
+}
+
 /* List of all Test Attributes */
 
+static struct timespec64 duration_default = {0, 0};
+
 static struct kunit_attr kunit_attr_list[] = {
{
.name = "speed",
@@ -256,6 +290,7 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_speed_filter,
.attr_default = (void *)KUNIT_SPEED_NORMAL,
.print = PRINT_ALWAYS,
+   .to_free = false,
},
{
.name = "module",
@@ -264,6 +299,7 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_string_filter,
.attr_default = (void *)"",
.print = PRINT_SUITE,
+   .to_free = false,
},
{
.name = "is_init",
@@ -272,10 +308,33 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_bool_filter,
  

[PATCH v2] kunit: add test duration attribute

2024-07-31 Thread Rae Moar
Add a new test duration attribute to print the duration of a test run.

Example:
 KTAP version 1
# Subtest: memcpy
# module: memcpy_kunit
1..4
# memcpy_large_test.speed: slow
# memcpy_large_test.duration: 1.134787584s
ok 1 memcpy_large_test
...

This attribute is printed for each test (excluding parameterized tests).

Add documentation for this new attribute to KUnit docs.

In order to save the timespec64 object, add the ability to save a memory
allocated object to the attributes framework.

Signed-off-by: Rae Moar 
---
Changes v1->v2:
- Change sprintf to kasprintf

 .../dev-tools/kunit/running_tips.rst  |  7 +++
 include/kunit/attributes.h|  5 ++
 include/kunit/test.h  |  1 +
 lib/kunit/attributes.c| 54 ++-
 lib/kunit/test.c  | 25 +++--
 5 files changed, 86 insertions(+), 6 deletions(-)

diff --git a/Documentation/dev-tools/kunit/running_tips.rst 
b/Documentation/dev-tools/kunit/running_tips.rst
index bd689db6fdd2..a528d92e5d8f 100644
--- a/Documentation/dev-tools/kunit/running_tips.rst
+++ b/Documentation/dev-tools/kunit/running_tips.rst
@@ -446,3 +446,10 @@ This attribute indicates whether the test uses init data 
or functions.
 
 This attribute is automatically saved as a boolean and tests can also be
 filtered using this attribute.
+
+``duration``
+
+This attribute indicates the length of time in seconds of the test execution.
+
+This attribute is automatically saved as a timespec64 and printed for each test
+(excluding parameterized tests).
diff --git a/include/kunit/attributes.h b/include/kunit/attributes.h
index bc76a0b786d2..89ca54ef380d 100644
--- a/include/kunit/attributes.h
+++ b/include/kunit/attributes.h
@@ -18,6 +18,11 @@ struct kunit_attr_filter {
char *input;
 };
 
+/*
+ * Frees all of a test's allocated attributes.
+ */
+void kunit_free_attr(void *test_or_suite, bool is_test);
+
 /*
  * Returns the name of the filter's attribute.
  */
diff --git a/include/kunit/test.h b/include/kunit/test.h
index ec61cad6b71d..dca78d9bd3f6 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -82,6 +82,7 @@ enum kunit_speed {
 /* Holds attributes for each test case and suite */
 struct kunit_attributes {
enum kunit_speed speed;
+   struct timespec64 *duration;
 };
 
 /**
diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index 2cf04cc09372..fd01d54e52d7 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -40,6 +40,7 @@ struct kunit_attr {
int (*filter)(void *attr, const char *input, int *err);
void *attr_default;
enum print_ops print;
+   bool to_free;
 };
 
 /* String Lists for enum Attributes */
@@ -79,8 +80,22 @@ static const char *attr_string_to_string(void *attr, bool 
*to_free)
return (char *) attr;
 }
 
+static const char *attr_duration_to_string(void *attr, bool *to_free)
+{
+   struct timespec64 *val = (struct timespec64 *)attr;
+   char *str = kasprintf(GFP_KERNEL, "%lld.%09lds", val->tv_sec, 
val->tv_nsec);
+
+   *to_free = true;
+   return str;
+}
+
 /* Filter Methods */
 
+static int attr_default_filter(void *attr, const char *input, int *err)
+{
+   return false;
+}
+
 static const char op_list[] = "<>!=";
 
 /*
@@ -246,8 +261,20 @@ static void *attr_is_init_get(void *test_or_suite, bool 
is_test)
return ((void *) suite->is_init);
 }
 
+static void *attr_duration_get(void *test_or_suite, bool is_test)
+{
+   struct kunit_case *test = is_test ? test_or_suite : NULL;
+
+   if (test && !test->generate_params)
+   return ((void *) test->attr.duration);
+   else
+   return ((void *) NULL);
+}
+
 /* List of all Test Attributes */
 
+static struct timespec64 duration_default = {0, 0};
+
 static struct kunit_attr kunit_attr_list[] = {
{
.name = "speed",
@@ -256,6 +283,7 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_speed_filter,
.attr_default = (void *)KUNIT_SPEED_NORMAL,
.print = PRINT_ALWAYS,
+   .to_free = false,
},
{
.name = "module",
@@ -264,6 +292,7 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_string_filter,
.attr_default = (void *)"",
.print = PRINT_SUITE,
+   .to_free = false,
},
{
.name = "is_init",
@@ -272,10 +301,33 @@ static struct kunit_attr kunit_attr_list[] = {
.filter = attr_bool_filter,
.attr_default = (void *)false,
.print = PRINT_SUITE,
+   .to_free = false,
+   },
+   {
+   .name = "duration",
+   .get_attr = attr_d

Re: [PATCH] kunit: Device wrappers should also manage driver name

2024-08-02 Thread Rae Moar
On Wed, Jul 31, 2024 at 3:02 AM David Gow  wrote:
>
> kunit_driver_create() accepts a name for the driver, but does not copy
> it, so if that name is either on the stack, or otherwise freed, we end
> up with a use-after-free when the driver is cleaned up.
>
> Instead, strdup() the name, and manage it as another KUnit allocation.
> As there was no existing kunit_kstrdup(), we add one. Further, add a
> kunit_ variant of strdup_const() and kfree_const(), so we don't need to
> allocate and manage the string in the majority of cases where it's a
> constant.
>
> This fixes a KASAN splat with overflow.overflow_allocation_test, when
> built as a module.
>
> Fixes: d03c720e03bd ("kunit: Add APIs for managing devices")
> Reported-by: Nico Pache 
> Closes: https://groups.google.com/g/kunit-dev/c/81V9b9QYON0
> Signed-off-by: David Gow 
> Reviewed-by: Kees Cook 
> ---
>
> There's some more serious changes since the RFC I sent, so please take a
> closer look.
>
> Thanks,
> -- David
>

Hello!

These changes look good to me. Fun patch to review! Only comment is
that we could potentially add tests for these functions in a future
patch.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> Changes since RFC:
> https://groups.google.com/g/kunit-dev/c/81V9b9QYON0/m/PFKNKDKJ
> - Add and use the kunit_kstrdup_const() and kunit_free_const()
>   functions.
> - Fix a typo in the doc comments.
>
>
> ---
>  include/kunit/test.h | 58 
>  lib/kunit/device.c   |  7 --
>  2 files changed, 63 insertions(+), 2 deletions(-)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index e2a1f0928e8b..da9e84de14c0 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -28,6 +28,7 @@
>  #include 
>
>  #include 
> +#include 
>
>  /* Static key: true if any KUnit tests are currently running */
>  DECLARE_STATIC_KEY_FALSE(kunit_running);
> @@ -480,6 +481,63 @@ static inline void *kunit_kcalloc(struct kunit *test, 
> size_t n, size_t size, gfp
> return kunit_kmalloc_array(test, n, size, gfp | __GFP_ZERO);
>  }
>
> +
> +/**
> + * kunit_kfree_const() - conditionally free test managed memory
> + * @x: pointer to the memory
> + *
> + * Calls kunit_kfree() only if @x is not in .rodata section.
> + * See kunit_kstrdup_const() for more information.
> + */
> +static inline void kunit_kfree_const(struct kunit *test, const void *x)
> +{
> +   if (!is_kernel_rodata((unsigned long)x))
> +   kunit_kfree(test, x);
> +}
> +
> +/**
> + * kunit_kstrdup() - Duplicates a string into a test managed allocation.
> + *
> + * @test: The test context object.
> + * @str: The NULL-terminated string to duplicate.
> + * @gfp: flags passed to underlying kmalloc().
> + *
> + * See kstrdup() and kunit_kmalloc_array() for more information.
> + */
> +static inline char *kunit_kstrdup(struct kunit *test, const char *str, gfp_t 
> gfp)
> +{
> +   size_t len;
> +   char *buf;
> +
> +   if (!str)
> +   return NULL;
> +
> +   len = strlen(str) + 1;
> +   buf = kunit_kmalloc(test, len, gfp);
> +   if (buf)
> +   memcpy(buf, str, len);
> +   return buf;
> +}
> +
> +/**
> + * kunit_kstrdup_const() - Conditionally duplicates a string into a test 
> managed allocation.
> + *
> + * @test: The test context object.
> + * @str: The NULL-terminated string to duplicate.
> + * @gfp: flags passed to underlying kmalloc().
> + *
> + * Calls kunit_kstrdup() only if @str is not in the rodata section. Must be 
> freed with
> + * kunit_free_const() -- not kunit_free().
> + * See kstrdup_const() and kunit_kmalloc_array() for more information.
> + */
> +static inline const char *kunit_kstrdup_const(struct kunit *test, const char 
> *str, gfp_t gfp)
> +{
> +   if (is_kernel_rodata((unsigned long)str))
> +   return str;
> +
> +   return kunit_kstrdup(test, str, gfp);
> +}
> +
>  /**
>   * kunit_vm_mmap() - Allocate KUnit-tracked vm_mmap() area
>   * @test: The test context object.
> diff --git a/lib/kunit/device.c b/lib/kunit/device.c
> index 25c81ed465fb..520c1fccee8a 100644
> --- a/lib/kunit/device.c
> +++ b/lib/kunit/device.c
> @@ -89,7 +89,7 @@ struct device_driver *kunit_driver_create(struct kunit 
> *test, const char *name)
> if (!driver)
> return ERR_PTR(err);
>
> -   driver->name = name;
> +   driver->name = kunit_kstrdup_const(test, name, GFP_KERNEL);
> driver->bus = &kunit_bus_type;
> driver->owner = THIS_MODULE;
>
> @@ -192,8 +192,11 @@ void kunit_

Re: [PATCH] kunit: Fix race condition in try-catch completion

2024-04-12 Thread Rae Moar
On Thu, Apr 11, 2024 at 10:59 PM David Gow  wrote:
>
> KUnit's try-catch infrastructure now uses vfork_done, which is always
> set to a valid completion when a kthread is created, but which is set to
> NULL once the thread terminates. This creates a race condition, where
> the kthread exits before we can wait on it.
>
> Keep a copy of vfork_done, which is taken before we wake_up_process()
> and so valid, and wait on that instead.
>
> Fixes: 4de2a8e4cca4 ("kunit: Handle test faults")
> Reported-by: Linux Kernel Functional Testing 
> Closes: 
> https://lore.kernel.org/lkml/20240410102710.35911-1-naresh.kamb...@linaro.org/
> Tested-by: Linux Kernel Functional Testing 
> Acked-by: Mickaël Salaün 
> Signed-off-by: David Gow 

Hello,

This fix looks good to me. I have tested it and besides the fortify
test error discussed in the previous patch series I am happy.

Thanks!
-Rae

Reviewed-by: Rae Moar 


> ---
>  lib/kunit/try-catch.c | 10 +++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c
> index fa687278ccc9..6bbe0025b079 100644
> --- a/lib/kunit/try-catch.c
> +++ b/lib/kunit/try-catch.c
> @@ -63,6 +63,7 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, 
> void *context)
>  {
> struct kunit *test = try_catch->test;
> struct task_struct *task_struct;
> +   struct completion *task_done;
> int exit_code, time_remaining;
>
> try_catch->context = context;
> @@ -75,13 +76,16 @@ void kunit_try_catch_run(struct kunit_try_catch 
> *try_catch, void *context)
> return;
> }
> get_task_struct(task_struct);
> -   wake_up_process(task_struct);
> /*
>  * As for a vfork(2), task_struct->vfork_done (pointing to the
>  * underlying kthread->exited) can be used to wait for the end of a
> -* kernel thread.
> +* kernel thread. It is set to NULL when the thread exits, so we
> +* keep a copy here.
>  */
> -   time_remaining = wait_for_completion_timeout(task_struct->vfork_done,
> +   task_done = task_struct->vfork_done;
> +   wake_up_process(task_struct);
> +
> +   time_remaining = wait_for_completion_timeout(task_done,
>  kunit_test_timeout());
> if (time_remaining == 0) {
> try_catch->try_result = -ETIMEDOUT;
> --
> 2.44.0.683.g7961c838ac-goog
>



Re: [PATCH] kunit: test: Move fault tests behind KUNIT_FAULT_TEST Kconfig option

2024-04-23 Thread Rae Moar
On Tue, Apr 23, 2024 at 5:08 AM David Gow  wrote:
>
> The NULL dereference tests in kunit_fault deliberately trigger a kernel
> BUG(), and therefore print the associated stack trace, even when the
> test passes. This is both annoying (as it bloats the test output), and
> can confuse some test harnesses, which assume any BUG() is a failure.
>
> Allow these tests to be specifically disabled (without disabling all
> of KUnit's other tests), by placing them behind the
> CONFIG_KUNIT_FAULT_TEST Kconfig option. This is enabled by default, but
> can be set to 'n' to disable the test. An empty 'kunit_fault' suite is
> left behind, which will automatically be marked 'skipped'.
>
> As the fault tests already were disabled under UML (as they weren't
> compatible with its fault handling), we can simply adapt those
> conditions, and add a dependency on !UML for our new option.
>
> Suggested-by: Guenter Roeck 
> Link: 
> https://lore.kernel.org/all/928249cc-e027-4f7f-b43f-502f99a1e...@roeck-us.net/
> Fixes: 82b0beff3497 ("kunit: Add tests for fault")
> Signed-off-by: David Gow 

Hello!

This looks good to me. Very useful!

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
>  lib/kunit/Kconfig  | 11 +++
>  lib/kunit/kunit-test.c |  8 
>  2 files changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig
> index 68a6daec0aef..34d7242d526d 100644
> --- a/lib/kunit/Kconfig
> +++ b/lib/kunit/Kconfig
> @@ -24,6 +24,17 @@ config KUNIT_DEBUGFS
>   test suite, which allow users to see results of the last test suite
>   run that occurred.
>
> +config KUNIT_FAULT_TEST
> +   bool "Enable KUnit tests which print BUG stacktraces"
> +   depends on KUNIT_TEST
> +   depends on !UML
> +   default y
> +   help
> + Enables fault handling tests for the KUnit framework. These tests 
> may
> + trigger a kernel BUG(), and the associated stack trace, even when 
> they
> + pass. If this conflicts with your test infrastrcture (or is 
> confusing
> + or annoying), they can be disabled by setting this to N.
> +
>  config KUNIT_TEST
> tristate "KUnit test for KUnit" if !KUNIT_ALL_TESTS
> default KUNIT_ALL_TESTS
> diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
> index 0fdca5fffaec..e3412e0ca399 100644
> --- a/lib/kunit/kunit-test.c
> +++ b/lib/kunit/kunit-test.c
> @@ -109,7 +109,7 @@ static struct kunit_suite kunit_try_catch_test_suite = {
> .test_cases = kunit_try_catch_test_cases,
>  };
>
> -#ifndef CONFIG_UML
> +#if IS_ENABLED(CONFIG_KUNIT_FAULT_TEST)
>
>  static void kunit_test_null_dereference(void *data)
>  {
> @@ -136,12 +136,12 @@ static void kunit_test_fault_null_dereference(struct 
> kunit *test)
> KUNIT_EXPECT_TRUE(test, ctx->function_called);
>  }
>
> -#endif /* !CONFIG_UML */
> +#endif /* CONFIG_KUNIT_FAULT_TEST */
>
>  static struct kunit_case kunit_fault_test_cases[] = {
> -#ifndef CONFIG_UML
> +#if IS_ENABLED(CONFIG_KUNIT_FAULT_TEST)
> KUNIT_CASE(kunit_test_fault_null_dereference),
> -#endif /* !CONFIG_UML */
> +#endif /* CONFIG_KUNIT_FAULT_TEST */
> {}
>  };
>
> --
> 2.44.0.769.g3c40516874-goog
>



Re: [PATCH] kunit: string-stream-test: use KUNIT_DEFINE_ACTION_WRAPPER

2024-04-23 Thread Rae Moar
On Tue, Apr 23, 2024 at 2:27 PM Ivan Orlov  wrote:
>
> Use KUNIT_DEFINE_ACTION_WRAPPER macro to define the 'kfree' and
> 'string_stream_destroy' wrappers for kunit_add_action.
>
> Signed-off-by: Ivan Orlov 

Hello!

This looks like a good use of the macro. Thanks!

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
>  lib/kunit/string-stream-test.c | 12 ++--
>  1 file changed, 2 insertions(+), 10 deletions(-)
>
> diff --git a/lib/kunit/string-stream-test.c b/lib/kunit/string-stream-test.c
> index 03fb511826f7..7511442ea98f 100644
> --- a/lib/kunit/string-stream-test.c
> +++ b/lib/kunit/string-stream-test.c
> @@ -22,18 +22,10 @@ struct string_stream_test_priv {
>  };
>
>  /* Avoids a cast warning if kfree() is passed direct to kunit_add_action(). 
> */
> -static void kfree_wrapper(void *p)
> -{
> -   kfree(p);
> -}
> +KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
>
>  /* Avoids a cast warning if string_stream_destroy() is passed direct to 
> kunit_add_action(). */
> -static void cleanup_raw_stream(void *p)
> -{
> -   struct string_stream *stream = p;
> -
> -   string_stream_destroy(stream);
> -}
> +KUNIT_DEFINE_ACTION_WRAPPER(cleanup_raw_stream, string_stream_destroy, 
> struct string_stream *);
>
>  static char *get_concatenated_string(struct kunit *test, struct 
> string_stream *stream)
>  {
> --
> 2.34.1
>



Re: [PATCH] kunit: Cover 'assert.c' with tests

2024-04-29 Thread Rae Moar
On Sat, Apr 27, 2024 at 6:04 PM Ivan Orlov  wrote:
>
> There are multiple assertion formatting functions in the `assert.c`
> file, which are not covered with tests yet. Implement the KUnit test
> for these functions.
>
> The test consists of 11 test cases for the following functions:
>
> 1) 'is_literal'
> 2) 'is_str_literal'
> 3) 'kunit_assert_prologue', test case for multiple assert types
> 4) 'kunit_assert_print_msg'
> 5) 'kunit_unary_assert_format'
> 6) 'kunit_ptr_not_err_assert_format'
> 7) 'kunit_binary_assert_format'
> 8) 'kunit_binary_ptr_assert_format'
> 9) 'kunit_binary_str_assert_format'
> 10) 'kunit_assert_hexdump'
> 11) 'kunit_mem_assert_format'
>
> The test aims at maximizing the branch coverage for the assertion
> formatting functions. As you can see, it covers some of the static
> helper functions as well, so we have to import the test source in the
> `assert.c` file in order to be able to call and validate them.
>
> Signed-off-by: Ivan Orlov 

Hello,

I'll give this a full review tomorrow. But with a quick glance and
test, this is looking good to me.

Tested-by: Rae Moar 

Thanks!
-Rae

> ---
>  lib/kunit/assert.c  |   4 +
>  lib/kunit/assert_test.c | 416 
>  2 files changed, 420 insertions(+)
>  create mode 100644 lib/kunit/assert_test.c
>
> diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c
> index dd1d633d0fe2..ab68c6daf546 100644
> --- a/lib/kunit/assert.c
> +++ b/lib/kunit/assert.c
> @@ -270,3 +270,7 @@ void kunit_mem_assert_format(const struct kunit_assert 
> *assert,
> }
>  }
>  EXPORT_SYMBOL_GPL(kunit_mem_assert_format);
> +
> +#if IS_ENABLED(CONFIG_KUNIT_TEST)
> +#include "assert_test.c"
> +#endif
> diff --git a/lib/kunit/assert_test.c b/lib/kunit/assert_test.c
> new file mode 100644
> index ..d54841740761
> --- /dev/null
> +++ b/lib/kunit/assert_test.c
> @@ -0,0 +1,416 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * KUnit test for the assertion formatting functions.
> + * Author: Ivan Orlov 
> + */
> +#include 
> +
> +#define TEST_PTR_EXPECTED_BUF_SIZE 128
> +
> +static void kunit_test_is_literal(struct kunit *test)
> +{
> +   KUNIT_EXPECT_TRUE(test, is_literal("5", 5));
> +   KUNIT_EXPECT_TRUE(test, is_literal("0", 0));
> +   KUNIT_EXPECT_TRUE(test, is_literal("1234567890", 1234567890));
> +   KUNIT_EXPECT_TRUE(test, is_literal("-1234567890", -1234567890));
> +   KUNIT_EXPECT_FALSE(test, is_literal("05", 5));
> +   KUNIT_EXPECT_FALSE(test, is_literal("", 0));
> +   KUNIT_EXPECT_FALSE(test, is_literal("-0", 0));
> +   KUNIT_EXPECT_FALSE(test, is_literal("12#45", 1245));
> +}
> +
> +static void kunit_test_is_str_literal(struct kunit *test)
> +{
> +   KUNIT_EXPECT_TRUE(test, is_str_literal("\"Hello, World!\"", "Hello, 
> World!"));
> +   KUNIT_EXPECT_TRUE(test, is_str_literal("\"\"", ""));
> +   KUNIT_EXPECT_TRUE(test, is_str_literal("\"\"\"", "\""));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("", ""));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("\"", "\""));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("\"Abacaba", "Abacaba"));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("Abacaba\"", "Abacaba"));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("\"Abacaba\"", 
> "\"Abacaba\""));
> +}
> +
> +KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
> +
> +/* this function is used to get a "char *" string from the string stream and 
> defer its cleanup  */
> +static char *get_str_from_stream(struct kunit *test, struct string_stream 
> *stream)
> +{
> +   char *str = string_stream_get_string(stream);
> +
> +   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, str);
> +   kunit_add_action(test, kfree_wrapper, (void *)str);
> +
> +   return str;
> +}
> +
> +static void kunit_test_assert_prologue(struct kunit *test)
> +{
> +   struct string_stream *stream;
> +   const struct kunit_loc location = {
> +   .file = "testfile.c",
> +   .line = 1337,
> +   };
> +
> +   stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +  

Re: [PATCH] kunit: Cover 'assert.c' with tests

2024-05-01 Thread Rae Moar
On Sat, Apr 27, 2024 at 6:04 PM Ivan Orlov  wrote:
>
> There are multiple assertion formatting functions in the `assert.c`
> file, which are not covered with tests yet. Implement the KUnit test
> for these functions.
>
> The test consists of 11 test cases for the following functions:
>
> 1) 'is_literal'
> 2) 'is_str_literal'
> 3) 'kunit_assert_prologue', test case for multiple assert types
> 4) 'kunit_assert_print_msg'
> 5) 'kunit_unary_assert_format'
> 6) 'kunit_ptr_not_err_assert_format'
> 7) 'kunit_binary_assert_format'
> 8) 'kunit_binary_ptr_assert_format'
> 9) 'kunit_binary_str_assert_format'
> 10) 'kunit_assert_hexdump'
> 11) 'kunit_mem_assert_format'
>
> The test aims at maximizing the branch coverage for the assertion
> formatting functions. As you can see, it covers some of the static
> helper functions as well, so we have to import the test source in the
> `assert.c` file in order to be able to call and validate them.
>
> Signed-off-by: Ivan Orlov 

Hello!

This is a great patch and addition of KUnit tests. Happy to see it.
Thank you very much!

I do have a few comments below. But none of them are deal breakers.

Thanks!
-Rae

> ---
>  lib/kunit/assert.c  |   4 +
>  lib/kunit/assert_test.c | 416 
>  2 files changed, 420 insertions(+)
>  create mode 100644 lib/kunit/assert_test.c
>
> diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c
> index dd1d633d0fe2..ab68c6daf546 100644
> --- a/lib/kunit/assert.c
> +++ b/lib/kunit/assert.c
> @@ -270,3 +270,7 @@ void kunit_mem_assert_format(const struct kunit_assert 
> *assert,
> }
>  }
>  EXPORT_SYMBOL_GPL(kunit_mem_assert_format);
> +
> +#if IS_ENABLED(CONFIG_KUNIT_TEST)
> +#include "assert_test.c"
> +#endif

I might consider using the macro VISIBLE_IF_KUNIT macro, found in
include/kunit/visibility.h, to make the static functions in assert.c
visible only if KUnit is enabled. To avoid having to add the include
here. What do you think?

> diff --git a/lib/kunit/assert_test.c b/lib/kunit/assert_test.c
> new file mode 100644
> index ..d54841740761
> --- /dev/null
> +++ b/lib/kunit/assert_test.c
> @@ -0,0 +1,416 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * KUnit test for the assertion formatting functions.
> + * Author: Ivan Orlov 
> + */
> +#include 
> +
> +#define TEST_PTR_EXPECTED_BUF_SIZE 128
> +
> +static void kunit_test_is_literal(struct kunit *test)
> +{
> +   KUNIT_EXPECT_TRUE(test, is_literal("5", 5));
> +   KUNIT_EXPECT_TRUE(test, is_literal("0", 0));
> +   KUNIT_EXPECT_TRUE(test, is_literal("1234567890", 1234567890));
> +   KUNIT_EXPECT_TRUE(test, is_literal("-1234567890", -1234567890));
> +   KUNIT_EXPECT_FALSE(test, is_literal("05", 5));
> +   KUNIT_EXPECT_FALSE(test, is_literal("", 0));
> +   KUNIT_EXPECT_FALSE(test, is_literal("-0", 0));
> +   KUNIT_EXPECT_FALSE(test, is_literal("12#45", 1245));
> +}
> +
> +static void kunit_test_is_str_literal(struct kunit *test)
> +{
> +   KUNIT_EXPECT_TRUE(test, is_str_literal("\"Hello, World!\"", "Hello, 
> World!"));
> +   KUNIT_EXPECT_TRUE(test, is_str_literal("\"\"", ""));
> +   KUNIT_EXPECT_TRUE(test, is_str_literal("\"\"\"", "\""));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("", ""));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("\"", "\""));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("\"Abacaba", "Abacaba"));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("Abacaba\"", "Abacaba"));
> +   KUNIT_EXPECT_FALSE(test, is_str_literal("\"Abacaba\"", 
> "\"Abacaba\""));
> +}
> +
> +KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
> +
> +/* this function is used to get a "char *" string from the string stream and 
> defer its cleanup  */
> +static char *get_str_from_stream(struct kunit *test, struct string_stream 
> *stream)
> +{
> +   char *str = string_stream_get_string(stream);
> +
> +   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, str);
> +   kunit_add_action(test, kfree_wrapper, (void *)str);
> +
> +   return str;
> +}
> +
> +static void kunit_test_assert_prologue(struct kunit *test)
> +{
> +   struct string_stream *stream;
> +   const struct kunit_loc location = {
> +   .file = "testfile.c",
> +   .line = 1337,
> +   };
> +
> +   stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +   /* Test an expectation fail prologue */
> +   kunit_assert_prologue(&location, KUNIT_EXPECTATION, stream);
> +   KUNIT_EXPECT_STREQ(test, get_str_from_stream(test, stream),
> +  "EXPECTATION FAILED at testfile.c:1337\n");
> +
> +   /* Test an assertion fail prologue */
> +   string_stream_clear(stream);
> +   kunit_assert_prologue(&location, KUNIT_ASSERTION, stream);
> +   KUNIT_EXPECT_STREQ(test, get_str_from_stream(test, stream),
> +  "ASSERTION FAILED at testfile.c:1337\n");

My 

Re: [PATCH v3] kunit: Cover 'assert.c' with tests

2024-05-13 Thread Rae Moar
On Thu, May 9, 2024 at 5:05 AM Ivan Orlov  wrote:
>
> There are multiple assertion formatting functions in the `assert.c`
> file, which are not covered with tests yet. Implement the KUnit test
> for these functions.
>
> The test consists of 11 test cases for the following functions:
>
> 1) 'is_literal'
> 2) 'is_str_literal'
> 3) 'kunit_assert_prologue', test case for multiple assert types
> 4) 'kunit_assert_print_msg'
> 5) 'kunit_unary_assert_format'
> 6) 'kunit_ptr_not_err_assert_format'
> 7) 'kunit_binary_assert_format'
> 8) 'kunit_binary_ptr_assert_format'
> 9) 'kunit_binary_str_assert_format'
> 10) 'kunit_assert_hexdump'
> 11) 'kunit_mem_assert_format'
>
> The test aims at maximizing the branch coverage for the assertion
> formatting functions.
>
> As you can see, it covers some of the static helper functions as
> well, so mark the static functions in `assert.c` as 'VISIBLE_IF_KUNIT'
> and conditionally export them with EXPORT_SYMBOL_IF_KUNIT. Add the
> corresponding definitions to `assert.h`.
>
> Build the assert test when CONFIG_KUNIT_TEST is enabled, similar to
> how it is done for the string stream test.

Hello!

This looks great to me! Thanks for all your work on this! There is
just one comment I have below. Once that is fixed up, I am happy to
add a reviewed-by.

Thanks!
-Rae

>
> Signed-off-by: Ivan Orlov 
> ---
> V1 -> V2:
> - Check the output from the string stream for containing the key parts
> instead of comparing the results with expected strings char by char, as
> it was suggested by Rae Moar . Define two macros to
> make it possible (ASSERT_TEST_EXPECT_CONTAIN and
> ASSERT_TEST_EXPECT_NCONTAIN).
> - Mark the static functions in `assert.c` as VISIBLE_IF_KUNIT and export
> them conditionally if kunit is enabled instead of including the
> `assert_test.c` file in the end of `assert.c`. This way we will decouple
> the test from the implementation (SUT).
> - Update the kunit_assert_hexdump test: now it checks for presense of
> the brackets '<>' around the non-matching bytes, instead of comparing
> the kunit_assert_hexdump output char by char.
> V2 -> V3:
> - Make test case array and test suite definitions static
> - Change the condition in `assert.h`: we should declare VISIBLE_IF_KUNIT
> functions in the header file when CONFIG_KUNIT is enabled, not
> CONFIG_KUNIT_TEST. Otherwise, if CONFIG_KUNIT_TEST is disabled,
> VISIBLE_IF_KUNIT functions in the `assert.c` are not static, and
> prototypes for them can't be found.
> - Add MODULE_LICENSE and MODULE_DESCRIPTION macros
>
>  include/kunit/assert.h  |  11 ++
>  lib/kunit/Makefile  |   1 +
>  lib/kunit/assert.c  |  24 ++-
>  lib/kunit/assert_test.c | 391 
>  4 files changed, 419 insertions(+), 8 deletions(-)
>  create mode 100644 lib/kunit/assert_test.c
>
> diff --git a/include/kunit/assert.h b/include/kunit/assert.h
> index 24c2b9fa61e8..7e7490a74b13 100644
> --- a/include/kunit/assert.h
> +++ b/include/kunit/assert.h
> @@ -218,4 +218,15 @@ void kunit_mem_assert_format(const struct kunit_assert 
> *assert,
>  const struct va_format *message,
>  struct string_stream *stream);
>
> +#if IS_ENABLED(CONFIG_KUNIT)
> +void kunit_assert_print_msg(const struct va_format *message,
> +   struct string_stream *stream);
> +bool is_literal(const char *text, long long value);
> +bool is_str_literal(const char *text, const char *value);
> +void kunit_assert_hexdump(struct string_stream *stream,
> + const void *buf,
> + const void *compared_buf,
> + const size_t len);
> +#endif
> +
>  #endif /*  _KUNIT_ASSERT_H */
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 309659a32a78..be7c9903936f 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -18,6 +18,7 @@ endif
>  obj-y +=   hooks.o
>
>  obj-$(CONFIG_KUNIT_TEST) +=kunit-test.o
> +obj-$(CONFIG_KUNIT_TEST) +=assert_test.o
>
>  # string-stream-test compiles built-in only.
>  ifeq ($(CONFIG_KUNIT_TEST),y)
> diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c
> index dd1d633d0fe2..382eb409d34b 100644
> --- a/lib/kunit/assert.c
> +++ b/lib/kunit/assert.c
> @@ -7,6 +7,7 @@
>   */
>  #include 
>  #include 
> +#include 
>
>  #include "string-stream.h"
>
> @@ -30,12 +31,14 @@ void kunit_assert_prologue(const struct kunit_loc *loc,
>  }
>  EXPORT_SYMBOL_GPL(kunit_assert_pro

Re: [PATCH v3] kunit: Cover 'assert.c' with tests

2024-05-14 Thread Rae Moar
On Tue, May 14, 2024 at 10:31 AM Ivan Orlov  wrote:
>
> On 5/14/24 01:17, Rae Moar wrote:
> > On Thu, May 9, 2024 at 5:05 AM Ivan Orlov  wrote:
> >>
> >> There are multiple assertion formatting functions in the `assert.c`
> >> file, which are not covered with tests yet. Implement the KUnit test
> >> for these functions.
> >>
> >> The test consists of 11 test cases for the following functions:
> >>
> >> 1) 'is_literal'
> >> 2) 'is_str_literal'
> >> 3) 'kunit_assert_prologue', test case for multiple assert types
> >> 4) 'kunit_assert_print_msg'
> >> 5) 'kunit_unary_assert_format'
> >> 6) 'kunit_ptr_not_err_assert_format'
> >> 7) 'kunit_binary_assert_format'
> >> 8) 'kunit_binary_ptr_assert_format'
> >> 9) 'kunit_binary_str_assert_format'
> >> 10) 'kunit_assert_hexdump'
> >> 11) 'kunit_mem_assert_format'
> >>
> >> The test aims at maximizing the branch coverage for the assertion
> >> formatting functions.
> >>
> >> As you can see, it covers some of the static helper functions as
> >> well, so mark the static functions in `assert.c` as 'VISIBLE_IF_KUNIT'
> >> and conditionally export them with EXPORT_SYMBOL_IF_KUNIT. Add the
> >> corresponding definitions to `assert.h`.
> >>
> >> Build the assert test when CONFIG_KUNIT_TEST is enabled, similar to
> >> how it is done for the string stream test.
> >
> > Hello!
> >
> > This looks great to me! Thanks for all your work on this! There is
> > just one comment I have below. Once that is fixed up, I am happy to
> > add a reviewed-by.
> >
> > Thanks!
> > -Rae
> >
> >>
> >> Signed-off-by: Ivan Orlov 
> >> ---
> >> V1 -> V2:
> >> - Check the output from the string stream for containing the key parts
> >> instead of comparing the results with expected strings char by char, as
> >> it was suggested by Rae Moar . Define two macros to
> >> make it possible (ASSERT_TEST_EXPECT_CONTAIN and
> >> ASSERT_TEST_EXPECT_NCONTAIN).
> >> - Mark the static functions in `assert.c` as VISIBLE_IF_KUNIT and export
> >> them conditionally if kunit is enabled instead of including the
> >> `assert_test.c` file in the end of `assert.c`. This way we will decouple
> >> the test from the implementation (SUT).
> >> - Update the kunit_assert_hexdump test: now it checks for presense of
> >> the brackets '<>' around the non-matching bytes, instead of comparing
> >> the kunit_assert_hexdump output char by char.
> >> V2 -> V3:
> >> - Make test case array and test suite definitions static
> >> - Change the condition in `assert.h`: we should declare VISIBLE_IF_KUNIT
> >> functions in the header file when CONFIG_KUNIT is enabled, not
> >> CONFIG_KUNIT_TEST. Otherwise, if CONFIG_KUNIT_TEST is disabled,
> >> VISIBLE_IF_KUNIT functions in the `assert.c` are not static, and
> >> prototypes for them can't be found.
> >> - Add MODULE_LICENSE and MODULE_DESCRIPTION macros
> >>
> >>   include/kunit/assert.h  |  11 ++
> >>   lib/kunit/Makefile  |   1 +
> >>   lib/kunit/assert.c  |  24 ++-
> >>   lib/kunit/assert_test.c | 391 
> >>   4 files changed, 419 insertions(+), 8 deletions(-)
> >>   create mode 100644 lib/kunit/assert_test.c
> >>
> >> diff --git a/include/kunit/assert.h b/include/kunit/assert.h
> >> index 24c2b9fa61e8..7e7490a74b13 100644
> >> --- a/include/kunit/assert.h
> >> +++ b/include/kunit/assert.h
> >> @@ -218,4 +218,15 @@ void kunit_mem_assert_format(const struct 
> >> kunit_assert *assert,
> >>   const struct va_format *message,
> >>   struct string_stream *stream);
> >>
> >> +#if IS_ENABLED(CONFIG_KUNIT)
> >> +void kunit_assert_print_msg(const struct va_format *message,
> >> +   struct string_stream *stream);
> >> +bool is_literal(const char *text, long long value);
> >> +bool is_str_literal(const char *text, const char *value);
> >> +void kunit_assert_hexdump(struct string_stream *stream,
> >> + const void *buf,
> >> + const void *compared_buf,
> >> + const size_t len);
> >> +

Re: [PATCH v4] kunit: Cover 'assert.c' with tests

2024-05-16 Thread Rae Moar
On Wed, May 15, 2024 at 10:20 AM Ivan Orlov  wrote:
>
> There are multiple assertion formatting functions in the `assert.c`
> file, which are not covered with tests yet. Implement the KUnit test
> for these functions.
>
> The test consists of 11 test cases for the following functions:
>
> 1) 'is_literal'
> 2) 'is_str_literal'
> 3) 'kunit_assert_prologue', test case for multiple assert types
> 4) 'kunit_assert_print_msg'
> 5) 'kunit_unary_assert_format'
> 6) 'kunit_ptr_not_err_assert_format'
> 7) 'kunit_binary_assert_format'
> 8) 'kunit_binary_ptr_assert_format'
> 9) 'kunit_binary_str_assert_format'
> 10) 'kunit_assert_hexdump'
> 11) 'kunit_mem_assert_format'
>
> The test aims at maximizing the branch coverage for the assertion
> formatting functions.
>
> As you can see, it covers some of the static helper functions as
> well, so mark the static functions in `assert.c` as 'VISIBLE_IF_KUNIT'
> and conditionally export them with EXPORT_SYMBOL_IF_KUNIT. Add the
> corresponding definitions to `assert.h`.
>
> Build the assert test when CONFIG_KUNIT_TEST is enabled, similar to
> how it is done for the string stream test.
>
> Signed-off-by: Ivan Orlov 
> ---
> V1 -> V2:
> - Check the output from the string stream for containing the key parts
> instead of comparing the results with expected strings char by char, as
> it was suggested by Rae Moar . Define two macros to
> make it possible (ASSERT_TEST_EXPECT_CONTAIN and
> ASSERT_TEST_EXPECT_NCONTAIN).
> - Mark the static functions in `assert.c` as VISIBLE_IF_KUNIT and export
> them conditionally if kunit is enabled instead of including the
> `assert_test.c` file in the end of `assert.c`. This way we will decouple
> the test from the implementation (SUT).
> - Update the kunit_assert_hexdump test: now it checks for presense of
> the brackets '<>' around the non-matching bytes, instead of comparing
> the kunit_assert_hexdump output char by char.
> V2 -> V3:
> - Make test case array and test suite definitions static
> - Change the condition in `assert.h`: we should declare VISIBLE_IF_KUNIT
> functions in the header file when CONFIG_KUNIT is enabled, not
> CONFIG_KUNIT_TEST. Otherwise, if CONFIG_KUNIT_TEST is disabled,
> VISIBLE_IF_KUNIT functions in the `assert.c` are not static, and
> prototypes for them can't be found.
> - Add MODULE_LICENSE and MODULE_DESCRIPTION macros
> V3 -> V4:
> - Compile the assertion test only when CONFIG_KUNIT_TEST is set to 'y',
> as it is done for the string-stream test. It is necessary since
> functions from the string-stream are not exported into the public
> namespace, and therefore they are not accessible when linking and
> loading the test module.

Hi Ivan!

This looks great! Just one last thing, since this test is no longer
loadable as a module, could you remove the exporting of new symbols
and adding of the module license. Those can be part of the next patch,
where we convert these tests to modules.

Thanks!
-Rae

>
>  include/kunit/assert.h  |  11 ++
>  lib/kunit/Makefile  |   1 +
>  lib/kunit/assert.c  |  24 ++-
>  lib/kunit/assert_test.c | 391 
>  4 files changed, 419 insertions(+), 8 deletions(-)
>  create mode 100644 lib/kunit/assert_test.c
>
> diff --git a/include/kunit/assert.h b/include/kunit/assert.h
> index 24c2b9fa61e8..7e7490a74b13 100644
> --- a/include/kunit/assert.h
> +++ b/include/kunit/assert.h
> @@ -218,4 +218,15 @@ void kunit_mem_assert_format(const struct kunit_assert 
> *assert,
>  const struct va_format *message,
>  struct string_stream *stream);
>
> +#if IS_ENABLED(CONFIG_KUNIT)
> +void kunit_assert_print_msg(const struct va_format *message,
> +   struct string_stream *stream);
> +bool is_literal(const char *text, long long value);
> +bool is_str_literal(const char *text, const char *value);
> +void kunit_assert_hexdump(struct string_stream *stream,
> + const void *buf,
> + const void *compared_buf,
> + const size_t len);
> +#endif
> +
>  #endif /*  _KUNIT_ASSERT_H */
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 309659a32a78..900e6447c8e8 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_KUNIT_TEST) +=   kunit-test.o
>  # string-stream-test compiles built-in only.
>  ifeq ($(CONFIG_KUNIT_TEST),y)
>  obj-$(CONFIG_KUNIT_TEST) +=string-stream-test.o
> +obj-$(CONFIG_KUNIT_TEST) += 

Re: [PATCH v5] kunit: Cover 'assert.c' with tests

2024-05-20 Thread Rae Moar
On Thu, May 16, 2024 at 11:17 PM Ivan Orlov  wrote:
>
> There are multiple assertion formatting functions in the `assert.c`
> file, which are not covered with tests yet. Implement the KUnit test
> for these functions.
>
> The test consists of 11 test cases for the following functions:
>
> 1) 'is_literal'
> 2) 'is_str_literal'
> 3) 'kunit_assert_prologue', test case for multiple assert types
> 4) 'kunit_assert_print_msg'
> 5) 'kunit_unary_assert_format'
> 6) 'kunit_ptr_not_err_assert_format'
> 7) 'kunit_binary_assert_format'
> 8) 'kunit_binary_ptr_assert_format'
> 9) 'kunit_binary_str_assert_format'
> 10) 'kunit_assert_hexdump'
> 11) 'kunit_mem_assert_format'
>
> The test aims at maximizing the branch coverage for the assertion
> formatting functions.
>
> As you can see, it covers some of the static helper functions as
> well, so mark the static functions in `assert.c` as 'VISIBLE_IF_KUNIT'
> and conditionally export them with EXPORT_SYMBOL_IF_KUNIT. Add the
> corresponding definitions to `assert.h`.
>
> Build the assert test when CONFIG_KUNIT_TEST is enabled, similar to
> how it is done for the string stream test.
>
> Signed-off-by: Ivan Orlov 

Hi! This looks great to me!

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
> V1 -> V2:
> - Check the output from the string stream for containing the key parts
> instead of comparing the results with expected strings char by char, as
> it was suggested by Rae Moar . Define two macros to
> make it possible (ASSERT_TEST_EXPECT_CONTAIN and
> ASSERT_TEST_EXPECT_NCONTAIN).
> - Mark the static functions in `assert.c` as VISIBLE_IF_KUNIT and export
> them conditionally if kunit is enabled instead of including the
> `assert_test.c` file in the end of `assert.c`. This way we will decouple
> the test from the implementation (SUT).
> - Update the kunit_assert_hexdump test: now it checks for presense of
> the brackets '<>' around the non-matching bytes, instead of comparing
> the kunit_assert_hexdump output char by char.
> V2 -> V3:
> - Make test case array and test suite definitions static
> - Change the condition in `assert.h`: we should declare VISIBLE_IF_KUNIT
> functions in the header file when CONFIG_KUNIT is enabled, not
> CONFIG_KUNIT_TEST. Otherwise, if CONFIG_KUNIT_TEST is disabled,
> VISIBLE_IF_KUNIT functions in the `assert.c` are not static, and
> prototypes for them can't be found.
> - Add MODULE_LICENSE and MODULE_DESCRIPTION macros
> V3 -> V4:
> - Compile the assertion test only when CONFIG_KUNIT_TEST is set to 'y',
> as it is done for the string-stream test. It is necessary since
> functions from the string-stream are not exported into the public
> namespace, and therefore they are not accessible when linking and
> loading the test module.
> V4 -> V5:
> - Remove EXPORT_SYMBOL_IF_KUNIT from the assert.c and all of the
> module-related macros from the test source since the test can't
> be used as a loadable module for now (see V3 -> V4).
>
>  include/kunit/assert.h  |  11 ++
>  lib/kunit/Makefile  |   1 +
>  lib/kunit/assert.c  |  19 +-
>  lib/kunit/assert_test.c | 388 
>  4 files changed, 411 insertions(+), 8 deletions(-)
>  create mode 100644 lib/kunit/assert_test.c
>
> diff --git a/include/kunit/assert.h b/include/kunit/assert.h
> index 24c2b9fa61e8..7e7490a74b13 100644
> --- a/include/kunit/assert.h
> +++ b/include/kunit/assert.h
> @@ -218,4 +218,15 @@ void kunit_mem_assert_format(const struct kunit_assert 
> *assert,
>  const struct va_format *message,
>  struct string_stream *stream);
>
> +#if IS_ENABLED(CONFIG_KUNIT)
> +void kunit_assert_print_msg(const struct va_format *message,
> +   struct string_stream *stream);
> +bool is_literal(const char *text, long long value);
> +bool is_str_literal(const char *text, const char *value);
> +void kunit_assert_hexdump(struct string_stream *stream,
> + const void *buf,
> + const void *compared_buf,
> + const size_t len);
> +#endif
> +
>  #endif /*  _KUNIT_ASSERT_H */
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 309659a32a78..900e6447c8e8 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_KUNIT_TEST) +=   kunit-test.o
>  # string-stream-test compiles built-in only.
>  ifeq ($(CONFIG_KUNIT_TEST),y)
>  obj-$(CONFIG_KUNIT_TEST) +=string-stream-test.o
> +obj-$(CONFIG_KUNIT_TEST) 

Re: [PATCH] kunit: add missing MODULE_DESCRIPTION() macros to core modules

2024-06-03 Thread Rae Moar
On Sat, Jun 1, 2024 at 1:19 PM Jeff Johnson  wrote:
>
> make allmodconfig && make W=1 C=1 reports in lib/kunit:
> WARNING: modpost: missing MODULE_DESCRIPTION() in lib/kunit/kunit.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in lib/kunit/kunit-test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> lib/kunit/kunit-example-test.o
>
> Add the missing invocations of the MODULE_DESCRIPTION() macro.
>
> Signed-off-by: Jeff Johnson 

Hello!

This looks good to me.

Reviewed-by: Rae Moar 

Thanks!
-Rae

> ---
>  lib/kunit/kunit-example-test.c | 1 +
>  lib/kunit/kunit-test.c | 1 +
>  lib/kunit/test.c   | 1 +
>  3 files changed, 3 insertions(+)
>
> diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
> index 798924f7cc86..3056d6bc705d 100644
> --- a/lib/kunit/kunit-example-test.c
> +++ b/lib/kunit/kunit-example-test.c
> @@ -374,4 +374,5 @@ static struct kunit_suite example_init_test_suite = {
>   */
>  kunit_test_init_section_suites(&example_init_test_suite);
>
> +MODULE_DESCRIPTION("Example KUnit test suite");
>  MODULE_LICENSE("GPL v2");
> diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
> index e3412e0ca399..37e02be1e710 100644
> --- a/lib/kunit/kunit-test.c
> +++ b/lib/kunit/kunit-test.c
> @@ -871,4 +871,5 @@ kunit_test_suites(&kunit_try_catch_test_suite, 
> &kunit_resource_test_suite,
>   &kunit_current_test_suite, &kunit_device_test_suite,
>   &kunit_fault_test_suite);
>
> +MODULE_DESCRIPTION("KUnit test for core test infrastructure");
>  MODULE_LICENSE("GPL v2");
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index b8514dbb337c..e8b1b52a19ab 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -938,4 +938,5 @@ static void __exit kunit_exit(void)
>  }
>  module_exit(kunit_exit);
>
> +MODULE_DESCRIPTION("Base unit test (KUnit) API");
>  MODULE_LICENSE("GPL v2");
>
> ---
> base-commit: b050496579632f86ee1ef7e7501906db579f3457
> change-id: 20240601-md-lib-kunit-framework-ed2d8b6f5e76
>



Re: [PATCH v2] kunit: Device wrappers should also manage driver name

2024-08-20 Thread Rae Moar
On Fri, Aug 16, 2024 at 12:51 AM David Gow  wrote:
>
> kunit_driver_create() accepts a name for the driver, but does not copy
> it, so if that name is either on the stack, or otherwise freed, we end
> up with a use-after-free when the driver is cleaned up.
>
> Instead, strdup() the name, and manage it as another KUnit allocation.
> As there was no existing kunit_kstrdup(), we add one. Further, add a
> kunit_ variant of strdup_const() and kfree_const(), so we don't need to
> allocate and manage the string in the majority of cases where it's a
> constant.
>
> However, these are inline functions, and is_kernel_rodata() only works
> for built-in code. This causes problems in two cases:
> - If kunit is built as a module, __{start,end}_rodata is not defined.
> - If a kunit test using these functions is built as a module, it will
>   suffer the same fate.
>
> This fixes a KASAN splat with overflow.overflow_allocation_test, when
> built as a module.
>
> Restrict the is_kernel_rodata() case to when KUnit is built as a module,
> which fixes the first case, at the cost of losing the optimisation.
>
> Also, make kunit_{kstrdup,kfree}_const non-inline, so that other modules
> using them will not accidentally depend on is_kernel_rodata(). If KUnit
> is built-in, they'll benefit from the optimisation, if KUnit is not,
> they won't, but the string will be properly duplicated.
>
> Fixes: d03c720e03bd ("kunit: Add APIs for managing devices")
> Reported-by: Nico Pache 
> Closes: https://groups.google.com/g/kunit-dev/c/81V9b9QYON0
> Reviewed-by: Kees Cook 
> Reviewed-by: Maxime Ripard 
> Reviewed-by: Rae Moar 
> Signed-off-by: David Gow 
> ---
>
> This is a combination of the previous version of this patch with the
> follow-up fix "kunit: Fix kunit_kstrdup_const() with modules".
>
> kunit_kstrdup_const() now falls back to kstrdup() if KUnit is built as a
> module, and is no longer inlined. This should fix the issues we'd seen
> before.
>
> I've not tried doing something fancy by looking at module rodata
> sections: it might be a possible optimisation, but it seems like it'd
> overcomplicate things for this initial change. If we hit a KUnit test
> where this is a bottleneck (or if I have some more spare time), we can
> look into it.
>
> The overflow_kunit test has been fixed independently to not rely on this
> anyway, so there shouldn't be any current cases of this causing issues,
> but it's worth making the API robust regardless.
>
> Changes since previous version:
> https://lore.kernel.org/linux-kselftest/20240731070207.3918687-1-david...@google.com/
> - Fix module support by integrating:
>   
> https://lore.kernel.org/linux-kselftest/20240806020136.3481593-1-david...@google.com/
>

Hello!

I tested this new patch with modules, particularly the device tests
and the overflow_kunit test. And it seems to be working well.

Tested-by: Rae Moar 

Thanks!
-Rae

> ---
>  include/kunit/test.h | 48 
>  lib/kunit/device.c   |  7 +--
>  lib/kunit/test.c | 19 ++
>  3 files changed, 72 insertions(+), 2 deletions(-)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index e2a1f0928e8b..5ac237c949a0 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -28,6 +28,7 @@
>  #include 
>
>  #include 
> +#include 
>
>  /* Static key: true if any KUnit tests are currently running */
>  DECLARE_STATIC_KEY_FALSE(kunit_running);
> @@ -480,6 +481,53 @@ static inline void *kunit_kcalloc(struct kunit *test, 
> size_t n, size_t size, gfp
> return kunit_kmalloc_array(test, n, size, gfp | __GFP_ZERO);
>  }
>
> +
> +/**
> + * kunit_kfree_const() - conditionally free test managed memory
> + * @x: pointer to the memory
> + *
> + * Calls kunit_kfree() only if @x is not in .rodata section.
> + * See kunit_kstrdup_const() for more information.
> + */
> +void kunit_kfree_const(struct kunit *test, const void *x);
> +
> +/**
> + * kunit_kstrdup() - Duplicates a string into a test managed allocation.
> + *
> + * @test: The test context object.
> + * @str: The NULL-terminated string to duplicate.
> + * @gfp: flags passed to underlying kmalloc().
> + *
> + * See kstrdup() and kunit_kmalloc_array() for more information.
> + */
> +static inline char *kunit_kstrdup(struct kunit *test, const char *str, gfp_t 
> gfp)
> +{
> +   size_t len;
> +   char *buf;
> +
> +   if (!str)
> +   return NULL;
> +
> +   len = strlen(str) + 1;
> +   buf = kunit_kmalloc(test, len, gfp);
> +   if (buf)
> +   memcpy(buf, str, len);
> 

  1   2   >