18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Base unit test (KUnit) API. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019, Google LLC. 68c2ecf20Sopenharmony_ci * Author: Brendan Higgins <brendanhiggins@google.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <kunit/test.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/kref.h> 128c2ecf20Sopenharmony_ci#include <linux/sched/debug.h> 138c2ecf20Sopenharmony_ci#include <linux/sched.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "debugfs.h" 168c2ecf20Sopenharmony_ci#include "string-stream.h" 178c2ecf20Sopenharmony_ci#include "try-catch-impl.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Append formatted message to log, size of which is limited to 218c2ecf20Sopenharmony_ci * KUNIT_LOG_SIZE bytes (including null terminating byte). 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_civoid kunit_log_append(char *log, const char *fmt, ...) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci char line[KUNIT_LOG_SIZE]; 268c2ecf20Sopenharmony_ci va_list args; 278c2ecf20Sopenharmony_ci int len_left; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (!log) 308c2ecf20Sopenharmony_ci return; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci len_left = KUNIT_LOG_SIZE - strlen(log) - 1; 338c2ecf20Sopenharmony_ci if (len_left <= 0) 348c2ecf20Sopenharmony_ci return; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci va_start(args, fmt); 378c2ecf20Sopenharmony_ci vsnprintf(line, sizeof(line), fmt, args); 388c2ecf20Sopenharmony_ci va_end(args); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci strncat(log, line, len_left); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_log_append); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cisize_t kunit_suite_num_test_cases(struct kunit_suite *suite) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct kunit_case *test_case; 478c2ecf20Sopenharmony_ci size_t len = 0; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci kunit_suite_for_each_test_case(suite, test_case) 508c2ecf20Sopenharmony_ci len++; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return len; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_suite_num_test_cases); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void kunit_print_subtest_start(struct kunit_suite *suite) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "# Subtest: %s", 598c2ecf20Sopenharmony_ci suite->name); 608c2ecf20Sopenharmony_ci kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "1..%zd", 618c2ecf20Sopenharmony_ci kunit_suite_num_test_cases(suite)); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void kunit_print_ok_not_ok(void *test_or_suite, 658c2ecf20Sopenharmony_ci bool is_test, 668c2ecf20Sopenharmony_ci bool is_ok, 678c2ecf20Sopenharmony_ci size_t test_number, 688c2ecf20Sopenharmony_ci const char *description) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct kunit_suite *suite = is_test ? NULL : test_or_suite; 718c2ecf20Sopenharmony_ci struct kunit *test = is_test ? test_or_suite : NULL; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* 748c2ecf20Sopenharmony_ci * We do not log the test suite results as doing so would 758c2ecf20Sopenharmony_ci * mean debugfs display would consist of the test suite 768c2ecf20Sopenharmony_ci * description and status prior to individual test results. 778c2ecf20Sopenharmony_ci * Hence directly printk the suite status, and we will 788c2ecf20Sopenharmony_ci * separately seq_printf() the suite status for the debugfs 798c2ecf20Sopenharmony_ci * representation. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci if (suite) 828c2ecf20Sopenharmony_ci pr_info("%s %zd - %s\n", 838c2ecf20Sopenharmony_ci kunit_status_to_string(is_ok), 848c2ecf20Sopenharmony_ci test_number, description); 858c2ecf20Sopenharmony_ci else 868c2ecf20Sopenharmony_ci kunit_log(KERN_INFO, test, KUNIT_SUBTEST_INDENT "%s %zd - %s", 878c2ecf20Sopenharmony_ci kunit_status_to_string(is_ok), 888c2ecf20Sopenharmony_ci test_number, description); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cibool kunit_suite_has_succeeded(struct kunit_suite *suite) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci const struct kunit_case *test_case; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci kunit_suite_for_each_test_case(suite, test_case) { 968c2ecf20Sopenharmony_ci if (!test_case->success) 978c2ecf20Sopenharmony_ci return false; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return true; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_suite_has_succeeded); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void kunit_print_subtest_end(struct kunit_suite *suite) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci static size_t kunit_suite_counter = 1; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci kunit_print_ok_not_ok((void *)suite, false, 1098c2ecf20Sopenharmony_ci kunit_suite_has_succeeded(suite), 1108c2ecf20Sopenharmony_ci kunit_suite_counter++, 1118c2ecf20Sopenharmony_ci suite->name); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciunsigned int kunit_test_case_num(struct kunit_suite *suite, 1158c2ecf20Sopenharmony_ci struct kunit_case *test_case) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct kunit_case *tc; 1188c2ecf20Sopenharmony_ci unsigned int i = 1; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci kunit_suite_for_each_test_case(suite, tc) { 1218c2ecf20Sopenharmony_ci if (tc == test_case) 1228c2ecf20Sopenharmony_ci return i; 1238c2ecf20Sopenharmony_ci i++; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_test_case_num); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void kunit_print_string_stream(struct kunit *test, 1318c2ecf20Sopenharmony_ci struct string_stream *stream) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct string_stream_fragment *fragment; 1348c2ecf20Sopenharmony_ci char *buf; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (string_stream_is_empty(stream)) 1378c2ecf20Sopenharmony_ci return; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci buf = string_stream_get_string(stream); 1408c2ecf20Sopenharmony_ci if (!buf) { 1418c2ecf20Sopenharmony_ci kunit_err(test, 1428c2ecf20Sopenharmony_ci "Could not allocate buffer, dumping stream:\n"); 1438c2ecf20Sopenharmony_ci list_for_each_entry(fragment, &stream->fragments, node) { 1448c2ecf20Sopenharmony_ci kunit_err(test, "%s", fragment->fragment); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci kunit_err(test, "\n"); 1478c2ecf20Sopenharmony_ci } else { 1488c2ecf20Sopenharmony_ci kunit_err(test, "%s", buf); 1498c2ecf20Sopenharmony_ci kunit_kfree(test, buf); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void kunit_fail(struct kunit *test, struct kunit_assert *assert) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct string_stream *stream; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci kunit_set_failure(test); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci stream = alloc_string_stream(test, GFP_KERNEL); 1608c2ecf20Sopenharmony_ci if (!stream) { 1618c2ecf20Sopenharmony_ci WARN(true, 1628c2ecf20Sopenharmony_ci "Could not allocate stream to print failed assertion in %s:%d\n", 1638c2ecf20Sopenharmony_ci assert->file, 1648c2ecf20Sopenharmony_ci assert->line); 1658c2ecf20Sopenharmony_ci return; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci assert->format(assert, stream); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci kunit_print_string_stream(test, stream); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci WARN_ON(string_stream_destroy(stream)); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void __noreturn kunit_abort(struct kunit *test) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci kunit_try_catch_throw(&test->try_catch); /* Does not return. */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * Throw could not abort from test. 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * XXX: we should never reach this line! As kunit_try_catch_throw is 1838c2ecf20Sopenharmony_ci * marked __noreturn. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci WARN_ONCE(true, "Throw could not abort from test!\n"); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_civoid kunit_do_assertion(struct kunit *test, 1898c2ecf20Sopenharmony_ci struct kunit_assert *assert, 1908c2ecf20Sopenharmony_ci bool pass, 1918c2ecf20Sopenharmony_ci const char *fmt, ...) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci va_list args; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (pass) 1968c2ecf20Sopenharmony_ci return; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci va_start(args, fmt); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci assert->message.fmt = fmt; 2018c2ecf20Sopenharmony_ci assert->message.va = &args; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci kunit_fail(test, assert); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci va_end(args); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (assert->type == KUNIT_ASSERTION) 2088c2ecf20Sopenharmony_ci kunit_abort(test); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_do_assertion); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_civoid kunit_init_test(struct kunit *test, const char *name, char *log) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci spin_lock_init(&test->lock); 2158c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&test->resources); 2168c2ecf20Sopenharmony_ci test->name = name; 2178c2ecf20Sopenharmony_ci test->log = log; 2188c2ecf20Sopenharmony_ci if (test->log) 2198c2ecf20Sopenharmony_ci test->log[0] = '\0'; 2208c2ecf20Sopenharmony_ci test->success = true; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_init_test); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* 2258c2ecf20Sopenharmony_ci * Initializes and runs test case. Does not clean up or do post validations. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic void kunit_run_case_internal(struct kunit *test, 2288c2ecf20Sopenharmony_ci struct kunit_suite *suite, 2298c2ecf20Sopenharmony_ci struct kunit_case *test_case) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci if (suite->init) { 2328c2ecf20Sopenharmony_ci int ret; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ret = suite->init(test); 2358c2ecf20Sopenharmony_ci if (ret) { 2368c2ecf20Sopenharmony_ci kunit_err(test, "failed to initialize: %d\n", ret); 2378c2ecf20Sopenharmony_ci kunit_set_failure(test); 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci test_case->run_case(test); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void kunit_case_internal_cleanup(struct kunit *test) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci kunit_cleanup(test); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* 2518c2ecf20Sopenharmony_ci * Performs post validations and cleanup after a test case was run. 2528c2ecf20Sopenharmony_ci * XXX: Should ONLY BE CALLED AFTER kunit_run_case_internal! 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_cistatic void kunit_run_case_cleanup(struct kunit *test, 2558c2ecf20Sopenharmony_ci struct kunit_suite *suite) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci if (suite->exit) 2588c2ecf20Sopenharmony_ci suite->exit(test); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci kunit_case_internal_cleanup(test); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistruct kunit_try_catch_context { 2648c2ecf20Sopenharmony_ci struct kunit *test; 2658c2ecf20Sopenharmony_ci struct kunit_suite *suite; 2668c2ecf20Sopenharmony_ci struct kunit_case *test_case; 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void kunit_try_run_case(void *data) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct kunit_try_catch_context *ctx = data; 2728c2ecf20Sopenharmony_ci struct kunit *test = ctx->test; 2738c2ecf20Sopenharmony_ci struct kunit_suite *suite = ctx->suite; 2748c2ecf20Sopenharmony_ci struct kunit_case *test_case = ctx->test_case; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci#if (IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT)) 2778c2ecf20Sopenharmony_ci current->kunit_test = test; 2788c2ecf20Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT) */ 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * kunit_run_case_internal may encounter a fatal error; if it does, 2828c2ecf20Sopenharmony_ci * abort will be called, this thread will exit, and finally the parent 2838c2ecf20Sopenharmony_ci * thread will resume control and handle any necessary clean up. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci kunit_run_case_internal(test, suite, test_case); 2868c2ecf20Sopenharmony_ci /* This line may never be reached. */ 2878c2ecf20Sopenharmony_ci kunit_run_case_cleanup(test, suite); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void kunit_catch_run_case(void *data) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct kunit_try_catch_context *ctx = data; 2938c2ecf20Sopenharmony_ci struct kunit *test = ctx->test; 2948c2ecf20Sopenharmony_ci struct kunit_suite *suite = ctx->suite; 2958c2ecf20Sopenharmony_ci int try_exit_code = kunit_try_catch_get_result(&test->try_catch); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (try_exit_code) { 2988c2ecf20Sopenharmony_ci kunit_set_failure(test); 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * Test case could not finish, we have no idea what state it is 3018c2ecf20Sopenharmony_ci * in, so don't do clean up. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci if (try_exit_code == -ETIMEDOUT) { 3048c2ecf20Sopenharmony_ci kunit_err(test, "test case timed out\n"); 3058c2ecf20Sopenharmony_ci /* 3068c2ecf20Sopenharmony_ci * Unknown internal error occurred preventing test case from 3078c2ecf20Sopenharmony_ci * running, so there is nothing to clean up. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci } else { 3108c2ecf20Sopenharmony_ci kunit_err(test, "internal error occurred preventing test case from running: %d\n", 3118c2ecf20Sopenharmony_ci try_exit_code); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci return; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* 3178c2ecf20Sopenharmony_ci * Test case was run, but aborted. It is the test case's business as to 3188c2ecf20Sopenharmony_ci * whether it failed or not, we just need to clean up. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ci kunit_run_case_cleanup(test, suite); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* 3248c2ecf20Sopenharmony_ci * Performs all logic to run a test case. It also catches most errors that 3258c2ecf20Sopenharmony_ci * occur in a test case and reports them as failures. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_cistatic void kunit_run_case_catch_errors(struct kunit_suite *suite, 3288c2ecf20Sopenharmony_ci struct kunit_case *test_case) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct kunit_try_catch_context context; 3318c2ecf20Sopenharmony_ci struct kunit_try_catch *try_catch; 3328c2ecf20Sopenharmony_ci struct kunit test; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci kunit_init_test(&test, test_case->name, test_case->log); 3358c2ecf20Sopenharmony_ci try_catch = &test.try_catch; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci kunit_try_catch_init(try_catch, 3388c2ecf20Sopenharmony_ci &test, 3398c2ecf20Sopenharmony_ci kunit_try_run_case, 3408c2ecf20Sopenharmony_ci kunit_catch_run_case); 3418c2ecf20Sopenharmony_ci context.test = &test; 3428c2ecf20Sopenharmony_ci context.suite = suite; 3438c2ecf20Sopenharmony_ci context.test_case = test_case; 3448c2ecf20Sopenharmony_ci kunit_try_catch_run(try_catch, &context); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci test_case->success = test.success; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci kunit_print_ok_not_ok(&test, true, test_case->success, 3498c2ecf20Sopenharmony_ci kunit_test_case_num(suite, test_case), 3508c2ecf20Sopenharmony_ci test_case->name); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ciint kunit_run_tests(struct kunit_suite *suite) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct kunit_case *test_case; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci kunit_print_subtest_start(suite); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci kunit_suite_for_each_test_case(suite, test_case) 3608c2ecf20Sopenharmony_ci kunit_run_case_catch_errors(suite, test_case); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci kunit_print_subtest_end(suite); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_run_tests); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void kunit_init_suite(struct kunit_suite *suite) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci kunit_debugfs_create_suite(suite); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ciint __kunit_test_suites_init(struct kunit_suite * const * const suites) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci unsigned int i; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci for (i = 0; suites[i] != NULL; i++) { 3788c2ecf20Sopenharmony_ci kunit_init_suite(suites[i]); 3798c2ecf20Sopenharmony_ci kunit_run_tests(suites[i]); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__kunit_test_suites_init); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic void kunit_exit_suite(struct kunit_suite *suite) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci kunit_debugfs_destroy_suite(suite); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_civoid __kunit_test_suites_exit(struct kunit_suite **suites) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci unsigned int i; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci for (i = 0; suites[i] != NULL; i++) 3958c2ecf20Sopenharmony_ci kunit_exit_suite(suites[i]); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__kunit_test_suites_exit); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/* 4008c2ecf20Sopenharmony_ci * Used for static resources and when a kunit_resource * has been created by 4018c2ecf20Sopenharmony_ci * kunit_alloc_resource(). When an init function is supplied, @data is passed 4028c2ecf20Sopenharmony_ci * into the init function; otherwise, we simply set the resource data field to 4038c2ecf20Sopenharmony_ci * the data value passed in. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ciint kunit_add_resource(struct kunit *test, 4068c2ecf20Sopenharmony_ci kunit_resource_init_t init, 4078c2ecf20Sopenharmony_ci kunit_resource_free_t free, 4088c2ecf20Sopenharmony_ci struct kunit_resource *res, 4098c2ecf20Sopenharmony_ci void *data) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci int ret = 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci res->free = free; 4148c2ecf20Sopenharmony_ci kref_init(&res->refcount); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (init) { 4178c2ecf20Sopenharmony_ci ret = init(res, data); 4188c2ecf20Sopenharmony_ci if (ret) 4198c2ecf20Sopenharmony_ci return ret; 4208c2ecf20Sopenharmony_ci } else { 4218c2ecf20Sopenharmony_ci res->data = data; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci spin_lock(&test->lock); 4258c2ecf20Sopenharmony_ci list_add_tail(&res->node, &test->resources); 4268c2ecf20Sopenharmony_ci /* refcount for list is established by kref_init() */ 4278c2ecf20Sopenharmony_ci spin_unlock(&test->lock); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return ret; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_add_resource); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ciint kunit_add_named_resource(struct kunit *test, 4348c2ecf20Sopenharmony_ci kunit_resource_init_t init, 4358c2ecf20Sopenharmony_ci kunit_resource_free_t free, 4368c2ecf20Sopenharmony_ci struct kunit_resource *res, 4378c2ecf20Sopenharmony_ci const char *name, 4388c2ecf20Sopenharmony_ci void *data) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct kunit_resource *existing; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (!name) 4438c2ecf20Sopenharmony_ci return -EINVAL; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci existing = kunit_find_named_resource(test, name); 4468c2ecf20Sopenharmony_ci if (existing) { 4478c2ecf20Sopenharmony_ci kunit_put_resource(existing); 4488c2ecf20Sopenharmony_ci return -EEXIST; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci res->name = name; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return kunit_add_resource(test, init, free, res, data); 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_add_named_resource); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistruct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test, 4588c2ecf20Sopenharmony_ci kunit_resource_init_t init, 4598c2ecf20Sopenharmony_ci kunit_resource_free_t free, 4608c2ecf20Sopenharmony_ci gfp_t internal_gfp, 4618c2ecf20Sopenharmony_ci void *data) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct kunit_resource *res; 4648c2ecf20Sopenharmony_ci int ret; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci res = kzalloc(sizeof(*res), internal_gfp); 4678c2ecf20Sopenharmony_ci if (!res) 4688c2ecf20Sopenharmony_ci return NULL; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ret = kunit_add_resource(test, init, free, res, data); 4718c2ecf20Sopenharmony_ci if (!ret) { 4728c2ecf20Sopenharmony_ci /* 4738c2ecf20Sopenharmony_ci * bump refcount for get; kunit_resource_put() should be called 4748c2ecf20Sopenharmony_ci * when done. 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci kunit_get_resource(res); 4778c2ecf20Sopenharmony_ci return res; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci return NULL; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_alloc_and_get_resource); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_civoid kunit_remove_resource(struct kunit *test, struct kunit_resource *res) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci spin_lock(&test->lock); 4868c2ecf20Sopenharmony_ci list_del(&res->node); 4878c2ecf20Sopenharmony_ci spin_unlock(&test->lock); 4888c2ecf20Sopenharmony_ci kunit_put_resource(res); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_remove_resource); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ciint kunit_destroy_resource(struct kunit *test, kunit_resource_match_t match, 4938c2ecf20Sopenharmony_ci void *match_data) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct kunit_resource *res = kunit_find_resource(test, match, 4968c2ecf20Sopenharmony_ci match_data); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (!res) 4998c2ecf20Sopenharmony_ci return -ENOENT; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci kunit_remove_resource(test, res); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* We have a reference also via _find(); drop it. */ 5048c2ecf20Sopenharmony_ci kunit_put_resource(res); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_destroy_resource); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistruct kunit_kmalloc_params { 5118c2ecf20Sopenharmony_ci size_t size; 5128c2ecf20Sopenharmony_ci gfp_t gfp; 5138c2ecf20Sopenharmony_ci}; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int kunit_kmalloc_init(struct kunit_resource *res, void *context) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct kunit_kmalloc_params *params = context; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci res->data = kmalloc(params->size, params->gfp); 5208c2ecf20Sopenharmony_ci if (!res->data) 5218c2ecf20Sopenharmony_ci return -ENOMEM; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return 0; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic void kunit_kmalloc_free(struct kunit_resource *res) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci kfree(res->data); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_civoid *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct kunit_kmalloc_params params = { 5348c2ecf20Sopenharmony_ci .size = size, 5358c2ecf20Sopenharmony_ci .gfp = gfp 5368c2ecf20Sopenharmony_ci }; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return kunit_alloc_resource(test, 5398c2ecf20Sopenharmony_ci kunit_kmalloc_init, 5408c2ecf20Sopenharmony_ci kunit_kmalloc_free, 5418c2ecf20Sopenharmony_ci gfp, 5428c2ecf20Sopenharmony_ci ¶ms); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_kmalloc); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_civoid kunit_kfree(struct kunit *test, const void *ptr) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct kunit_resource *res; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci res = kunit_find_resource(test, kunit_resource_instance_match, 5518c2ecf20Sopenharmony_ci (void *)ptr); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* 5548c2ecf20Sopenharmony_ci * Removing the resource from the list of resources drops the 5558c2ecf20Sopenharmony_ci * reference count to 1; the final put will trigger the free. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_ci kunit_remove_resource(test, res); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci kunit_put_resource(res); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_kfree); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_civoid kunit_cleanup(struct kunit *test) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct kunit_resource *res; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* 5698c2ecf20Sopenharmony_ci * test->resources is a stack - each allocation must be freed in the 5708c2ecf20Sopenharmony_ci * reverse order from which it was added since one resource may depend 5718c2ecf20Sopenharmony_ci * on another for its entire lifetime. 5728c2ecf20Sopenharmony_ci * Also, we cannot use the normal list_for_each constructs, even the 5738c2ecf20Sopenharmony_ci * safe ones because *arbitrary* nodes may be deleted when 5748c2ecf20Sopenharmony_ci * kunit_resource_free is called; the list_for_each_safe variants only 5758c2ecf20Sopenharmony_ci * protect against the current node being deleted, not the next. 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_ci while (true) { 5788c2ecf20Sopenharmony_ci spin_lock(&test->lock); 5798c2ecf20Sopenharmony_ci if (list_empty(&test->resources)) { 5808c2ecf20Sopenharmony_ci spin_unlock(&test->lock); 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci res = list_last_entry(&test->resources, 5848c2ecf20Sopenharmony_ci struct kunit_resource, 5858c2ecf20Sopenharmony_ci node); 5868c2ecf20Sopenharmony_ci /* 5878c2ecf20Sopenharmony_ci * Need to unlock here as a resource may remove another 5888c2ecf20Sopenharmony_ci * resource, and this can't happen if the test->lock 5898c2ecf20Sopenharmony_ci * is held. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci spin_unlock(&test->lock); 5928c2ecf20Sopenharmony_ci kunit_remove_resource(test, res); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci#if (IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT)) 5958c2ecf20Sopenharmony_ci current->kunit_test = NULL; 5968c2ecf20Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT)*/ 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_cleanup); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic int __init kunit_init(void) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci kunit_debugfs_init(); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_cilate_initcall(kunit_init); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic void __exit kunit_exit(void) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci kunit_debugfs_cleanup(); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_cimodule_exit(kunit_exit); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 615