162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Base unit test (KUnit) API. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019, Google LLC. 662306a36Sopenharmony_ci * Author: Brendan Higgins <brendanhiggins@google.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <kunit/resource.h> 1062306a36Sopenharmony_ci#include <kunit/test.h> 1162306a36Sopenharmony_ci#include <kunit/test-bug.h> 1262306a36Sopenharmony_ci#include <kunit/attributes.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/moduleparam.h> 1662306a36Sopenharmony_ci#include <linux/panic.h> 1762306a36Sopenharmony_ci#include <linux/sched/debug.h> 1862306a36Sopenharmony_ci#include <linux/sched.h> 1962306a36Sopenharmony_ci#include <linux/mm.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "debugfs.h" 2262306a36Sopenharmony_ci#include "hooks-impl.h" 2362306a36Sopenharmony_ci#include "string-stream.h" 2462306a36Sopenharmony_ci#include "try-catch-impl.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Hook to fail the current test and print an error message to the log. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_civoid __printf(3, 4) __kunit_fail_current_test_impl(const char *file, int line, const char *fmt, ...) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci va_list args; 3262306a36Sopenharmony_ci int len; 3362306a36Sopenharmony_ci char *buffer; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (!current->kunit_test) 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci kunit_set_failure(current->kunit_test); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* kunit_err() only accepts literals, so evaluate the args first. */ 4162306a36Sopenharmony_ci va_start(args, fmt); 4262306a36Sopenharmony_ci len = vsnprintf(NULL, 0, fmt, args) + 1; 4362306a36Sopenharmony_ci va_end(args); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci buffer = kunit_kmalloc(current->kunit_test, len, GFP_KERNEL); 4662306a36Sopenharmony_ci if (!buffer) 4762306a36Sopenharmony_ci return; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci va_start(args, fmt); 5062306a36Sopenharmony_ci vsnprintf(buffer, len, fmt, args); 5162306a36Sopenharmony_ci va_end(args); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci kunit_err(current->kunit_test, "%s:%d: %s", file, line, buffer); 5462306a36Sopenharmony_ci kunit_kfree(current->kunit_test, buffer); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * Enable KUnit tests to run. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci#ifdef CONFIG_KUNIT_DEFAULT_ENABLED 6162306a36Sopenharmony_cistatic bool enable_param = true; 6262306a36Sopenharmony_ci#else 6362306a36Sopenharmony_cistatic bool enable_param; 6462306a36Sopenharmony_ci#endif 6562306a36Sopenharmony_cimodule_param_named(enable, enable_param, bool, 0); 6662306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable KUnit tests"); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 6962306a36Sopenharmony_ci * KUnit statistic mode: 7062306a36Sopenharmony_ci * 0 - disabled 7162306a36Sopenharmony_ci * 1 - only when there is more than one subtest 7262306a36Sopenharmony_ci * 2 - enabled 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistatic int kunit_stats_enabled = 1; 7562306a36Sopenharmony_cimodule_param_named(stats_enabled, kunit_stats_enabled, int, 0644); 7662306a36Sopenharmony_ciMODULE_PARM_DESC(stats_enabled, 7762306a36Sopenharmony_ci "Print test stats: never (0), only for multiple subtests (1), or always (2)"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct kunit_result_stats { 8062306a36Sopenharmony_ci unsigned long passed; 8162306a36Sopenharmony_ci unsigned long skipped; 8262306a36Sopenharmony_ci unsigned long failed; 8362306a36Sopenharmony_ci unsigned long total; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic bool kunit_should_print_stats(struct kunit_result_stats stats) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci if (kunit_stats_enabled == 0) 8962306a36Sopenharmony_ci return false; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (kunit_stats_enabled == 2) 9262306a36Sopenharmony_ci return true; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return (stats.total > 1); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic void kunit_print_test_stats(struct kunit *test, 9862306a36Sopenharmony_ci struct kunit_result_stats stats) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci if (!kunit_should_print_stats(stats)) 10162306a36Sopenharmony_ci return; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci kunit_log(KERN_INFO, test, 10462306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT 10562306a36Sopenharmony_ci "# %s: pass:%lu fail:%lu skip:%lu total:%lu", 10662306a36Sopenharmony_ci test->name, 10762306a36Sopenharmony_ci stats.passed, 10862306a36Sopenharmony_ci stats.failed, 10962306a36Sopenharmony_ci stats.skipped, 11062306a36Sopenharmony_ci stats.total); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/** 11462306a36Sopenharmony_ci * kunit_log_newline() - Add newline to the end of log if one is not 11562306a36Sopenharmony_ci * already present. 11662306a36Sopenharmony_ci * @log: The log to add the newline to. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_cistatic void kunit_log_newline(char *log) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci int log_len, len_left; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci log_len = strlen(log); 12362306a36Sopenharmony_ci len_left = KUNIT_LOG_SIZE - log_len - 1; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (log_len > 0 && log[log_len - 1] != '\n') 12662306a36Sopenharmony_ci strncat(log, "\n", len_left); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* 13062306a36Sopenharmony_ci * Append formatted message to log, size of which is limited to 13162306a36Sopenharmony_ci * KUNIT_LOG_SIZE bytes (including null terminating byte). 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_civoid kunit_log_append(char *log, const char *fmt, ...) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci va_list args; 13662306a36Sopenharmony_ci int len, log_len, len_left; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (!log) 13962306a36Sopenharmony_ci return; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci log_len = strlen(log); 14262306a36Sopenharmony_ci len_left = KUNIT_LOG_SIZE - log_len - 1; 14362306a36Sopenharmony_ci if (len_left <= 0) 14462306a36Sopenharmony_ci return; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* Evaluate length of line to add to log */ 14762306a36Sopenharmony_ci va_start(args, fmt); 14862306a36Sopenharmony_ci len = vsnprintf(NULL, 0, fmt, args) + 1; 14962306a36Sopenharmony_ci va_end(args); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Print formatted line to the log */ 15262306a36Sopenharmony_ci va_start(args, fmt); 15362306a36Sopenharmony_ci vsnprintf(log + log_len, min(len, len_left), fmt, args); 15462306a36Sopenharmony_ci va_end(args); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Add newline to end of log if not already present. */ 15762306a36Sopenharmony_ci kunit_log_newline(log); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_log_append); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cisize_t kunit_suite_num_test_cases(struct kunit_suite *suite) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct kunit_case *test_case; 16462306a36Sopenharmony_ci size_t len = 0; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci kunit_suite_for_each_test_case(suite, test_case) 16762306a36Sopenharmony_ci len++; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return len; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_suite_num_test_cases); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* Currently supported test levels */ 17462306a36Sopenharmony_cienum { 17562306a36Sopenharmony_ci KUNIT_LEVEL_SUITE = 0, 17662306a36Sopenharmony_ci KUNIT_LEVEL_CASE, 17762306a36Sopenharmony_ci KUNIT_LEVEL_CASE_PARAM, 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void kunit_print_suite_start(struct kunit_suite *suite) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * We do not log the test suite header as doing so would 18462306a36Sopenharmony_ci * mean debugfs display would consist of the test suite 18562306a36Sopenharmony_ci * header prior to individual test results. 18662306a36Sopenharmony_ci * Hence directly printk the suite status, and we will 18762306a36Sopenharmony_ci * separately seq_printf() the suite header for the debugfs 18862306a36Sopenharmony_ci * representation. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci pr_info(KUNIT_SUBTEST_INDENT "KTAP version 1\n"); 19162306a36Sopenharmony_ci pr_info(KUNIT_SUBTEST_INDENT "# Subtest: %s\n", 19262306a36Sopenharmony_ci suite->name); 19362306a36Sopenharmony_ci kunit_print_attr((void *)suite, false, KUNIT_LEVEL_CASE); 19462306a36Sopenharmony_ci pr_info(KUNIT_SUBTEST_INDENT "1..%zd\n", 19562306a36Sopenharmony_ci kunit_suite_num_test_cases(suite)); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void kunit_print_ok_not_ok(struct kunit *test, 19962306a36Sopenharmony_ci unsigned int test_level, 20062306a36Sopenharmony_ci enum kunit_status status, 20162306a36Sopenharmony_ci size_t test_number, 20262306a36Sopenharmony_ci const char *description, 20362306a36Sopenharmony_ci const char *directive) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci const char *directive_header = (status == KUNIT_SKIPPED) ? " # SKIP " : ""; 20662306a36Sopenharmony_ci const char *directive_body = (status == KUNIT_SKIPPED) ? directive : ""; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* 20962306a36Sopenharmony_ci * When test is NULL assume that results are from the suite 21062306a36Sopenharmony_ci * and today suite results are expected at level 0 only. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci WARN(!test && test_level, "suite test level can't be %u!\n", test_level); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * We do not log the test suite results as doing so would 21662306a36Sopenharmony_ci * mean debugfs display would consist of an incorrect test 21762306a36Sopenharmony_ci * number. Hence directly printk the suite result, and we will 21862306a36Sopenharmony_ci * separately seq_printf() the suite results for the debugfs 21962306a36Sopenharmony_ci * representation. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci if (!test) 22262306a36Sopenharmony_ci pr_info("%s %zd %s%s%s\n", 22362306a36Sopenharmony_ci kunit_status_to_ok_not_ok(status), 22462306a36Sopenharmony_ci test_number, description, directive_header, 22562306a36Sopenharmony_ci directive_body); 22662306a36Sopenharmony_ci else 22762306a36Sopenharmony_ci kunit_log(KERN_INFO, test, 22862306a36Sopenharmony_ci "%*s%s %zd %s%s%s", 22962306a36Sopenharmony_ci KUNIT_INDENT_LEN * test_level, "", 23062306a36Sopenharmony_ci kunit_status_to_ok_not_ok(status), 23162306a36Sopenharmony_ci test_number, description, directive_header, 23262306a36Sopenharmony_ci directive_body); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cienum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci const struct kunit_case *test_case; 23862306a36Sopenharmony_ci enum kunit_status status = KUNIT_SKIPPED; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (suite->suite_init_err) 24162306a36Sopenharmony_ci return KUNIT_FAILURE; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci kunit_suite_for_each_test_case(suite, test_case) { 24462306a36Sopenharmony_ci if (test_case->status == KUNIT_FAILURE) 24562306a36Sopenharmony_ci return KUNIT_FAILURE; 24662306a36Sopenharmony_ci else if (test_case->status == KUNIT_SUCCESS) 24762306a36Sopenharmony_ci status = KUNIT_SUCCESS; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return status; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_suite_has_succeeded); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic size_t kunit_suite_counter = 1; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic void kunit_print_suite_end(struct kunit_suite *suite) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci kunit_print_ok_not_ok(NULL, KUNIT_LEVEL_SUITE, 25962306a36Sopenharmony_ci kunit_suite_has_succeeded(suite), 26062306a36Sopenharmony_ci kunit_suite_counter++, 26162306a36Sopenharmony_ci suite->name, 26262306a36Sopenharmony_ci suite->status_comment); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ciunsigned int kunit_test_case_num(struct kunit_suite *suite, 26662306a36Sopenharmony_ci struct kunit_case *test_case) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct kunit_case *tc; 26962306a36Sopenharmony_ci unsigned int i = 1; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci kunit_suite_for_each_test_case(suite, tc) { 27262306a36Sopenharmony_ci if (tc == test_case) 27362306a36Sopenharmony_ci return i; 27462306a36Sopenharmony_ci i++; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_test_case_num); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic void kunit_print_string_stream(struct kunit *test, 28262306a36Sopenharmony_ci struct string_stream *stream) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct string_stream_fragment *fragment; 28562306a36Sopenharmony_ci char *buf; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (string_stream_is_empty(stream)) 28862306a36Sopenharmony_ci return; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci buf = string_stream_get_string(stream); 29162306a36Sopenharmony_ci if (!buf) { 29262306a36Sopenharmony_ci kunit_err(test, 29362306a36Sopenharmony_ci "Could not allocate buffer, dumping stream:\n"); 29462306a36Sopenharmony_ci list_for_each_entry(fragment, &stream->fragments, node) { 29562306a36Sopenharmony_ci kunit_err(test, "%s", fragment->fragment); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci kunit_err(test, "\n"); 29862306a36Sopenharmony_ci } else { 29962306a36Sopenharmony_ci kunit_err(test, "%s", buf); 30062306a36Sopenharmony_ci kunit_kfree(test, buf); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void kunit_fail(struct kunit *test, const struct kunit_loc *loc, 30562306a36Sopenharmony_ci enum kunit_assert_type type, const struct kunit_assert *assert, 30662306a36Sopenharmony_ci assert_format_t assert_format, const struct va_format *message) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct string_stream *stream; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci kunit_set_failure(test); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci stream = alloc_string_stream(test, GFP_KERNEL); 31362306a36Sopenharmony_ci if (IS_ERR(stream)) { 31462306a36Sopenharmony_ci WARN(true, 31562306a36Sopenharmony_ci "Could not allocate stream to print failed assertion in %s:%d\n", 31662306a36Sopenharmony_ci loc->file, 31762306a36Sopenharmony_ci loc->line); 31862306a36Sopenharmony_ci return; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci kunit_assert_prologue(loc, type, stream); 32262306a36Sopenharmony_ci assert_format(assert, message, stream); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci kunit_print_string_stream(test, stream); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci string_stream_destroy(stream); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_civoid __noreturn __kunit_abort(struct kunit *test) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci kunit_try_catch_throw(&test->try_catch); /* Does not return. */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * Throw could not abort from test. 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * XXX: we should never reach this line! As kunit_try_catch_throw is 33762306a36Sopenharmony_ci * marked __noreturn. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ci WARN_ONCE(true, "Throw could not abort from test!\n"); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__kunit_abort); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_civoid __kunit_do_failed_assertion(struct kunit *test, 34462306a36Sopenharmony_ci const struct kunit_loc *loc, 34562306a36Sopenharmony_ci enum kunit_assert_type type, 34662306a36Sopenharmony_ci const struct kunit_assert *assert, 34762306a36Sopenharmony_ci assert_format_t assert_format, 34862306a36Sopenharmony_ci const char *fmt, ...) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci va_list args; 35162306a36Sopenharmony_ci struct va_format message; 35262306a36Sopenharmony_ci va_start(args, fmt); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci message.fmt = fmt; 35562306a36Sopenharmony_ci message.va = &args; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci kunit_fail(test, loc, type, assert, assert_format, &message); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci va_end(args); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__kunit_do_failed_assertion); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_civoid kunit_init_test(struct kunit *test, const char *name, char *log) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci spin_lock_init(&test->lock); 36662306a36Sopenharmony_ci INIT_LIST_HEAD(&test->resources); 36762306a36Sopenharmony_ci test->name = name; 36862306a36Sopenharmony_ci test->log = log; 36962306a36Sopenharmony_ci if (test->log) 37062306a36Sopenharmony_ci test->log[0] = '\0'; 37162306a36Sopenharmony_ci test->status = KUNIT_SUCCESS; 37262306a36Sopenharmony_ci test->status_comment[0] = '\0'; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_init_test); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/* Only warn when a test takes more than twice the threshold */ 37762306a36Sopenharmony_ci#define KUNIT_SPEED_WARNING_MULTIPLIER 2 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* Slow tests are defined as taking more than 1s */ 38062306a36Sopenharmony_ci#define KUNIT_SPEED_SLOW_THRESHOLD_S 1 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci#define KUNIT_SPEED_SLOW_WARNING_THRESHOLD_S \ 38362306a36Sopenharmony_ci (KUNIT_SPEED_WARNING_MULTIPLIER * KUNIT_SPEED_SLOW_THRESHOLD_S) 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci#define s_to_timespec64(s) ns_to_timespec64((s) * NSEC_PER_SEC) 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void kunit_run_case_check_speed(struct kunit *test, 38862306a36Sopenharmony_ci struct kunit_case *test_case, 38962306a36Sopenharmony_ci struct timespec64 duration) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct timespec64 slow_thr = 39262306a36Sopenharmony_ci s_to_timespec64(KUNIT_SPEED_SLOW_WARNING_THRESHOLD_S); 39362306a36Sopenharmony_ci enum kunit_speed speed = test_case->attr.speed; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (timespec64_compare(&duration, &slow_thr) < 0) 39662306a36Sopenharmony_ci return; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (speed == KUNIT_SPEED_VERY_SLOW || speed == KUNIT_SPEED_SLOW) 39962306a36Sopenharmony_ci return; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci kunit_warn(test, 40262306a36Sopenharmony_ci "Test should be marked slow (runtime: %lld.%09lds)", 40362306a36Sopenharmony_ci duration.tv_sec, duration.tv_nsec); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci/* 40762306a36Sopenharmony_ci * Initializes and runs test case. Does not clean up or do post validations. 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_cistatic void kunit_run_case_internal(struct kunit *test, 41062306a36Sopenharmony_ci struct kunit_suite *suite, 41162306a36Sopenharmony_ci struct kunit_case *test_case) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct timespec64 start, end; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (suite->init) { 41662306a36Sopenharmony_ci int ret; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = suite->init(test); 41962306a36Sopenharmony_ci if (ret) { 42062306a36Sopenharmony_ci kunit_err(test, "failed to initialize: %d\n", ret); 42162306a36Sopenharmony_ci kunit_set_failure(test); 42262306a36Sopenharmony_ci return; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci ktime_get_ts64(&start); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci test_case->run_case(test); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ktime_get_ts64(&end); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci kunit_run_case_check_speed(test, test_case, timespec64_sub(end, start)); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic void kunit_case_internal_cleanup(struct kunit *test) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci kunit_cleanup(test); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/* 44162306a36Sopenharmony_ci * Performs post validations and cleanup after a test case was run. 44262306a36Sopenharmony_ci * XXX: Should ONLY BE CALLED AFTER kunit_run_case_internal! 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_cistatic void kunit_run_case_cleanup(struct kunit *test, 44562306a36Sopenharmony_ci struct kunit_suite *suite) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci if (suite->exit) 44862306a36Sopenharmony_ci suite->exit(test); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci kunit_case_internal_cleanup(test); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistruct kunit_try_catch_context { 45462306a36Sopenharmony_ci struct kunit *test; 45562306a36Sopenharmony_ci struct kunit_suite *suite; 45662306a36Sopenharmony_ci struct kunit_case *test_case; 45762306a36Sopenharmony_ci}; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic void kunit_try_run_case(void *data) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct kunit_try_catch_context *ctx = data; 46262306a36Sopenharmony_ci struct kunit *test = ctx->test; 46362306a36Sopenharmony_ci struct kunit_suite *suite = ctx->suite; 46462306a36Sopenharmony_ci struct kunit_case *test_case = ctx->test_case; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci current->kunit_test = test; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * kunit_run_case_internal may encounter a fatal error; if it does, 47062306a36Sopenharmony_ci * abort will be called, this thread will exit, and finally the parent 47162306a36Sopenharmony_ci * thread will resume control and handle any necessary clean up. 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_ci kunit_run_case_internal(test, suite, test_case); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic void kunit_try_run_case_cleanup(void *data) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct kunit_try_catch_context *ctx = data; 47962306a36Sopenharmony_ci struct kunit *test = ctx->test; 48062306a36Sopenharmony_ci struct kunit_suite *suite = ctx->suite; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci current->kunit_test = test; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci kunit_run_case_cleanup(test, suite); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void kunit_catch_run_case_cleanup(void *data) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct kunit_try_catch_context *ctx = data; 49062306a36Sopenharmony_ci struct kunit *test = ctx->test; 49162306a36Sopenharmony_ci int try_exit_code = kunit_try_catch_get_result(&test->try_catch); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* It is always a failure if cleanup aborts. */ 49462306a36Sopenharmony_ci kunit_set_failure(test); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (try_exit_code) { 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * Test case could not finish, we have no idea what state it is 49962306a36Sopenharmony_ci * in, so don't do clean up. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci if (try_exit_code == -ETIMEDOUT) { 50262306a36Sopenharmony_ci kunit_err(test, "test case cleanup timed out\n"); 50362306a36Sopenharmony_ci /* 50462306a36Sopenharmony_ci * Unknown internal error occurred preventing test case from 50562306a36Sopenharmony_ci * running, so there is nothing to clean up. 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ci } else { 50862306a36Sopenharmony_ci kunit_err(test, "internal error occurred during test case cleanup: %d\n", 50962306a36Sopenharmony_ci try_exit_code); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci return; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci kunit_err(test, "test aborted during cleanup. continuing without cleaning up\n"); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void kunit_catch_run_case(void *data) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct kunit_try_catch_context *ctx = data; 52162306a36Sopenharmony_ci struct kunit *test = ctx->test; 52262306a36Sopenharmony_ci int try_exit_code = kunit_try_catch_get_result(&test->try_catch); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (try_exit_code) { 52562306a36Sopenharmony_ci kunit_set_failure(test); 52662306a36Sopenharmony_ci /* 52762306a36Sopenharmony_ci * Test case could not finish, we have no idea what state it is 52862306a36Sopenharmony_ci * in, so don't do clean up. 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_ci if (try_exit_code == -ETIMEDOUT) { 53162306a36Sopenharmony_ci kunit_err(test, "test case timed out\n"); 53262306a36Sopenharmony_ci /* 53362306a36Sopenharmony_ci * Unknown internal error occurred preventing test case from 53462306a36Sopenharmony_ci * running, so there is nothing to clean up. 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_ci } else { 53762306a36Sopenharmony_ci kunit_err(test, "internal error occurred preventing test case from running: %d\n", 53862306a36Sopenharmony_ci try_exit_code); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci return; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/* 54562306a36Sopenharmony_ci * Performs all logic to run a test case. It also catches most errors that 54662306a36Sopenharmony_ci * occur in a test case and reports them as failures. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_cistatic void kunit_run_case_catch_errors(struct kunit_suite *suite, 54962306a36Sopenharmony_ci struct kunit_case *test_case, 55062306a36Sopenharmony_ci struct kunit *test) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct kunit_try_catch_context context; 55362306a36Sopenharmony_ci struct kunit_try_catch *try_catch; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci try_catch = &test->try_catch; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci kunit_try_catch_init(try_catch, 55862306a36Sopenharmony_ci test, 55962306a36Sopenharmony_ci kunit_try_run_case, 56062306a36Sopenharmony_ci kunit_catch_run_case); 56162306a36Sopenharmony_ci context.test = test; 56262306a36Sopenharmony_ci context.suite = suite; 56362306a36Sopenharmony_ci context.test_case = test_case; 56462306a36Sopenharmony_ci kunit_try_catch_run(try_catch, &context); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Now run the cleanup */ 56762306a36Sopenharmony_ci kunit_try_catch_init(try_catch, 56862306a36Sopenharmony_ci test, 56962306a36Sopenharmony_ci kunit_try_run_case_cleanup, 57062306a36Sopenharmony_ci kunit_catch_run_case_cleanup); 57162306a36Sopenharmony_ci kunit_try_catch_run(try_catch, &context); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* Propagate the parameter result to the test case. */ 57462306a36Sopenharmony_ci if (test->status == KUNIT_FAILURE) 57562306a36Sopenharmony_ci test_case->status = KUNIT_FAILURE; 57662306a36Sopenharmony_ci else if (test_case->status != KUNIT_FAILURE && test->status == KUNIT_SUCCESS) 57762306a36Sopenharmony_ci test_case->status = KUNIT_SUCCESS; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void kunit_print_suite_stats(struct kunit_suite *suite, 58162306a36Sopenharmony_ci struct kunit_result_stats suite_stats, 58262306a36Sopenharmony_ci struct kunit_result_stats param_stats) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci if (kunit_should_print_stats(suite_stats)) { 58562306a36Sopenharmony_ci kunit_log(KERN_INFO, suite, 58662306a36Sopenharmony_ci "# %s: pass:%lu fail:%lu skip:%lu total:%lu", 58762306a36Sopenharmony_ci suite->name, 58862306a36Sopenharmony_ci suite_stats.passed, 58962306a36Sopenharmony_ci suite_stats.failed, 59062306a36Sopenharmony_ci suite_stats.skipped, 59162306a36Sopenharmony_ci suite_stats.total); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (kunit_should_print_stats(param_stats)) { 59562306a36Sopenharmony_ci kunit_log(KERN_INFO, suite, 59662306a36Sopenharmony_ci "# Totals: pass:%lu fail:%lu skip:%lu total:%lu", 59762306a36Sopenharmony_ci param_stats.passed, 59862306a36Sopenharmony_ci param_stats.failed, 59962306a36Sopenharmony_ci param_stats.skipped, 60062306a36Sopenharmony_ci param_stats.total); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic void kunit_update_stats(struct kunit_result_stats *stats, 60562306a36Sopenharmony_ci enum kunit_status status) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci switch (status) { 60862306a36Sopenharmony_ci case KUNIT_SUCCESS: 60962306a36Sopenharmony_ci stats->passed++; 61062306a36Sopenharmony_ci break; 61162306a36Sopenharmony_ci case KUNIT_SKIPPED: 61262306a36Sopenharmony_ci stats->skipped++; 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci case KUNIT_FAILURE: 61562306a36Sopenharmony_ci stats->failed++; 61662306a36Sopenharmony_ci break; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci stats->total++; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic void kunit_accumulate_stats(struct kunit_result_stats *total, 62362306a36Sopenharmony_ci struct kunit_result_stats add) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci total->passed += add.passed; 62662306a36Sopenharmony_ci total->skipped += add.skipped; 62762306a36Sopenharmony_ci total->failed += add.failed; 62862306a36Sopenharmony_ci total->total += add.total; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ciint kunit_run_tests(struct kunit_suite *suite) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci char param_desc[KUNIT_PARAM_DESC_SIZE]; 63462306a36Sopenharmony_ci struct kunit_case *test_case; 63562306a36Sopenharmony_ci struct kunit_result_stats suite_stats = { 0 }; 63662306a36Sopenharmony_ci struct kunit_result_stats total_stats = { 0 }; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Taint the kernel so we know we've run tests. */ 63962306a36Sopenharmony_ci add_taint(TAINT_TEST, LOCKDEP_STILL_OK); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (suite->suite_init) { 64262306a36Sopenharmony_ci suite->suite_init_err = suite->suite_init(suite); 64362306a36Sopenharmony_ci if (suite->suite_init_err) { 64462306a36Sopenharmony_ci kunit_err(suite, KUNIT_SUBTEST_INDENT 64562306a36Sopenharmony_ci "# failed to initialize (%d)", suite->suite_init_err); 64662306a36Sopenharmony_ci goto suite_end; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci kunit_print_suite_start(suite); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci kunit_suite_for_each_test_case(suite, test_case) { 65362306a36Sopenharmony_ci struct kunit test = { .param_value = NULL, .param_index = 0 }; 65462306a36Sopenharmony_ci struct kunit_result_stats param_stats = { 0 }; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci kunit_init_test(&test, test_case->name, test_case->log); 65762306a36Sopenharmony_ci if (test_case->status == KUNIT_SKIPPED) { 65862306a36Sopenharmony_ci /* Test marked as skip */ 65962306a36Sopenharmony_ci test.status = KUNIT_SKIPPED; 66062306a36Sopenharmony_ci kunit_update_stats(¶m_stats, test.status); 66162306a36Sopenharmony_ci } else if (!test_case->generate_params) { 66262306a36Sopenharmony_ci /* Non-parameterised test. */ 66362306a36Sopenharmony_ci test_case->status = KUNIT_SKIPPED; 66462306a36Sopenharmony_ci kunit_run_case_catch_errors(suite, test_case, &test); 66562306a36Sopenharmony_ci kunit_update_stats(¶m_stats, test.status); 66662306a36Sopenharmony_ci } else { 66762306a36Sopenharmony_ci /* Get initial param. */ 66862306a36Sopenharmony_ci param_desc[0] = '\0'; 66962306a36Sopenharmony_ci test.param_value = test_case->generate_params(NULL, param_desc); 67062306a36Sopenharmony_ci test_case->status = KUNIT_SKIPPED; 67162306a36Sopenharmony_ci kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 67262306a36Sopenharmony_ci "KTAP version 1\n"); 67362306a36Sopenharmony_ci kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 67462306a36Sopenharmony_ci "# Subtest: %s", test_case->name); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci while (test.param_value) { 67762306a36Sopenharmony_ci kunit_run_case_catch_errors(suite, test_case, &test); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (param_desc[0] == '\0') { 68062306a36Sopenharmony_ci snprintf(param_desc, sizeof(param_desc), 68162306a36Sopenharmony_ci "param-%d", test.param_index); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE_PARAM, 68562306a36Sopenharmony_ci test.status, 68662306a36Sopenharmony_ci test.param_index + 1, 68762306a36Sopenharmony_ci param_desc, 68862306a36Sopenharmony_ci test.status_comment); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* Get next param. */ 69162306a36Sopenharmony_ci param_desc[0] = '\0'; 69262306a36Sopenharmony_ci test.param_value = test_case->generate_params(test.param_value, param_desc); 69362306a36Sopenharmony_ci test.param_index++; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci kunit_update_stats(¶m_stats, test.status); 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci kunit_print_test_stats(&test, param_stats); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE, test_case->status, 70462306a36Sopenharmony_ci kunit_test_case_num(suite, test_case), 70562306a36Sopenharmony_ci test_case->name, 70662306a36Sopenharmony_ci test.status_comment); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci kunit_update_stats(&suite_stats, test_case->status); 70962306a36Sopenharmony_ci kunit_accumulate_stats(&total_stats, param_stats); 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if (suite->suite_exit) 71362306a36Sopenharmony_ci suite->suite_exit(suite); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci kunit_print_suite_stats(suite, suite_stats, total_stats); 71662306a36Sopenharmony_cisuite_end: 71762306a36Sopenharmony_ci kunit_print_suite_end(suite); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci return 0; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_run_tests); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic void kunit_init_suite(struct kunit_suite *suite) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci kunit_debugfs_create_suite(suite); 72662306a36Sopenharmony_ci suite->status_comment[0] = '\0'; 72762306a36Sopenharmony_ci suite->suite_init_err = 0; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cibool kunit_enabled(void) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci return enable_param; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ciint __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci unsigned int i; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (!kunit_enabled() && num_suites > 0) { 74062306a36Sopenharmony_ci pr_info("kunit: disabled\n"); 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci kunit_suite_counter = 1; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci static_branch_inc(&kunit_running); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci for (i = 0; i < num_suites; i++) { 74962306a36Sopenharmony_ci kunit_init_suite(suites[i]); 75062306a36Sopenharmony_ci kunit_run_tests(suites[i]); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci static_branch_dec(&kunit_running); 75462306a36Sopenharmony_ci return 0; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__kunit_test_suites_init); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic void kunit_exit_suite(struct kunit_suite *suite) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci kunit_debugfs_destroy_suite(suite); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_civoid __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci unsigned int i; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (!kunit_enabled()) 76862306a36Sopenharmony_ci return; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci for (i = 0; i < num_suites; i++) 77162306a36Sopenharmony_ci kunit_exit_suite(suites[i]); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__kunit_test_suites_exit); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci#ifdef CONFIG_MODULES 77662306a36Sopenharmony_cistatic void kunit_module_init(struct module *mod) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct kunit_suite_set suite_set = { 77962306a36Sopenharmony_ci mod->kunit_suites, mod->kunit_suites + mod->num_kunit_suites, 78062306a36Sopenharmony_ci }; 78162306a36Sopenharmony_ci const char *action = kunit_action(); 78262306a36Sopenharmony_ci int err = 0; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci suite_set = kunit_filter_suites(&suite_set, 78562306a36Sopenharmony_ci kunit_filter_glob() ?: "*.*", 78662306a36Sopenharmony_ci kunit_filter(), kunit_filter_action(), 78762306a36Sopenharmony_ci &err); 78862306a36Sopenharmony_ci if (err) 78962306a36Sopenharmony_ci pr_err("kunit module: error filtering suites: %d\n", err); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci mod->kunit_suites = (struct kunit_suite **)suite_set.start; 79262306a36Sopenharmony_ci mod->num_kunit_suites = suite_set.end - suite_set.start; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (!action) 79562306a36Sopenharmony_ci kunit_exec_run_tests(&suite_set, false); 79662306a36Sopenharmony_ci else if (!strcmp(action, "list")) 79762306a36Sopenharmony_ci kunit_exec_list_tests(&suite_set, false); 79862306a36Sopenharmony_ci else if (!strcmp(action, "list_attr")) 79962306a36Sopenharmony_ci kunit_exec_list_tests(&suite_set, true); 80062306a36Sopenharmony_ci else 80162306a36Sopenharmony_ci pr_err("kunit: unknown action '%s'\n", action); 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic void kunit_module_exit(struct module *mod) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct kunit_suite_set suite_set = { 80762306a36Sopenharmony_ci mod->kunit_suites, mod->kunit_suites + mod->num_kunit_suites, 80862306a36Sopenharmony_ci }; 80962306a36Sopenharmony_ci const char *action = kunit_action(); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* 81262306a36Sopenharmony_ci * Check if the start address is a valid virtual address to detect 81362306a36Sopenharmony_ci * if the module load sequence has failed and the suite set has not 81462306a36Sopenharmony_ci * been initialized and filtered. 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_ci if (!suite_set.start || !virt_addr_valid(suite_set.start)) 81762306a36Sopenharmony_ci return; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (!action) 82062306a36Sopenharmony_ci __kunit_test_suites_exit(mod->kunit_suites, 82162306a36Sopenharmony_ci mod->num_kunit_suites); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci kunit_free_suite_set(suite_set); 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic int kunit_module_notify(struct notifier_block *nb, unsigned long val, 82762306a36Sopenharmony_ci void *data) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct module *mod = data; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci switch (val) { 83262306a36Sopenharmony_ci case MODULE_STATE_LIVE: 83362306a36Sopenharmony_ci kunit_module_init(mod); 83462306a36Sopenharmony_ci break; 83562306a36Sopenharmony_ci case MODULE_STATE_GOING: 83662306a36Sopenharmony_ci kunit_module_exit(mod); 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci case MODULE_STATE_COMING: 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci case MODULE_STATE_UNFORMED: 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic struct notifier_block kunit_mod_nb = { 84862306a36Sopenharmony_ci .notifier_call = kunit_module_notify, 84962306a36Sopenharmony_ci .priority = 0, 85062306a36Sopenharmony_ci}; 85162306a36Sopenharmony_ci#endif 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_civoid *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci void *data; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci data = kmalloc_array(n, size, gfp); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (!data) 86062306a36Sopenharmony_ci return NULL; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (kunit_add_action_or_reset(test, (kunit_action_t *)kfree, data) != 0) 86362306a36Sopenharmony_ci return NULL; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci return data; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_kmalloc_array); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_civoid kunit_kfree(struct kunit *test, const void *ptr) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci if (!ptr) 87262306a36Sopenharmony_ci return; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci kunit_release_action(test, (kunit_action_t *)kfree, (void *)ptr); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_kfree); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_civoid kunit_cleanup(struct kunit *test) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci struct kunit_resource *res; 88162306a36Sopenharmony_ci unsigned long flags; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* 88462306a36Sopenharmony_ci * test->resources is a stack - each allocation must be freed in the 88562306a36Sopenharmony_ci * reverse order from which it was added since one resource may depend 88662306a36Sopenharmony_ci * on another for its entire lifetime. 88762306a36Sopenharmony_ci * Also, we cannot use the normal list_for_each constructs, even the 88862306a36Sopenharmony_ci * safe ones because *arbitrary* nodes may be deleted when 88962306a36Sopenharmony_ci * kunit_resource_free is called; the list_for_each_safe variants only 89062306a36Sopenharmony_ci * protect against the current node being deleted, not the next. 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_ci while (true) { 89362306a36Sopenharmony_ci spin_lock_irqsave(&test->lock, flags); 89462306a36Sopenharmony_ci if (list_empty(&test->resources)) { 89562306a36Sopenharmony_ci spin_unlock_irqrestore(&test->lock, flags); 89662306a36Sopenharmony_ci break; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci res = list_last_entry(&test->resources, 89962306a36Sopenharmony_ci struct kunit_resource, 90062306a36Sopenharmony_ci node); 90162306a36Sopenharmony_ci /* 90262306a36Sopenharmony_ci * Need to unlock here as a resource may remove another 90362306a36Sopenharmony_ci * resource, and this can't happen if the test->lock 90462306a36Sopenharmony_ci * is held. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_ci spin_unlock_irqrestore(&test->lock, flags); 90762306a36Sopenharmony_ci kunit_remove_resource(test, res); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci current->kunit_test = NULL; 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_cleanup); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic int __init kunit_init(void) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci /* Install the KUnit hook functions. */ 91662306a36Sopenharmony_ci kunit_install_hooks(); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci kunit_debugfs_init(); 91962306a36Sopenharmony_ci#ifdef CONFIG_MODULES 92062306a36Sopenharmony_ci return register_module_notifier(&kunit_mod_nb); 92162306a36Sopenharmony_ci#else 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci#endif 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_cilate_initcall(kunit_init); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic void __exit kunit_exit(void) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci memset(&kunit_hooks, 0, sizeof(kunit_hooks)); 93062306a36Sopenharmony_ci#ifdef CONFIG_MODULES 93162306a36Sopenharmony_ci unregister_module_notifier(&kunit_mod_nb); 93262306a36Sopenharmony_ci#endif 93362306a36Sopenharmony_ci kunit_debugfs_cleanup(); 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_cimodule_exit(kunit_exit); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 938