1914cc63eSBrendan Higgins // SPDX-License-Identifier: GPL-2.0
2914cc63eSBrendan Higgins /*
3914cc63eSBrendan Higgins * Base unit test (KUnit) API.
4914cc63eSBrendan Higgins *
5914cc63eSBrendan Higgins * Copyright (C) 2019, Google LLC.
6914cc63eSBrendan Higgins * Author: Brendan Higgins <brendanhiggins@google.com>
7914cc63eSBrendan Higgins */
8914cc63eSBrendan Higgins
9cdebea69SDaniel Latypov #include <kunit/resource.h>
10914cc63eSBrendan Higgins #include <kunit/test.h>
11359a3760SUriel Guajardo #include <kunit/test-bug.h>
1239e92cb1SRae Moar #include <kunit/attributes.h>
13914cc63eSBrendan Higgins #include <linux/kernel.h>
143d6e4462SJeremy Kerr #include <linux/module.h>
15acd8e840SDavid Gow #include <linux/moduleparam.h>
16c272612cSDavid Gow #include <linux/panic.h>
175f3e0620SBrendan Higgins #include <linux/sched/debug.h>
1883c4e7a0SPatricia Alfonso #include <linux/sched.h>
19*8e4319a4SMarco Pagani #include <linux/mm.h>
20914cc63eSBrendan Higgins
21e2219db2SAlan Maguire #include "debugfs.h"
227170b7edSDavid Gow #include "hooks-impl.h"
23109fb06fSAlan Maguire #include "string-stream.h"
249bbb11c6SAlan Maguire #include "try-catch-impl.h"
25109fb06fSAlan Maguire
26359a3760SUriel Guajardo /*
277170b7edSDavid Gow * Hook to fail the current test and print an error message to the log.
28359a3760SUriel Guajardo */
__kunit_fail_current_test_impl(const char * file,int line,const char * fmt,...)2982649c7cSDavid Gow void __printf(3, 4) __kunit_fail_current_test_impl(const char *file, int line, const char *fmt, ...)
30359a3760SUriel Guajardo {
31359a3760SUriel Guajardo va_list args;
32359a3760SUriel Guajardo int len;
33359a3760SUriel Guajardo char *buffer;
34359a3760SUriel Guajardo
35359a3760SUriel Guajardo if (!current->kunit_test)
36359a3760SUriel Guajardo return;
37359a3760SUriel Guajardo
38359a3760SUriel Guajardo kunit_set_failure(current->kunit_test);
39359a3760SUriel Guajardo
40359a3760SUriel Guajardo /* kunit_err() only accepts literals, so evaluate the args first. */
41359a3760SUriel Guajardo va_start(args, fmt);
42359a3760SUriel Guajardo len = vsnprintf(NULL, 0, fmt, args) + 1;
43359a3760SUriel Guajardo va_end(args);
44359a3760SUriel Guajardo
45359a3760SUriel Guajardo buffer = kunit_kmalloc(current->kunit_test, len, GFP_KERNEL);
46359a3760SUriel Guajardo if (!buffer)
47359a3760SUriel Guajardo return;
48359a3760SUriel Guajardo
49359a3760SUriel Guajardo va_start(args, fmt);
50359a3760SUriel Guajardo vsnprintf(buffer, len, fmt, args);
51359a3760SUriel Guajardo va_end(args);
52359a3760SUriel Guajardo
53359a3760SUriel Guajardo kunit_err(current->kunit_test, "%s:%d: %s", file, line, buffer);
54359a3760SUriel Guajardo kunit_kfree(current->kunit_test, buffer);
55359a3760SUriel Guajardo }
56359a3760SUriel Guajardo
57e2219db2SAlan Maguire /*
58d20a6ba5SJoe Fradley * Enable KUnit tests to run.
59d20a6ba5SJoe Fradley */
60d20a6ba5SJoe Fradley #ifdef CONFIG_KUNIT_DEFAULT_ENABLED
61d20a6ba5SJoe Fradley static bool enable_param = true;
62d20a6ba5SJoe Fradley #else
63d20a6ba5SJoe Fradley static bool enable_param;
64d20a6ba5SJoe Fradley #endif
65d20a6ba5SJoe Fradley module_param_named(enable, enable_param, bool, 0);
66d20a6ba5SJoe Fradley MODULE_PARM_DESC(enable, "Enable KUnit tests");
67d20a6ba5SJoe Fradley
68d20a6ba5SJoe Fradley /*
69acd8e840SDavid Gow * KUnit statistic mode:
70acd8e840SDavid Gow * 0 - disabled
71acd8e840SDavid Gow * 1 - only when there is more than one subtest
72acd8e840SDavid Gow * 2 - enabled
73acd8e840SDavid Gow */
74acd8e840SDavid Gow static int kunit_stats_enabled = 1;
75acd8e840SDavid Gow module_param_named(stats_enabled, kunit_stats_enabled, int, 0644);
76acd8e840SDavid Gow MODULE_PARM_DESC(stats_enabled,
77acd8e840SDavid Gow "Print test stats: never (0), only for multiple subtests (1), or always (2)");
78acd8e840SDavid Gow
79acd8e840SDavid Gow struct kunit_result_stats {
80acd8e840SDavid Gow unsigned long passed;
81acd8e840SDavid Gow unsigned long skipped;
82acd8e840SDavid Gow unsigned long failed;
83acd8e840SDavid Gow unsigned long total;
84acd8e840SDavid Gow };
85acd8e840SDavid Gow
kunit_should_print_stats(struct kunit_result_stats stats)86acd8e840SDavid Gow static bool kunit_should_print_stats(struct kunit_result_stats stats)
87acd8e840SDavid Gow {
88acd8e840SDavid Gow if (kunit_stats_enabled == 0)
89acd8e840SDavid Gow return false;
90acd8e840SDavid Gow
91acd8e840SDavid Gow if (kunit_stats_enabled == 2)
92acd8e840SDavid Gow return true;
93acd8e840SDavid Gow
94acd8e840SDavid Gow return (stats.total > 1);
95acd8e840SDavid Gow }
96acd8e840SDavid Gow
kunit_print_test_stats(struct kunit * test,struct kunit_result_stats stats)97acd8e840SDavid Gow static void kunit_print_test_stats(struct kunit *test,
98acd8e840SDavid Gow struct kunit_result_stats stats)
99acd8e840SDavid Gow {
100acd8e840SDavid Gow if (!kunit_should_print_stats(stats))
101acd8e840SDavid Gow return;
102acd8e840SDavid Gow
103acd8e840SDavid Gow kunit_log(KERN_INFO, test,
104acd8e840SDavid Gow KUNIT_SUBTEST_INDENT
105acd8e840SDavid Gow "# %s: pass:%lu fail:%lu skip:%lu total:%lu",
106acd8e840SDavid Gow test->name,
107acd8e840SDavid Gow stats.passed,
108acd8e840SDavid Gow stats.failed,
109acd8e840SDavid Gow stats.skipped,
110acd8e840SDavid Gow stats.total);
111acd8e840SDavid Gow }
112acd8e840SDavid Gow
1132c6a96daSRae Moar /**
1142c6a96daSRae Moar * kunit_log_newline() - Add newline to the end of log if one is not
1152c6a96daSRae Moar * already present.
1162c6a96daSRae Moar * @log: The log to add the newline to.
1172c6a96daSRae Moar */
kunit_log_newline(char * log)1182c6a96daSRae Moar static void kunit_log_newline(char *log)
1192c6a96daSRae Moar {
1202c6a96daSRae Moar int log_len, len_left;
1212c6a96daSRae Moar
1222c6a96daSRae Moar log_len = strlen(log);
1232c6a96daSRae Moar len_left = KUNIT_LOG_SIZE - log_len - 1;
1242c6a96daSRae Moar
1252c6a96daSRae Moar if (log_len > 0 && log[log_len - 1] != '\n')
1262c6a96daSRae Moar strncat(log, "\n", len_left);
1272c6a96daSRae Moar }
1282c6a96daSRae Moar
129acd8e840SDavid Gow /*
130e2219db2SAlan Maguire * Append formatted message to log, size of which is limited to
131e2219db2SAlan Maguire * KUNIT_LOG_SIZE bytes (including null terminating byte).
132e2219db2SAlan Maguire */
kunit_log_append(char * log,const char * fmt,...)133e2219db2SAlan Maguire void kunit_log_append(char *log, const char *fmt, ...)
134e2219db2SAlan Maguire {
135e2219db2SAlan Maguire va_list args;
136887d85a0SRae Moar int len, log_len, len_left;
137e2219db2SAlan Maguire
138e2219db2SAlan Maguire if (!log)
139e2219db2SAlan Maguire return;
140e2219db2SAlan Maguire
141887d85a0SRae Moar log_len = strlen(log);
142887d85a0SRae Moar len_left = KUNIT_LOG_SIZE - log_len - 1;
143e2219db2SAlan Maguire if (len_left <= 0)
144e2219db2SAlan Maguire return;
145e2219db2SAlan Maguire
146887d85a0SRae Moar /* Evaluate length of line to add to log */
147e2219db2SAlan Maguire va_start(args, fmt);
148887d85a0SRae Moar len = vsnprintf(NULL, 0, fmt, args) + 1;
149e2219db2SAlan Maguire va_end(args);
150e2219db2SAlan Maguire
151887d85a0SRae Moar /* Print formatted line to the log */
152887d85a0SRae Moar va_start(args, fmt);
153887d85a0SRae Moar vsnprintf(log + log_len, min(len, len_left), fmt, args);
154887d85a0SRae Moar va_end(args);
155887d85a0SRae Moar
1562c6a96daSRae Moar /* Add newline to end of log if not already present. */
1572c6a96daSRae Moar kunit_log_newline(log);
158e2219db2SAlan Maguire }
159e2219db2SAlan Maguire EXPORT_SYMBOL_GPL(kunit_log_append);
160e2219db2SAlan Maguire
kunit_suite_num_test_cases(struct kunit_suite * suite)161e2219db2SAlan Maguire size_t kunit_suite_num_test_cases(struct kunit_suite *suite)
162914cc63eSBrendan Higgins {
163914cc63eSBrendan Higgins struct kunit_case *test_case;
164914cc63eSBrendan Higgins size_t len = 0;
165914cc63eSBrendan Higgins
166e2219db2SAlan Maguire kunit_suite_for_each_test_case(suite, test_case)
167914cc63eSBrendan Higgins len++;
168914cc63eSBrendan Higgins
169914cc63eSBrendan Higgins return len;
170914cc63eSBrendan Higgins }
171e2219db2SAlan Maguire EXPORT_SYMBOL_GPL(kunit_suite_num_test_cases);
172914cc63eSBrendan Higgins
17339e92cb1SRae Moar /* Currently supported test levels */
17439e92cb1SRae Moar enum {
17539e92cb1SRae Moar KUNIT_LEVEL_SUITE = 0,
17639e92cb1SRae Moar KUNIT_LEVEL_CASE,
17739e92cb1SRae Moar KUNIT_LEVEL_CASE_PARAM,
17839e92cb1SRae Moar };
17939e92cb1SRae Moar
kunit_print_suite_start(struct kunit_suite * suite)180cae56e17SDaniel Latypov static void kunit_print_suite_start(struct kunit_suite *suite)
181914cc63eSBrendan Higgins {
182f9a301c3SRae Moar /*
183f9a301c3SRae Moar * We do not log the test suite header as doing so would
184f9a301c3SRae Moar * mean debugfs display would consist of the test suite
185f9a301c3SRae Moar * header prior to individual test results.
186f9a301c3SRae Moar * Hence directly printk the suite status, and we will
187f9a301c3SRae Moar * separately seq_printf() the suite header for the debugfs
188f9a301c3SRae Moar * representation.
189f9a301c3SRae Moar */
190f9a301c3SRae Moar pr_info(KUNIT_SUBTEST_INDENT "KTAP version 1\n");
191f9a301c3SRae Moar pr_info(KUNIT_SUBTEST_INDENT "# Subtest: %s\n",
192c3bba690SAlan Maguire suite->name);
19339e92cb1SRae Moar kunit_print_attr((void *)suite, false, KUNIT_LEVEL_CASE);
194f9a301c3SRae Moar pr_info(KUNIT_SUBTEST_INDENT "1..%zd\n",
195e2219db2SAlan Maguire kunit_suite_num_test_cases(suite));
196914cc63eSBrendan Higgins }
197914cc63eSBrendan Higgins
kunit_print_ok_not_ok(struct kunit * test,unsigned int test_level,enum kunit_status status,size_t test_number,const char * description,const char * directive)198b1eaa8b2SMichal Wajdeczko static void kunit_print_ok_not_ok(struct kunit *test,
199b1eaa8b2SMichal Wajdeczko unsigned int test_level,
2006d2426b2SDavid Gow enum kunit_status status,
201914cc63eSBrendan Higgins size_t test_number,
2026d2426b2SDavid Gow const char *description,
2036d2426b2SDavid Gow const char *directive)
204914cc63eSBrendan Higgins {
2056d2426b2SDavid Gow const char *directive_header = (status == KUNIT_SKIPPED) ? " # SKIP " : "";
206b1eaa8b2SMichal Wajdeczko const char *directive_body = (status == KUNIT_SKIPPED) ? directive : "";
207b1eaa8b2SMichal Wajdeczko
208b1eaa8b2SMichal Wajdeczko /*
209b1eaa8b2SMichal Wajdeczko * When test is NULL assume that results are from the suite
210b1eaa8b2SMichal Wajdeczko * and today suite results are expected at level 0 only.
211b1eaa8b2SMichal Wajdeczko */
212b1eaa8b2SMichal Wajdeczko WARN(!test && test_level, "suite test level can't be %u!\n", test_level);
213914cc63eSBrendan Higgins
214e2219db2SAlan Maguire /*
215e2219db2SAlan Maguire * We do not log the test suite results as doing so would
216f9a301c3SRae Moar * mean debugfs display would consist of an incorrect test
217f9a301c3SRae Moar * number. Hence directly printk the suite result, and we will
218f9a301c3SRae Moar * separately seq_printf() the suite results for the debugfs
219e2219db2SAlan Maguire * representation.
220e2219db2SAlan Maguire */
221b1eaa8b2SMichal Wajdeczko if (!test)
2226c738b52SRae Moar pr_info("%s %zd %s%s%s\n",
2236d2426b2SDavid Gow kunit_status_to_ok_not_ok(status),
2246d2426b2SDavid Gow test_number, description, directive_header,
225b1eaa8b2SMichal Wajdeczko directive_body);
226914cc63eSBrendan Higgins else
2276d2426b2SDavid Gow kunit_log(KERN_INFO, test,
228b1eaa8b2SMichal Wajdeczko "%*s%s %zd %s%s%s",
229b1eaa8b2SMichal Wajdeczko KUNIT_INDENT_LEN * test_level, "",
2306d2426b2SDavid Gow kunit_status_to_ok_not_ok(status),
2316d2426b2SDavid Gow test_number, description, directive_header,
232b1eaa8b2SMichal Wajdeczko directive_body);
233914cc63eSBrendan Higgins }
234914cc63eSBrendan Higgins
kunit_suite_has_succeeded(struct kunit_suite * suite)2356d2426b2SDavid Gow enum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite)
236914cc63eSBrendan Higgins {
237914cc63eSBrendan Higgins const struct kunit_case *test_case;
2386d2426b2SDavid Gow enum kunit_status status = KUNIT_SKIPPED;
239914cc63eSBrendan Higgins
2401cdba21dSDaniel Latypov if (suite->suite_init_err)
2411cdba21dSDaniel Latypov return KUNIT_FAILURE;
2421cdba21dSDaniel Latypov
243e2219db2SAlan Maguire kunit_suite_for_each_test_case(suite, test_case) {
2446d2426b2SDavid Gow if (test_case->status == KUNIT_FAILURE)
2456d2426b2SDavid Gow return KUNIT_FAILURE;
2466d2426b2SDavid Gow else if (test_case->status == KUNIT_SUCCESS)
2476d2426b2SDavid Gow status = KUNIT_SUCCESS;
248e2219db2SAlan Maguire }
249914cc63eSBrendan Higgins
2506d2426b2SDavid Gow return status;
251914cc63eSBrendan Higgins }
252e2219db2SAlan Maguire EXPORT_SYMBOL_GPL(kunit_suite_has_succeeded);
253914cc63eSBrendan Higgins
254914cc63eSBrendan Higgins static size_t kunit_suite_counter = 1;
255914cc63eSBrendan Higgins
kunit_print_suite_end(struct kunit_suite * suite)256cae56e17SDaniel Latypov static void kunit_print_suite_end(struct kunit_suite *suite)
25717ac23ebSDavid Gow {
258b1eaa8b2SMichal Wajdeczko kunit_print_ok_not_ok(NULL, KUNIT_LEVEL_SUITE,
259914cc63eSBrendan Higgins kunit_suite_has_succeeded(suite),
260914cc63eSBrendan Higgins kunit_suite_counter++,
2616d2426b2SDavid Gow suite->name,
2626d2426b2SDavid Gow suite->status_comment);
263914cc63eSBrendan Higgins }
264914cc63eSBrendan Higgins
kunit_test_case_num(struct kunit_suite * suite,struct kunit_case * test_case)265e2219db2SAlan Maguire unsigned int kunit_test_case_num(struct kunit_suite *suite,
266e2219db2SAlan Maguire struct kunit_case *test_case)
267914cc63eSBrendan Higgins {
268e2219db2SAlan Maguire struct kunit_case *tc;
269e2219db2SAlan Maguire unsigned int i = 1;
270e2219db2SAlan Maguire
271e2219db2SAlan Maguire kunit_suite_for_each_test_case(suite, tc) {
272e2219db2SAlan Maguire if (tc == test_case)
273e2219db2SAlan Maguire return i;
274e2219db2SAlan Maguire i++;
275914cc63eSBrendan Higgins }
276914cc63eSBrendan Higgins
277e2219db2SAlan Maguire return 0;
278e2219db2SAlan Maguire }
279e2219db2SAlan Maguire EXPORT_SYMBOL_GPL(kunit_test_case_num);
280e2219db2SAlan Maguire
kunit_print_string_stream(struct kunit * test,struct string_stream * stream)28173cda7bbSBrendan Higgins static void kunit_print_string_stream(struct kunit *test,
28273cda7bbSBrendan Higgins struct string_stream *stream)
28373cda7bbSBrendan Higgins {
28473cda7bbSBrendan Higgins struct string_stream_fragment *fragment;
28573cda7bbSBrendan Higgins char *buf;
28673cda7bbSBrendan Higgins
287e2219db2SAlan Maguire if (string_stream_is_empty(stream))
288e2219db2SAlan Maguire return;
289e2219db2SAlan Maguire
29073cda7bbSBrendan Higgins buf = string_stream_get_string(stream);
29173cda7bbSBrendan Higgins if (!buf) {
29273cda7bbSBrendan Higgins kunit_err(test,
29373cda7bbSBrendan Higgins "Could not allocate buffer, dumping stream:\n");
29473cda7bbSBrendan Higgins list_for_each_entry(fragment, &stream->fragments, node) {
295741a98d0SBrendan Higgins kunit_err(test, "%s", fragment->fragment);
29673cda7bbSBrendan Higgins }
29773cda7bbSBrendan Higgins kunit_err(test, "\n");
29873cda7bbSBrendan Higgins } else {
299741a98d0SBrendan Higgins kunit_err(test, "%s", buf);
30073cda7bbSBrendan Higgins kunit_kfree(test, buf);
30173cda7bbSBrendan Higgins }
30273cda7bbSBrendan Higgins }
30373cda7bbSBrendan Higgins
kunit_fail(struct kunit * test,const struct kunit_loc * loc,enum kunit_assert_type type,const struct kunit_assert * assert,assert_format_t assert_format,const struct va_format * message)30421957f90SDaniel Latypov static void kunit_fail(struct kunit *test, const struct kunit_loc *loc,
3057466886bSMiguel Ojeda enum kunit_assert_type type, const struct kunit_assert *assert,
306a8495ad8SDaniel Latypov assert_format_t assert_format, const struct va_format *message)
30773cda7bbSBrendan Higgins {
30873cda7bbSBrendan Higgins struct string_stream *stream;
30973cda7bbSBrendan Higgins
31073cda7bbSBrendan Higgins kunit_set_failure(test);
31173cda7bbSBrendan Higgins
31273cda7bbSBrendan Higgins stream = alloc_string_stream(test, GFP_KERNEL);
31361888776SDan Carpenter if (IS_ERR(stream)) {
31473cda7bbSBrendan Higgins WARN(true,
31573cda7bbSBrendan Higgins "Could not allocate stream to print failed assertion in %s:%d\n",
31621957f90SDaniel Latypov loc->file,
31721957f90SDaniel Latypov loc->line);
31873cda7bbSBrendan Higgins return;
31973cda7bbSBrendan Higgins }
32073cda7bbSBrendan Higgins
32121957f90SDaniel Latypov kunit_assert_prologue(loc, type, stream);
322a8495ad8SDaniel Latypov assert_format(assert, message, stream);
32373cda7bbSBrendan Higgins
32473cda7bbSBrendan Higgins kunit_print_string_stream(test, stream);
32573cda7bbSBrendan Higgins
32678b1c658SDavid Gow string_stream_destroy(stream);
32773cda7bbSBrendan Higgins }
32873cda7bbSBrendan Higgins
__kunit_abort(struct kunit * test)32926075518SDavid Gow void __noreturn __kunit_abort(struct kunit *test)
3305f3e0620SBrendan Higgins {
3315f3e0620SBrendan Higgins kunit_try_catch_throw(&test->try_catch); /* Does not return. */
3325f3e0620SBrendan Higgins
3335f3e0620SBrendan Higgins /*
3345f3e0620SBrendan Higgins * Throw could not abort from test.
3355f3e0620SBrendan Higgins *
3365f3e0620SBrendan Higgins * XXX: we should never reach this line! As kunit_try_catch_throw is
3375f3e0620SBrendan Higgins * marked __noreturn.
3385f3e0620SBrendan Higgins */
3395f3e0620SBrendan Higgins WARN_ONCE(true, "Throw could not abort from test!\n");
3405f3e0620SBrendan Higgins }
34126075518SDavid Gow EXPORT_SYMBOL_GPL(__kunit_abort);
3425f3e0620SBrendan Higgins
__kunit_do_failed_assertion(struct kunit * test,const struct kunit_loc * loc,enum kunit_assert_type type,const struct kunit_assert * assert,assert_format_t assert_format,const char * fmt,...)34326075518SDavid Gow void __kunit_do_failed_assertion(struct kunit *test,
34421957f90SDaniel Latypov const struct kunit_loc *loc,
34521957f90SDaniel Latypov enum kunit_assert_type type,
3467466886bSMiguel Ojeda const struct kunit_assert *assert,
347a8495ad8SDaniel Latypov assert_format_t assert_format,
34873cda7bbSBrendan Higgins const char *fmt, ...)
34973cda7bbSBrendan Higgins {
35073cda7bbSBrendan Higgins va_list args;
3516419abb8SDaniel Latypov struct va_format message;
35273cda7bbSBrendan Higgins va_start(args, fmt);
35373cda7bbSBrendan Higgins
3546419abb8SDaniel Latypov message.fmt = fmt;
3556419abb8SDaniel Latypov message.va = &args;
35673cda7bbSBrendan Higgins
357a8495ad8SDaniel Latypov kunit_fail(test, loc, type, assert, assert_format, &message);
35873cda7bbSBrendan Higgins
35973cda7bbSBrendan Higgins va_end(args);
36073cda7bbSBrendan Higgins }
36126075518SDavid Gow EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion);
36273cda7bbSBrendan Higgins
kunit_init_test(struct kunit * test,const char * name,char * log)363e2219db2SAlan Maguire void kunit_init_test(struct kunit *test, const char *name, char *log)
364914cc63eSBrendan Higgins {
3650a756853SBrendan Higgins spin_lock_init(&test->lock);
3660a756853SBrendan Higgins INIT_LIST_HEAD(&test->resources);
367914cc63eSBrendan Higgins test->name = name;
368e2219db2SAlan Maguire test->log = log;
369e2219db2SAlan Maguire if (test->log)
370e2219db2SAlan Maguire test->log[0] = '\0';
3716d2426b2SDavid Gow test->status = KUNIT_SUCCESS;
3726d2426b2SDavid Gow test->status_comment[0] = '\0';
373914cc63eSBrendan Higgins }
374c475c77dSAlan Maguire EXPORT_SYMBOL_GPL(kunit_init_test);
375914cc63eSBrendan Higgins
376858c0840SMaxime Ripard /* Only warn when a test takes more than twice the threshold */
377858c0840SMaxime Ripard #define KUNIT_SPEED_WARNING_MULTIPLIER 2
378858c0840SMaxime Ripard
379858c0840SMaxime Ripard /* Slow tests are defined as taking more than 1s */
380858c0840SMaxime Ripard #define KUNIT_SPEED_SLOW_THRESHOLD_S 1
381858c0840SMaxime Ripard
382858c0840SMaxime Ripard #define KUNIT_SPEED_SLOW_WARNING_THRESHOLD_S \
383858c0840SMaxime Ripard (KUNIT_SPEED_WARNING_MULTIPLIER * KUNIT_SPEED_SLOW_THRESHOLD_S)
384858c0840SMaxime Ripard
385858c0840SMaxime Ripard #define s_to_timespec64(s) ns_to_timespec64((s) * NSEC_PER_SEC)
386858c0840SMaxime Ripard
kunit_run_case_check_speed(struct kunit * test,struct kunit_case * test_case,struct timespec64 duration)387858c0840SMaxime Ripard static void kunit_run_case_check_speed(struct kunit *test,
388858c0840SMaxime Ripard struct kunit_case *test_case,
389858c0840SMaxime Ripard struct timespec64 duration)
390858c0840SMaxime Ripard {
391858c0840SMaxime Ripard struct timespec64 slow_thr =
392858c0840SMaxime Ripard s_to_timespec64(KUNIT_SPEED_SLOW_WARNING_THRESHOLD_S);
393858c0840SMaxime Ripard enum kunit_speed speed = test_case->attr.speed;
394858c0840SMaxime Ripard
395858c0840SMaxime Ripard if (timespec64_compare(&duration, &slow_thr) < 0)
396858c0840SMaxime Ripard return;
397858c0840SMaxime Ripard
398858c0840SMaxime Ripard if (speed == KUNIT_SPEED_VERY_SLOW || speed == KUNIT_SPEED_SLOW)
399858c0840SMaxime Ripard return;
400858c0840SMaxime Ripard
401858c0840SMaxime Ripard kunit_warn(test,
402858c0840SMaxime Ripard "Test should be marked slow (runtime: %lld.%09lds)",
403858c0840SMaxime Ripard duration.tv_sec, duration.tv_nsec);
404858c0840SMaxime Ripard }
405858c0840SMaxime Ripard
406914cc63eSBrendan Higgins /*
4075f3e0620SBrendan Higgins * Initializes and runs test case. Does not clean up or do post validations.
408914cc63eSBrendan Higgins */
kunit_run_case_internal(struct kunit * test,struct kunit_suite * suite,struct kunit_case * test_case)4095f3e0620SBrendan Higgins static void kunit_run_case_internal(struct kunit *test,
4105f3e0620SBrendan Higgins struct kunit_suite *suite,
411914cc63eSBrendan Higgins struct kunit_case *test_case)
412914cc63eSBrendan Higgins {
413858c0840SMaxime Ripard struct timespec64 start, end;
414858c0840SMaxime Ripard
415914cc63eSBrendan Higgins if (suite->init) {
416914cc63eSBrendan Higgins int ret;
417914cc63eSBrendan Higgins
4185f3e0620SBrendan Higgins ret = suite->init(test);
419914cc63eSBrendan Higgins if (ret) {
4205f3e0620SBrendan Higgins kunit_err(test, "failed to initialize: %d\n", ret);
4215f3e0620SBrendan Higgins kunit_set_failure(test);
422914cc63eSBrendan Higgins return;
423914cc63eSBrendan Higgins }
424914cc63eSBrendan Higgins }
425914cc63eSBrendan Higgins
426858c0840SMaxime Ripard ktime_get_ts64(&start);
427858c0840SMaxime Ripard
4285f3e0620SBrendan Higgins test_case->run_case(test);
429858c0840SMaxime Ripard
430858c0840SMaxime Ripard ktime_get_ts64(&end);
431858c0840SMaxime Ripard
432858c0840SMaxime Ripard kunit_run_case_check_speed(test, test_case, timespec64_sub(end, start));
4335f3e0620SBrendan Higgins }
434914cc63eSBrendan Higgins
kunit_case_internal_cleanup(struct kunit * test)4355f3e0620SBrendan Higgins static void kunit_case_internal_cleanup(struct kunit *test)
4365f3e0620SBrendan Higgins {
4375f3e0620SBrendan Higgins kunit_cleanup(test);
4385f3e0620SBrendan Higgins }
4395f3e0620SBrendan Higgins
4405f3e0620SBrendan Higgins /*
4415f3e0620SBrendan Higgins * Performs post validations and cleanup after a test case was run.
4425f3e0620SBrendan Higgins * XXX: Should ONLY BE CALLED AFTER kunit_run_case_internal!
4435f3e0620SBrendan Higgins */
kunit_run_case_cleanup(struct kunit * test,struct kunit_suite * suite)4445f3e0620SBrendan Higgins static void kunit_run_case_cleanup(struct kunit *test,
4455f3e0620SBrendan Higgins struct kunit_suite *suite)
4465f3e0620SBrendan Higgins {
447914cc63eSBrendan Higgins if (suite->exit)
4485f3e0620SBrendan Higgins suite->exit(test);
449914cc63eSBrendan Higgins
4505f3e0620SBrendan Higgins kunit_case_internal_cleanup(test);
4515f3e0620SBrendan Higgins }
4525f3e0620SBrendan Higgins
4535f3e0620SBrendan Higgins struct kunit_try_catch_context {
4545f3e0620SBrendan Higgins struct kunit *test;
4555f3e0620SBrendan Higgins struct kunit_suite *suite;
4565f3e0620SBrendan Higgins struct kunit_case *test_case;
4575f3e0620SBrendan Higgins };
4585f3e0620SBrendan Higgins
kunit_try_run_case(void * data)4595f3e0620SBrendan Higgins static void kunit_try_run_case(void *data)
4605f3e0620SBrendan Higgins {
4615f3e0620SBrendan Higgins struct kunit_try_catch_context *ctx = data;
4625f3e0620SBrendan Higgins struct kunit *test = ctx->test;
4635f3e0620SBrendan Higgins struct kunit_suite *suite = ctx->suite;
4645f3e0620SBrendan Higgins struct kunit_case *test_case = ctx->test_case;
4655f3e0620SBrendan Higgins
46683c4e7a0SPatricia Alfonso current->kunit_test = test;
46783c4e7a0SPatricia Alfonso
4685f3e0620SBrendan Higgins /*
4695f3e0620SBrendan Higgins * kunit_run_case_internal may encounter a fatal error; if it does,
4705f3e0620SBrendan Higgins * abort will be called, this thread will exit, and finally the parent
4715f3e0620SBrendan Higgins * thread will resume control and handle any necessary clean up.
4725f3e0620SBrendan Higgins */
4735f3e0620SBrendan Higgins kunit_run_case_internal(test, suite, test_case);
47455e8c1b4SDavid Gow }
47555e8c1b4SDavid Gow
kunit_try_run_case_cleanup(void * data)47655e8c1b4SDavid Gow static void kunit_try_run_case_cleanup(void *data)
47755e8c1b4SDavid Gow {
47855e8c1b4SDavid Gow struct kunit_try_catch_context *ctx = data;
47955e8c1b4SDavid Gow struct kunit *test = ctx->test;
48055e8c1b4SDavid Gow struct kunit_suite *suite = ctx->suite;
48155e8c1b4SDavid Gow
48255e8c1b4SDavid Gow current->kunit_test = test;
48355e8c1b4SDavid Gow
4845f3e0620SBrendan Higgins kunit_run_case_cleanup(test, suite);
4855f3e0620SBrendan Higgins }
4865f3e0620SBrendan Higgins
kunit_catch_run_case_cleanup(void * data)48755e8c1b4SDavid Gow static void kunit_catch_run_case_cleanup(void *data)
48855e8c1b4SDavid Gow {
48955e8c1b4SDavid Gow struct kunit_try_catch_context *ctx = data;
49055e8c1b4SDavid Gow struct kunit *test = ctx->test;
49155e8c1b4SDavid Gow int try_exit_code = kunit_try_catch_get_result(&test->try_catch);
49255e8c1b4SDavid Gow
49355e8c1b4SDavid Gow /* It is always a failure if cleanup aborts. */
49455e8c1b4SDavid Gow kunit_set_failure(test);
49555e8c1b4SDavid Gow
49655e8c1b4SDavid Gow if (try_exit_code) {
49755e8c1b4SDavid Gow /*
49855e8c1b4SDavid Gow * Test case could not finish, we have no idea what state it is
49955e8c1b4SDavid Gow * in, so don't do clean up.
50055e8c1b4SDavid Gow */
50155e8c1b4SDavid Gow if (try_exit_code == -ETIMEDOUT) {
50255e8c1b4SDavid Gow kunit_err(test, "test case cleanup timed out\n");
50355e8c1b4SDavid Gow /*
50455e8c1b4SDavid Gow * Unknown internal error occurred preventing test case from
50555e8c1b4SDavid Gow * running, so there is nothing to clean up.
50655e8c1b4SDavid Gow */
50755e8c1b4SDavid Gow } else {
50855e8c1b4SDavid Gow kunit_err(test, "internal error occurred during test case cleanup: %d\n",
50955e8c1b4SDavid Gow try_exit_code);
51055e8c1b4SDavid Gow }
51155e8c1b4SDavid Gow return;
51255e8c1b4SDavid Gow }
51355e8c1b4SDavid Gow
51455e8c1b4SDavid Gow kunit_err(test, "test aborted during cleanup. continuing without cleaning up\n");
51555e8c1b4SDavid Gow }
51655e8c1b4SDavid Gow
51755e8c1b4SDavid Gow
kunit_catch_run_case(void * data)5185f3e0620SBrendan Higgins static void kunit_catch_run_case(void *data)
5195f3e0620SBrendan Higgins {
5205f3e0620SBrendan Higgins struct kunit_try_catch_context *ctx = data;
5215f3e0620SBrendan Higgins struct kunit *test = ctx->test;
5225f3e0620SBrendan Higgins int try_exit_code = kunit_try_catch_get_result(&test->try_catch);
5235f3e0620SBrendan Higgins
5245f3e0620SBrendan Higgins if (try_exit_code) {
5255f3e0620SBrendan Higgins kunit_set_failure(test);
5265f3e0620SBrendan Higgins /*
5275f3e0620SBrendan Higgins * Test case could not finish, we have no idea what state it is
5285f3e0620SBrendan Higgins * in, so don't do clean up.
5295f3e0620SBrendan Higgins */
5305f3e0620SBrendan Higgins if (try_exit_code == -ETIMEDOUT) {
5315f3e0620SBrendan Higgins kunit_err(test, "test case timed out\n");
5325f3e0620SBrendan Higgins /*
5335f3e0620SBrendan Higgins * Unknown internal error occurred preventing test case from
5345f3e0620SBrendan Higgins * running, so there is nothing to clean up.
5355f3e0620SBrendan Higgins */
5365f3e0620SBrendan Higgins } else {
5375f3e0620SBrendan Higgins kunit_err(test, "internal error occurred preventing test case from running: %d\n",
5385f3e0620SBrendan Higgins try_exit_code);
5395f3e0620SBrendan Higgins }
5405f3e0620SBrendan Higgins return;
5415f3e0620SBrendan Higgins }
5425f3e0620SBrendan Higgins }
5435f3e0620SBrendan Higgins
5445f3e0620SBrendan Higgins /*
5455f3e0620SBrendan Higgins * Performs all logic to run a test case. It also catches most errors that
5465f3e0620SBrendan Higgins * occur in a test case and reports them as failures.
5475f3e0620SBrendan Higgins */
kunit_run_case_catch_errors(struct kunit_suite * suite,struct kunit_case * test_case,struct kunit * test)5485f3e0620SBrendan Higgins static void kunit_run_case_catch_errors(struct kunit_suite *suite,
549fadb08e7SArpitha Raghunandan struct kunit_case *test_case,
550fadb08e7SArpitha Raghunandan struct kunit *test)
5515f3e0620SBrendan Higgins {
5525f3e0620SBrendan Higgins struct kunit_try_catch_context context;
5535f3e0620SBrendan Higgins struct kunit_try_catch *try_catch;
5545f3e0620SBrendan Higgins
555fadb08e7SArpitha Raghunandan try_catch = &test->try_catch;
5565f3e0620SBrendan Higgins
5575f3e0620SBrendan Higgins kunit_try_catch_init(try_catch,
558fadb08e7SArpitha Raghunandan test,
5595f3e0620SBrendan Higgins kunit_try_run_case,
5605f3e0620SBrendan Higgins kunit_catch_run_case);
561fadb08e7SArpitha Raghunandan context.test = test;
5625f3e0620SBrendan Higgins context.suite = suite;
5635f3e0620SBrendan Higgins context.test_case = test_case;
5645f3e0620SBrendan Higgins kunit_try_catch_run(try_catch, &context);
5650a756853SBrendan Higgins
56655e8c1b4SDavid Gow /* Now run the cleanup */
56755e8c1b4SDavid Gow kunit_try_catch_init(try_catch,
56855e8c1b4SDavid Gow test,
56955e8c1b4SDavid Gow kunit_try_run_case_cleanup,
57055e8c1b4SDavid Gow kunit_catch_run_case_cleanup);
57155e8c1b4SDavid Gow kunit_try_catch_run(try_catch, &context);
57255e8c1b4SDavid Gow
5736d2426b2SDavid Gow /* Propagate the parameter result to the test case. */
5746d2426b2SDavid Gow if (test->status == KUNIT_FAILURE)
5756d2426b2SDavid Gow test_case->status = KUNIT_FAILURE;
5766d2426b2SDavid Gow else if (test_case->status != KUNIT_FAILURE && test->status == KUNIT_SUCCESS)
5776d2426b2SDavid Gow test_case->status = KUNIT_SUCCESS;
578914cc63eSBrendan Higgins }
579914cc63eSBrendan Higgins
kunit_print_suite_stats(struct kunit_suite * suite,struct kunit_result_stats suite_stats,struct kunit_result_stats param_stats)580acd8e840SDavid Gow static void kunit_print_suite_stats(struct kunit_suite *suite,
581acd8e840SDavid Gow struct kunit_result_stats suite_stats,
582acd8e840SDavid Gow struct kunit_result_stats param_stats)
583acd8e840SDavid Gow {
584acd8e840SDavid Gow if (kunit_should_print_stats(suite_stats)) {
585acd8e840SDavid Gow kunit_log(KERN_INFO, suite,
586acd8e840SDavid Gow "# %s: pass:%lu fail:%lu skip:%lu total:%lu",
587acd8e840SDavid Gow suite->name,
588acd8e840SDavid Gow suite_stats.passed,
589acd8e840SDavid Gow suite_stats.failed,
590acd8e840SDavid Gow suite_stats.skipped,
591acd8e840SDavid Gow suite_stats.total);
592acd8e840SDavid Gow }
593acd8e840SDavid Gow
594acd8e840SDavid Gow if (kunit_should_print_stats(param_stats)) {
595acd8e840SDavid Gow kunit_log(KERN_INFO, suite,
596acd8e840SDavid Gow "# Totals: pass:%lu fail:%lu skip:%lu total:%lu",
597acd8e840SDavid Gow param_stats.passed,
598acd8e840SDavid Gow param_stats.failed,
599acd8e840SDavid Gow param_stats.skipped,
600acd8e840SDavid Gow param_stats.total);
601acd8e840SDavid Gow }
602acd8e840SDavid Gow }
603acd8e840SDavid Gow
kunit_update_stats(struct kunit_result_stats * stats,enum kunit_status status)604acd8e840SDavid Gow static void kunit_update_stats(struct kunit_result_stats *stats,
605acd8e840SDavid Gow enum kunit_status status)
606acd8e840SDavid Gow {
607acd8e840SDavid Gow switch (status) {
608acd8e840SDavid Gow case KUNIT_SUCCESS:
609acd8e840SDavid Gow stats->passed++;
610acd8e840SDavid Gow break;
611acd8e840SDavid Gow case KUNIT_SKIPPED:
612acd8e840SDavid Gow stats->skipped++;
613acd8e840SDavid Gow break;
614acd8e840SDavid Gow case KUNIT_FAILURE:
615acd8e840SDavid Gow stats->failed++;
616acd8e840SDavid Gow break;
617acd8e840SDavid Gow }
618acd8e840SDavid Gow
619acd8e840SDavid Gow stats->total++;
620acd8e840SDavid Gow }
621acd8e840SDavid Gow
kunit_accumulate_stats(struct kunit_result_stats * total,struct kunit_result_stats add)622acd8e840SDavid Gow static void kunit_accumulate_stats(struct kunit_result_stats *total,
623acd8e840SDavid Gow struct kunit_result_stats add)
624acd8e840SDavid Gow {
625acd8e840SDavid Gow total->passed += add.passed;
626acd8e840SDavid Gow total->skipped += add.skipped;
627acd8e840SDavid Gow total->failed += add.failed;
628acd8e840SDavid Gow total->total += add.total;
629acd8e840SDavid Gow }
630acd8e840SDavid Gow
kunit_run_tests(struct kunit_suite * suite)631914cc63eSBrendan Higgins int kunit_run_tests(struct kunit_suite *suite)
632914cc63eSBrendan Higgins {
633fadb08e7SArpitha Raghunandan char param_desc[KUNIT_PARAM_DESC_SIZE];
634914cc63eSBrendan Higgins struct kunit_case *test_case;
635acd8e840SDavid Gow struct kunit_result_stats suite_stats = { 0 };
636acd8e840SDavid Gow struct kunit_result_stats total_stats = { 0 };
637914cc63eSBrendan Higgins
638c272612cSDavid Gow /* Taint the kernel so we know we've run tests. */
639c272612cSDavid Gow add_taint(TAINT_TEST, LOCKDEP_STILL_OK);
640c272612cSDavid Gow
6411cdba21dSDaniel Latypov if (suite->suite_init) {
6421cdba21dSDaniel Latypov suite->suite_init_err = suite->suite_init(suite);
6431cdba21dSDaniel Latypov if (suite->suite_init_err) {
6441cdba21dSDaniel Latypov kunit_err(suite, KUNIT_SUBTEST_INDENT
6451cdba21dSDaniel Latypov "# failed to initialize (%d)", suite->suite_init_err);
6461cdba21dSDaniel Latypov goto suite_end;
6471cdba21dSDaniel Latypov }
6481cdba21dSDaniel Latypov }
6491cdba21dSDaniel Latypov
650cae56e17SDaniel Latypov kunit_print_suite_start(suite);
651914cc63eSBrendan Higgins
652fadb08e7SArpitha Raghunandan kunit_suite_for_each_test_case(suite, test_case) {
653fadb08e7SArpitha Raghunandan struct kunit test = { .param_value = NULL, .param_index = 0 };
654acd8e840SDavid Gow struct kunit_result_stats param_stats = { 0 };
655fadb08e7SArpitha Raghunandan
656887d85a0SRae Moar kunit_init_test(&test, test_case->name, test_case->log);
657529534e8SRae Moar if (test_case->status == KUNIT_SKIPPED) {
658529534e8SRae Moar /* Test marked as skip */
659529534e8SRae Moar test.status = KUNIT_SKIPPED;
660529534e8SRae Moar kunit_update_stats(¶m_stats, test.status);
661529534e8SRae Moar } else if (!test_case->generate_params) {
66237dbb4c7SDavid Gow /* Non-parameterised test. */
663529534e8SRae Moar test_case->status = KUNIT_SKIPPED;
66437dbb4c7SDavid Gow kunit_run_case_catch_errors(suite, test_case, &test);
66537dbb4c7SDavid Gow kunit_update_stats(¶m_stats, test.status);
66637dbb4c7SDavid Gow } else {
667fadb08e7SArpitha Raghunandan /* Get initial param. */
668fadb08e7SArpitha Raghunandan param_desc[0] = '\0';
669fadb08e7SArpitha Raghunandan test.param_value = test_case->generate_params(NULL, param_desc);
670529534e8SRae Moar test_case->status = KUNIT_SKIPPED;
67144b7da5fSDavid Gow kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
6726c738b52SRae Moar "KTAP version 1\n");
6736c738b52SRae Moar kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
67444b7da5fSDavid Gow "# Subtest: %s", test_case->name);
675fadb08e7SArpitha Raghunandan
67637dbb4c7SDavid Gow while (test.param_value) {
677fadb08e7SArpitha Raghunandan kunit_run_case_catch_errors(suite, test_case, &test);
678fadb08e7SArpitha Raghunandan
679fadb08e7SArpitha Raghunandan if (param_desc[0] == '\0') {
680fadb08e7SArpitha Raghunandan snprintf(param_desc, sizeof(param_desc),
681fadb08e7SArpitha Raghunandan "param-%d", test.param_index);
682fadb08e7SArpitha Raghunandan }
683fadb08e7SArpitha Raghunandan
684b1eaa8b2SMichal Wajdeczko kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE_PARAM,
685b1eaa8b2SMichal Wajdeczko test.status,
686b1eaa8b2SMichal Wajdeczko test.param_index + 1,
687b1eaa8b2SMichal Wajdeczko param_desc,
688b1eaa8b2SMichal Wajdeczko test.status_comment);
689fadb08e7SArpitha Raghunandan
690fadb08e7SArpitha Raghunandan /* Get next param. */
691fadb08e7SArpitha Raghunandan param_desc[0] = '\0';
692fadb08e7SArpitha Raghunandan test.param_value = test_case->generate_params(test.param_value, param_desc);
693fadb08e7SArpitha Raghunandan test.param_index++;
694acd8e840SDavid Gow
695acd8e840SDavid Gow kunit_update_stats(¶m_stats, test.status);
69637dbb4c7SDavid Gow }
69737dbb4c7SDavid Gow }
698acd8e840SDavid Gow
69939e92cb1SRae Moar kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE);
700fadb08e7SArpitha Raghunandan
701acd8e840SDavid Gow kunit_print_test_stats(&test, param_stats);
702acd8e840SDavid Gow
703b1eaa8b2SMichal Wajdeczko kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE, test_case->status,
704fadb08e7SArpitha Raghunandan kunit_test_case_num(suite, test_case),
7056d2426b2SDavid Gow test_case->name,
7066d2426b2SDavid Gow test.status_comment);
707acd8e840SDavid Gow
708acd8e840SDavid Gow kunit_update_stats(&suite_stats, test_case->status);
709acd8e840SDavid Gow kunit_accumulate_stats(&total_stats, param_stats);
710fadb08e7SArpitha Raghunandan }
711914cc63eSBrendan Higgins
7121cdba21dSDaniel Latypov if (suite->suite_exit)
7131cdba21dSDaniel Latypov suite->suite_exit(suite);
7141cdba21dSDaniel Latypov
715acd8e840SDavid Gow kunit_print_suite_stats(suite, suite_stats, total_stats);
7161cdba21dSDaniel Latypov suite_end:
717cae56e17SDaniel Latypov kunit_print_suite_end(suite);
718914cc63eSBrendan Higgins
719914cc63eSBrendan Higgins return 0;
720914cc63eSBrendan Higgins }
721c475c77dSAlan Maguire EXPORT_SYMBOL_GPL(kunit_run_tests);
722914cc63eSBrendan Higgins
kunit_init_suite(struct kunit_suite * suite)723e2219db2SAlan Maguire static void kunit_init_suite(struct kunit_suite *suite)
724e2219db2SAlan Maguire {
725e2219db2SAlan Maguire kunit_debugfs_create_suite(suite);
7266d2426b2SDavid Gow suite->status_comment[0] = '\0';
7271cdba21dSDaniel Latypov suite->suite_init_err = 0;
728e2219db2SAlan Maguire }
729e2219db2SAlan Maguire
kunit_enabled(void)730d20a6ba5SJoe Fradley bool kunit_enabled(void)
731d20a6ba5SJoe Fradley {
732d20a6ba5SJoe Fradley return enable_param;
733d20a6ba5SJoe Fradley }
734d20a6ba5SJoe Fradley
__kunit_test_suites_init(struct kunit_suite * const * const suites,int num_suites)735e5857d39SDaniel Latypov int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites)
736e2219db2SAlan Maguire {
737e2219db2SAlan Maguire unsigned int i;
738e2219db2SAlan Maguire
739d20a6ba5SJoe Fradley if (!kunit_enabled() && num_suites > 0) {
740d20a6ba5SJoe Fradley pr_info("kunit: disabled\n");
741d20a6ba5SJoe Fradley return 0;
742d20a6ba5SJoe Fradley }
743d20a6ba5SJoe Fradley
744b12a3311SMichal Wajdeczko kunit_suite_counter = 1;
745b12a3311SMichal Wajdeczko
746908d0c17SDavid Gow static_branch_inc(&kunit_running);
747908d0c17SDavid Gow
748e5857d39SDaniel Latypov for (i = 0; i < num_suites; i++) {
749e2219db2SAlan Maguire kunit_init_suite(suites[i]);
750e2219db2SAlan Maguire kunit_run_tests(suites[i]);
751e2219db2SAlan Maguire }
752908d0c17SDavid Gow
753908d0c17SDavid Gow static_branch_dec(&kunit_running);
754e2219db2SAlan Maguire return 0;
755e2219db2SAlan Maguire }
756e2219db2SAlan Maguire EXPORT_SYMBOL_GPL(__kunit_test_suites_init);
757e2219db2SAlan Maguire
kunit_exit_suite(struct kunit_suite * suite)758e2219db2SAlan Maguire static void kunit_exit_suite(struct kunit_suite *suite)
759e2219db2SAlan Maguire {
760e2219db2SAlan Maguire kunit_debugfs_destroy_suite(suite);
761e2219db2SAlan Maguire }
762e2219db2SAlan Maguire
__kunit_test_suites_exit(struct kunit_suite ** suites,int num_suites)763e5857d39SDaniel Latypov void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites)
764e2219db2SAlan Maguire {
765e2219db2SAlan Maguire unsigned int i;
766e2219db2SAlan Maguire
767d20a6ba5SJoe Fradley if (!kunit_enabled())
768d20a6ba5SJoe Fradley return;
769d20a6ba5SJoe Fradley
770e5857d39SDaniel Latypov for (i = 0; i < num_suites; i++)
771e2219db2SAlan Maguire kunit_exit_suite(suites[i]);
772e2219db2SAlan Maguire }
773e2219db2SAlan Maguire EXPORT_SYMBOL_GPL(__kunit_test_suites_exit);
774e2219db2SAlan Maguire
7753d6e4462SJeremy Kerr #ifdef CONFIG_MODULES
kunit_module_init(struct module * mod)7763d6e4462SJeremy Kerr static void kunit_module_init(struct module *mod)
7773d6e4462SJeremy Kerr {
778c95e7c05SJanusz Krzysztofik struct kunit_suite_set suite_set = {
779c95e7c05SJanusz Krzysztofik mod->kunit_suites, mod->kunit_suites + mod->num_kunit_suites,
780c95e7c05SJanusz Krzysztofik };
78118258c60SJanusz Krzysztofik const char *action = kunit_action();
782b67abaadSJanusz Krzysztofik int err = 0;
783b67abaadSJanusz Krzysztofik
784b67abaadSJanusz Krzysztofik suite_set = kunit_filter_suites(&suite_set,
785b67abaadSJanusz Krzysztofik kunit_filter_glob() ?: "*.*",
786b67abaadSJanusz Krzysztofik kunit_filter(), kunit_filter_action(),
787b67abaadSJanusz Krzysztofik &err);
788b67abaadSJanusz Krzysztofik if (err)
789b67abaadSJanusz Krzysztofik pr_err("kunit module: error filtering suites: %d\n", err);
790b67abaadSJanusz Krzysztofik
791b67abaadSJanusz Krzysztofik mod->kunit_suites = (struct kunit_suite **)suite_set.start;
792b67abaadSJanusz Krzysztofik mod->num_kunit_suites = suite_set.end - suite_set.start;
793c95e7c05SJanusz Krzysztofik
79418258c60SJanusz Krzysztofik if (!action)
795c95e7c05SJanusz Krzysztofik kunit_exec_run_tests(&suite_set, false);
79618258c60SJanusz Krzysztofik else if (!strcmp(action, "list"))
79718258c60SJanusz Krzysztofik kunit_exec_list_tests(&suite_set, false);
79818258c60SJanusz Krzysztofik else if (!strcmp(action, "list_attr"))
79918258c60SJanusz Krzysztofik kunit_exec_list_tests(&suite_set, true);
80018258c60SJanusz Krzysztofik else
80118258c60SJanusz Krzysztofik pr_err("kunit: unknown action '%s'\n", action);
8023d6e4462SJeremy Kerr }
8033d6e4462SJeremy Kerr
kunit_module_exit(struct module * mod)8043d6e4462SJeremy Kerr static void kunit_module_exit(struct module *mod)
8053d6e4462SJeremy Kerr {
806b67abaadSJanusz Krzysztofik struct kunit_suite_set suite_set = {
807b67abaadSJanusz Krzysztofik mod->kunit_suites, mod->kunit_suites + mod->num_kunit_suites,
808b67abaadSJanusz Krzysztofik };
80918258c60SJanusz Krzysztofik const char *action = kunit_action();
81018258c60SJanusz Krzysztofik
811*8e4319a4SMarco Pagani /*
812*8e4319a4SMarco Pagani * Check if the start address is a valid virtual address to detect
813*8e4319a4SMarco Pagani * if the module load sequence has failed and the suite set has not
814*8e4319a4SMarco Pagani * been initialized and filtered.
815*8e4319a4SMarco Pagani */
816*8e4319a4SMarco Pagani if (!suite_set.start || !virt_addr_valid(suite_set.start))
817*8e4319a4SMarco Pagani return;
818*8e4319a4SMarco Pagani
81918258c60SJanusz Krzysztofik if (!action)
82018258c60SJanusz Krzysztofik __kunit_test_suites_exit(mod->kunit_suites,
82118258c60SJanusz Krzysztofik mod->num_kunit_suites);
822b67abaadSJanusz Krzysztofik
823b67abaadSJanusz Krzysztofik kunit_free_suite_set(suite_set);
8243d6e4462SJeremy Kerr }
8253d6e4462SJeremy Kerr
kunit_module_notify(struct notifier_block * nb,unsigned long val,void * data)8263d6e4462SJeremy Kerr static int kunit_module_notify(struct notifier_block *nb, unsigned long val,
8273d6e4462SJeremy Kerr void *data)
8283d6e4462SJeremy Kerr {
8293d6e4462SJeremy Kerr struct module *mod = data;
8303d6e4462SJeremy Kerr
8313d6e4462SJeremy Kerr switch (val) {
8323d6e4462SJeremy Kerr case MODULE_STATE_LIVE:
833*8e4319a4SMarco Pagani kunit_module_init(mod);
8343d6e4462SJeremy Kerr break;
8353d6e4462SJeremy Kerr case MODULE_STATE_GOING:
8363d6e4462SJeremy Kerr kunit_module_exit(mod);
8373d6e4462SJeremy Kerr break;
8383d6e4462SJeremy Kerr case MODULE_STATE_COMING:
8392810c1e9SJinjie Ruan break;
8403d6e4462SJeremy Kerr case MODULE_STATE_UNFORMED:
8413d6e4462SJeremy Kerr break;
8423d6e4462SJeremy Kerr }
8433d6e4462SJeremy Kerr
8443d6e4462SJeremy Kerr return 0;
8453d6e4462SJeremy Kerr }
8463d6e4462SJeremy Kerr
8473d6e4462SJeremy Kerr static struct notifier_block kunit_mod_nb = {
8483d6e4462SJeremy Kerr .notifier_call = kunit_module_notify,
8493d6e4462SJeremy Kerr .priority = 0,
8503d6e4462SJeremy Kerr };
8513d6e4462SJeremy Kerr #endif
8523d6e4462SJeremy Kerr
kunit_kmalloc_array(struct kunit * test,size_t n,size_t size,gfp_t gfp)8537122debbSDaniel Latypov void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp)
8540a756853SBrendan Higgins {
85557e3cdedSDavid Gow void *data;
8560a756853SBrendan Higgins
85757e3cdedSDavid Gow data = kmalloc_array(n, size, gfp);
85857e3cdedSDavid Gow
85957e3cdedSDavid Gow if (!data)
86057e3cdedSDavid Gow return NULL;
86157e3cdedSDavid Gow
86257e3cdedSDavid Gow if (kunit_add_action_or_reset(test, (kunit_action_t *)kfree, data) != 0)
86357e3cdedSDavid Gow return NULL;
86457e3cdedSDavid Gow
86557e3cdedSDavid Gow return data;
8660a756853SBrendan Higgins }
8677122debbSDaniel Latypov EXPORT_SYMBOL_GPL(kunit_kmalloc_array);
8680a756853SBrendan Higgins
kunit_kfree(struct kunit * test,const void * ptr)8690a756853SBrendan Higgins void kunit_kfree(struct kunit *test, const void *ptr)
8700a756853SBrendan Higgins {
871185d5779SDaniel Latypov if (!ptr)
872185d5779SDaniel Latypov return;
873185d5779SDaniel Latypov
87457e3cdedSDavid Gow kunit_release_action(test, (kunit_action_t *)kfree, (void *)ptr);
8750a756853SBrendan Higgins }
876c475c77dSAlan Maguire EXPORT_SYMBOL_GPL(kunit_kfree);
8770a756853SBrendan Higgins
kunit_cleanup(struct kunit * test)8780a756853SBrendan Higgins void kunit_cleanup(struct kunit *test)
8790a756853SBrendan Higgins {
880d4cdd146SAlan Maguire struct kunit_resource *res;
88126c6cb7cSVlastimil Babka unsigned long flags;
8820a756853SBrendan Higgins
8830a756853SBrendan Higgins /*
8840a756853SBrendan Higgins * test->resources is a stack - each allocation must be freed in the
8850a756853SBrendan Higgins * reverse order from which it was added since one resource may depend
8860a756853SBrendan Higgins * on another for its entire lifetime.
8870a756853SBrendan Higgins * Also, we cannot use the normal list_for_each constructs, even the
8880a756853SBrendan Higgins * safe ones because *arbitrary* nodes may be deleted when
8890a756853SBrendan Higgins * kunit_resource_free is called; the list_for_each_safe variants only
8900a756853SBrendan Higgins * protect against the current node being deleted, not the next.
8910a756853SBrendan Higgins */
8920a756853SBrendan Higgins while (true) {
89326c6cb7cSVlastimil Babka spin_lock_irqsave(&test->lock, flags);
8940a756853SBrendan Higgins if (list_empty(&test->resources)) {
89526c6cb7cSVlastimil Babka spin_unlock_irqrestore(&test->lock, flags);
8960a756853SBrendan Higgins break;
8970a756853SBrendan Higgins }
898d4cdd146SAlan Maguire res = list_last_entry(&test->resources,
8990a756853SBrendan Higgins struct kunit_resource,
9000a756853SBrendan Higgins node);
901d4cdd146SAlan Maguire /*
902d4cdd146SAlan Maguire * Need to unlock here as a resource may remove another
903d4cdd146SAlan Maguire * resource, and this can't happen if the test->lock
904d4cdd146SAlan Maguire * is held.
905d4cdd146SAlan Maguire */
90626c6cb7cSVlastimil Babka spin_unlock_irqrestore(&test->lock, flags);
907d4cdd146SAlan Maguire kunit_remove_resource(test, res);
9080a756853SBrendan Higgins }
90983c4e7a0SPatricia Alfonso current->kunit_test = NULL;
9100a756853SBrendan Higgins }
911c475c77dSAlan Maguire EXPORT_SYMBOL_GPL(kunit_cleanup);
9129fe124bfSAlan Maguire
kunit_init(void)9139fe124bfSAlan Maguire static int __init kunit_init(void)
9149fe124bfSAlan Maguire {
9157170b7edSDavid Gow /* Install the KUnit hook functions. */
9167170b7edSDavid Gow kunit_install_hooks();
9177170b7edSDavid Gow
918e2219db2SAlan Maguire kunit_debugfs_init();
9193d6e4462SJeremy Kerr #ifdef CONFIG_MODULES
9203d6e4462SJeremy Kerr return register_module_notifier(&kunit_mod_nb);
9213d6e4462SJeremy Kerr #else
9229fe124bfSAlan Maguire return 0;
9233d6e4462SJeremy Kerr #endif
9249fe124bfSAlan Maguire }
9259fe124bfSAlan Maguire late_initcall(kunit_init);
9269fe124bfSAlan Maguire
kunit_exit(void)9279fe124bfSAlan Maguire static void __exit kunit_exit(void)
9289fe124bfSAlan Maguire {
9297170b7edSDavid Gow memset(&kunit_hooks, 0, sizeof(kunit_hooks));
9303d6e4462SJeremy Kerr #ifdef CONFIG_MODULES
9313d6e4462SJeremy Kerr unregister_module_notifier(&kunit_mod_nb);
9323d6e4462SJeremy Kerr #endif
933e2219db2SAlan Maguire kunit_debugfs_cleanup();
9349fe124bfSAlan Maguire }
9359fe124bfSAlan Maguire module_exit(kunit_exit);
9369fe124bfSAlan Maguire
9379fe124bfSAlan Maguire MODULE_LICENSE("GPL v2");
938