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(&param_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(&param_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(&param_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