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				    &params);
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