Assert that the kernel is not tainted with `TAINT_WARN` prior to running
a KUnit test case, and assert that it has not become tainted with
`TAINT_WARN` while the test has run. If this is not enabled,
writing and running KUnit test cases that trigger a `WARN()` does not
fail the test if the test itself passes. If enabled, it marks any test
that triggers a warning as failed, and forcefully skips all proceeding
test cases, since the taint cannot be cleared and the kernel is now seen
as unreliable.
The assertions are gated behind `CONFIG_KUNIT_FAIL_TEST_ON_WARN=y`

Signed-off-by: Malte Wechter <[email protected]>
---
 lib/kunit/test.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 1292a0799c33..6d6f1e947db5 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -81,6 +81,30 @@ void __printf(3, 4) __kunit_fail_current_test_impl(const 
char *file, int line, c
        kunit_kfree(current->kunit_test, buffer);
 }
 
+/*
+ * Fails current test if TAINT_WARN has been set (changed) after the test has 
run.
+ */
+static void kunit_check_taint_warn(struct kunit *test, unsigned long 
tainted_before)
+{
+       if (IS_ENABLED(CONFIG_KUNIT_FAIL_TEST_ON_WARN) &&
+               test_taint(TAINT_WARN) && !tainted_before) {
+               kunit_err(test, "Test triggered a kernel WARN");
+               kunit_set_failure(test);
+       }
+}
+
+/*
+ * Skip a KUnit test if the kernel is tainted with TAINT_WARN.
+ */
+static void kunit_skip_if_taint_warn(struct kunit *test, struct kunit_suite 
*suite)
+{
+       if (IS_ENABLED(CONFIG_KUNIT_FAIL_TEST_ON_WARN) && 
test_taint(TAINT_WARN)) {
+               suite->forced_skip = true;
+               test->forced_skip = true;
+               kunit_skip(test, "force skip: kernel is tainted with 
TAINT_WARN");
+       }
+}
+
 /*
  * Fails current test if test turns off debug_locks.
  */
@@ -487,6 +511,7 @@ static void kunit_run_case_internal(struct kunit *test,
        struct timespec64 start, end;
 
        kunit_skip_if_lockdep(test, suite);
+       kunit_skip_if_taint_warn(test, suite);
 
        if (suite->init) {
                int ret;
@@ -539,6 +564,7 @@ static void kunit_try_run_case(void *data)
        struct kunit_suite *suite = ctx->suite;
        struct kunit_case *test_case = ctx->test_case;
        int debug_locks_snapshot = debug_locks;
+       unsigned long tainted_warn_snapshot = test_taint(TAINT_WARN);
 
        current->kunit_test = test;
 
@@ -549,6 +575,7 @@ static void kunit_try_run_case(void *data)
         */
        kunit_run_case_internal(test, suite, test_case);
 
+       kunit_check_taint_warn(test, tainted_warn_snapshot);
        kunit_check_lockdep(test, debug_locks_snapshot);
 }
 

-- 
2.54.0


Reply via email to