0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <kunit/resource.h>
0010 #include <kunit/test.h>
0011 #include <kunit/test-bug.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/moduleparam.h>
0015 #include <linux/panic.h>
0016 #include <linux/sched/debug.h>
0017 #include <linux/sched.h>
0018
0019 #include "debugfs.h"
0020 #include "string-stream.h"
0021 #include "try-catch-impl.h"
0022
0023 #if IS_BUILTIN(CONFIG_KUNIT)
0024
0025
0026
0027 void __kunit_fail_current_test(const char *file, int line, const char *fmt, ...)
0028 {
0029 va_list args;
0030 int len;
0031 char *buffer;
0032
0033 if (!current->kunit_test)
0034 return;
0035
0036 kunit_set_failure(current->kunit_test);
0037
0038
0039 va_start(args, fmt);
0040 len = vsnprintf(NULL, 0, fmt, args) + 1;
0041 va_end(args);
0042
0043 buffer = kunit_kmalloc(current->kunit_test, len, GFP_KERNEL);
0044 if (!buffer)
0045 return;
0046
0047 va_start(args, fmt);
0048 vsnprintf(buffer, len, fmt, args);
0049 va_end(args);
0050
0051 kunit_err(current->kunit_test, "%s:%d: %s", file, line, buffer);
0052 kunit_kfree(current->kunit_test, buffer);
0053 }
0054 EXPORT_SYMBOL_GPL(__kunit_fail_current_test);
0055 #endif
0056
0057
0058
0059
0060
0061
0062
0063 static int kunit_stats_enabled = 1;
0064 module_param_named(stats_enabled, kunit_stats_enabled, int, 0644);
0065 MODULE_PARM_DESC(stats_enabled,
0066 "Print test stats: never (0), only for multiple subtests (1), or always (2)");
0067
0068 struct kunit_result_stats {
0069 unsigned long passed;
0070 unsigned long skipped;
0071 unsigned long failed;
0072 unsigned long total;
0073 };
0074
0075 static bool kunit_should_print_stats(struct kunit_result_stats stats)
0076 {
0077 if (kunit_stats_enabled == 0)
0078 return false;
0079
0080 if (kunit_stats_enabled == 2)
0081 return true;
0082
0083 return (stats.total > 1);
0084 }
0085
0086 static void kunit_print_test_stats(struct kunit *test,
0087 struct kunit_result_stats stats)
0088 {
0089 if (!kunit_should_print_stats(stats))
0090 return;
0091
0092 kunit_log(KERN_INFO, test,
0093 KUNIT_SUBTEST_INDENT
0094 "# %s: pass:%lu fail:%lu skip:%lu total:%lu",
0095 test->name,
0096 stats.passed,
0097 stats.failed,
0098 stats.skipped,
0099 stats.total);
0100 }
0101
0102
0103
0104
0105
0106 void kunit_log_append(char *log, const char *fmt, ...)
0107 {
0108 char line[KUNIT_LOG_SIZE];
0109 va_list args;
0110 int len_left;
0111
0112 if (!log)
0113 return;
0114
0115 len_left = KUNIT_LOG_SIZE - strlen(log) - 1;
0116 if (len_left <= 0)
0117 return;
0118
0119 va_start(args, fmt);
0120 vsnprintf(line, sizeof(line), fmt, args);
0121 va_end(args);
0122
0123 strncat(log, line, len_left);
0124 }
0125 EXPORT_SYMBOL_GPL(kunit_log_append);
0126
0127 size_t kunit_suite_num_test_cases(struct kunit_suite *suite)
0128 {
0129 struct kunit_case *test_case;
0130 size_t len = 0;
0131
0132 kunit_suite_for_each_test_case(suite, test_case)
0133 len++;
0134
0135 return len;
0136 }
0137 EXPORT_SYMBOL_GPL(kunit_suite_num_test_cases);
0138
0139 static void kunit_print_suite_start(struct kunit_suite *suite)
0140 {
0141 kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "# Subtest: %s",
0142 suite->name);
0143 kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "1..%zd",
0144 kunit_suite_num_test_cases(suite));
0145 }
0146
0147 static void kunit_print_ok_not_ok(void *test_or_suite,
0148 bool is_test,
0149 enum kunit_status status,
0150 size_t test_number,
0151 const char *description,
0152 const char *directive)
0153 {
0154 struct kunit_suite *suite = is_test ? NULL : test_or_suite;
0155 struct kunit *test = is_test ? test_or_suite : NULL;
0156 const char *directive_header = (status == KUNIT_SKIPPED) ? " # SKIP " : "";
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166 if (suite)
0167 pr_info("%s %zd - %s%s%s\n",
0168 kunit_status_to_ok_not_ok(status),
0169 test_number, description, directive_header,
0170 (status == KUNIT_SKIPPED) ? directive : "");
0171 else
0172 kunit_log(KERN_INFO, test,
0173 KUNIT_SUBTEST_INDENT "%s %zd - %s%s%s",
0174 kunit_status_to_ok_not_ok(status),
0175 test_number, description, directive_header,
0176 (status == KUNIT_SKIPPED) ? directive : "");
0177 }
0178
0179 enum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite)
0180 {
0181 const struct kunit_case *test_case;
0182 enum kunit_status status = KUNIT_SKIPPED;
0183
0184 if (suite->suite_init_err)
0185 return KUNIT_FAILURE;
0186
0187 kunit_suite_for_each_test_case(suite, test_case) {
0188 if (test_case->status == KUNIT_FAILURE)
0189 return KUNIT_FAILURE;
0190 else if (test_case->status == KUNIT_SUCCESS)
0191 status = KUNIT_SUCCESS;
0192 }
0193
0194 return status;
0195 }
0196 EXPORT_SYMBOL_GPL(kunit_suite_has_succeeded);
0197
0198 static size_t kunit_suite_counter = 1;
0199
0200 static void kunit_print_suite_end(struct kunit_suite *suite)
0201 {
0202 kunit_print_ok_not_ok((void *)suite, false,
0203 kunit_suite_has_succeeded(suite),
0204 kunit_suite_counter++,
0205 suite->name,
0206 suite->status_comment);
0207 }
0208
0209 unsigned int kunit_test_case_num(struct kunit_suite *suite,
0210 struct kunit_case *test_case)
0211 {
0212 struct kunit_case *tc;
0213 unsigned int i = 1;
0214
0215 kunit_suite_for_each_test_case(suite, tc) {
0216 if (tc == test_case)
0217 return i;
0218 i++;
0219 }
0220
0221 return 0;
0222 }
0223 EXPORT_SYMBOL_GPL(kunit_test_case_num);
0224
0225 static void kunit_print_string_stream(struct kunit *test,
0226 struct string_stream *stream)
0227 {
0228 struct string_stream_fragment *fragment;
0229 char *buf;
0230
0231 if (string_stream_is_empty(stream))
0232 return;
0233
0234 buf = string_stream_get_string(stream);
0235 if (!buf) {
0236 kunit_err(test,
0237 "Could not allocate buffer, dumping stream:\n");
0238 list_for_each_entry(fragment, &stream->fragments, node) {
0239 kunit_err(test, "%s", fragment->fragment);
0240 }
0241 kunit_err(test, "\n");
0242 } else {
0243 kunit_err(test, "%s", buf);
0244 kunit_kfree(test, buf);
0245 }
0246 }
0247
0248 static void kunit_fail(struct kunit *test, const struct kunit_loc *loc,
0249 enum kunit_assert_type type, const struct kunit_assert *assert,
0250 const struct va_format *message)
0251 {
0252 struct string_stream *stream;
0253
0254 kunit_set_failure(test);
0255
0256 stream = alloc_string_stream(test, GFP_KERNEL);
0257 if (!stream) {
0258 WARN(true,
0259 "Could not allocate stream to print failed assertion in %s:%d\n",
0260 loc->file,
0261 loc->line);
0262 return;
0263 }
0264
0265 kunit_assert_prologue(loc, type, stream);
0266 assert->format(assert, message, stream);
0267
0268 kunit_print_string_stream(test, stream);
0269
0270 WARN_ON(string_stream_destroy(stream));
0271 }
0272
0273 static void __noreturn kunit_abort(struct kunit *test)
0274 {
0275 kunit_try_catch_throw(&test->try_catch);
0276
0277
0278
0279
0280
0281
0282
0283 WARN_ONCE(true, "Throw could not abort from test!\n");
0284 }
0285
0286 void kunit_do_failed_assertion(struct kunit *test,
0287 const struct kunit_loc *loc,
0288 enum kunit_assert_type type,
0289 const struct kunit_assert *assert,
0290 const char *fmt, ...)
0291 {
0292 va_list args;
0293 struct va_format message;
0294 va_start(args, fmt);
0295
0296 message.fmt = fmt;
0297 message.va = &args;
0298
0299 kunit_fail(test, loc, type, assert, &message);
0300
0301 va_end(args);
0302
0303 if (type == KUNIT_ASSERTION)
0304 kunit_abort(test);
0305 }
0306 EXPORT_SYMBOL_GPL(kunit_do_failed_assertion);
0307
0308 void kunit_init_test(struct kunit *test, const char *name, char *log)
0309 {
0310 spin_lock_init(&test->lock);
0311 INIT_LIST_HEAD(&test->resources);
0312 test->name = name;
0313 test->log = log;
0314 if (test->log)
0315 test->log[0] = '\0';
0316 test->status = KUNIT_SUCCESS;
0317 test->status_comment[0] = '\0';
0318 }
0319 EXPORT_SYMBOL_GPL(kunit_init_test);
0320
0321
0322
0323
0324 static void kunit_run_case_internal(struct kunit *test,
0325 struct kunit_suite *suite,
0326 struct kunit_case *test_case)
0327 {
0328 if (suite->init) {
0329 int ret;
0330
0331 ret = suite->init(test);
0332 if (ret) {
0333 kunit_err(test, "failed to initialize: %d\n", ret);
0334 kunit_set_failure(test);
0335 return;
0336 }
0337 }
0338
0339 test_case->run_case(test);
0340 }
0341
0342 static void kunit_case_internal_cleanup(struct kunit *test)
0343 {
0344 kunit_cleanup(test);
0345 }
0346
0347
0348
0349
0350
0351 static void kunit_run_case_cleanup(struct kunit *test,
0352 struct kunit_suite *suite)
0353 {
0354 if (suite->exit)
0355 suite->exit(test);
0356
0357 kunit_case_internal_cleanup(test);
0358 }
0359
0360 struct kunit_try_catch_context {
0361 struct kunit *test;
0362 struct kunit_suite *suite;
0363 struct kunit_case *test_case;
0364 };
0365
0366 static void kunit_try_run_case(void *data)
0367 {
0368 struct kunit_try_catch_context *ctx = data;
0369 struct kunit *test = ctx->test;
0370 struct kunit_suite *suite = ctx->suite;
0371 struct kunit_case *test_case = ctx->test_case;
0372
0373 current->kunit_test = test;
0374
0375
0376
0377
0378
0379
0380 kunit_run_case_internal(test, suite, test_case);
0381
0382 kunit_run_case_cleanup(test, suite);
0383 }
0384
0385 static void kunit_catch_run_case(void *data)
0386 {
0387 struct kunit_try_catch_context *ctx = data;
0388 struct kunit *test = ctx->test;
0389 struct kunit_suite *suite = ctx->suite;
0390 int try_exit_code = kunit_try_catch_get_result(&test->try_catch);
0391
0392 if (try_exit_code) {
0393 kunit_set_failure(test);
0394
0395
0396
0397
0398 if (try_exit_code == -ETIMEDOUT) {
0399 kunit_err(test, "test case timed out\n");
0400
0401
0402
0403
0404 } else {
0405 kunit_err(test, "internal error occurred preventing test case from running: %d\n",
0406 try_exit_code);
0407 }
0408 return;
0409 }
0410
0411
0412
0413
0414
0415 kunit_run_case_cleanup(test, suite);
0416 }
0417
0418
0419
0420
0421
0422 static void kunit_run_case_catch_errors(struct kunit_suite *suite,
0423 struct kunit_case *test_case,
0424 struct kunit *test)
0425 {
0426 struct kunit_try_catch_context context;
0427 struct kunit_try_catch *try_catch;
0428
0429 kunit_init_test(test, test_case->name, test_case->log);
0430 try_catch = &test->try_catch;
0431
0432 kunit_try_catch_init(try_catch,
0433 test,
0434 kunit_try_run_case,
0435 kunit_catch_run_case);
0436 context.test = test;
0437 context.suite = suite;
0438 context.test_case = test_case;
0439 kunit_try_catch_run(try_catch, &context);
0440
0441
0442 if (test->status == KUNIT_FAILURE)
0443 test_case->status = KUNIT_FAILURE;
0444 else if (test_case->status != KUNIT_FAILURE && test->status == KUNIT_SUCCESS)
0445 test_case->status = KUNIT_SUCCESS;
0446 }
0447
0448 static void kunit_print_suite_stats(struct kunit_suite *suite,
0449 struct kunit_result_stats suite_stats,
0450 struct kunit_result_stats param_stats)
0451 {
0452 if (kunit_should_print_stats(suite_stats)) {
0453 kunit_log(KERN_INFO, suite,
0454 "# %s: pass:%lu fail:%lu skip:%lu total:%lu",
0455 suite->name,
0456 suite_stats.passed,
0457 suite_stats.failed,
0458 suite_stats.skipped,
0459 suite_stats.total);
0460 }
0461
0462 if (kunit_should_print_stats(param_stats)) {
0463 kunit_log(KERN_INFO, suite,
0464 "# Totals: pass:%lu fail:%lu skip:%lu total:%lu",
0465 param_stats.passed,
0466 param_stats.failed,
0467 param_stats.skipped,
0468 param_stats.total);
0469 }
0470 }
0471
0472 static void kunit_update_stats(struct kunit_result_stats *stats,
0473 enum kunit_status status)
0474 {
0475 switch (status) {
0476 case KUNIT_SUCCESS:
0477 stats->passed++;
0478 break;
0479 case KUNIT_SKIPPED:
0480 stats->skipped++;
0481 break;
0482 case KUNIT_FAILURE:
0483 stats->failed++;
0484 break;
0485 }
0486
0487 stats->total++;
0488 }
0489
0490 static void kunit_accumulate_stats(struct kunit_result_stats *total,
0491 struct kunit_result_stats add)
0492 {
0493 total->passed += add.passed;
0494 total->skipped += add.skipped;
0495 total->failed += add.failed;
0496 total->total += add.total;
0497 }
0498
0499 int kunit_run_tests(struct kunit_suite *suite)
0500 {
0501 char param_desc[KUNIT_PARAM_DESC_SIZE];
0502 struct kunit_case *test_case;
0503 struct kunit_result_stats suite_stats = { 0 };
0504 struct kunit_result_stats total_stats = { 0 };
0505
0506
0507 add_taint(TAINT_TEST, LOCKDEP_STILL_OK);
0508
0509 if (suite->suite_init) {
0510 suite->suite_init_err = suite->suite_init(suite);
0511 if (suite->suite_init_err) {
0512 kunit_err(suite, KUNIT_SUBTEST_INDENT
0513 "# failed to initialize (%d)", suite->suite_init_err);
0514 goto suite_end;
0515 }
0516 }
0517
0518 kunit_print_suite_start(suite);
0519
0520 kunit_suite_for_each_test_case(suite, test_case) {
0521 struct kunit test = { .param_value = NULL, .param_index = 0 };
0522 struct kunit_result_stats param_stats = { 0 };
0523 test_case->status = KUNIT_SKIPPED;
0524
0525 if (!test_case->generate_params) {
0526
0527 kunit_run_case_catch_errors(suite, test_case, &test);
0528 kunit_update_stats(¶m_stats, test.status);
0529 } else {
0530
0531 param_desc[0] = '\0';
0532 test.param_value = test_case->generate_params(NULL, param_desc);
0533 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
0534 "# Subtest: %s", test_case->name);
0535
0536 while (test.param_value) {
0537 kunit_run_case_catch_errors(suite, test_case, &test);
0538
0539 if (param_desc[0] == '\0') {
0540 snprintf(param_desc, sizeof(param_desc),
0541 "param-%d", test.param_index);
0542 }
0543
0544 kunit_log(KERN_INFO, &test,
0545 KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
0546 "%s %d - %s",
0547 kunit_status_to_ok_not_ok(test.status),
0548 test.param_index + 1, param_desc);
0549
0550
0551 param_desc[0] = '\0';
0552 test.param_value = test_case->generate_params(test.param_value, param_desc);
0553 test.param_index++;
0554
0555 kunit_update_stats(¶m_stats, test.status);
0556 }
0557 }
0558
0559
0560 kunit_print_test_stats(&test, param_stats);
0561
0562 kunit_print_ok_not_ok(&test, true, test_case->status,
0563 kunit_test_case_num(suite, test_case),
0564 test_case->name,
0565 test.status_comment);
0566
0567 kunit_update_stats(&suite_stats, test_case->status);
0568 kunit_accumulate_stats(&total_stats, param_stats);
0569 }
0570
0571 if (suite->suite_exit)
0572 suite->suite_exit(suite);
0573
0574 kunit_print_suite_stats(suite, suite_stats, total_stats);
0575 suite_end:
0576 kunit_print_suite_end(suite);
0577
0578 return 0;
0579 }
0580 EXPORT_SYMBOL_GPL(kunit_run_tests);
0581
0582 static void kunit_init_suite(struct kunit_suite *suite)
0583 {
0584 kunit_debugfs_create_suite(suite);
0585 suite->status_comment[0] = '\0';
0586 suite->suite_init_err = 0;
0587 }
0588
0589 int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites)
0590 {
0591 unsigned int i;
0592
0593 for (i = 0; i < num_suites; i++) {
0594 kunit_init_suite(suites[i]);
0595 kunit_run_tests(suites[i]);
0596 }
0597 return 0;
0598 }
0599 EXPORT_SYMBOL_GPL(__kunit_test_suites_init);
0600
0601 static void kunit_exit_suite(struct kunit_suite *suite)
0602 {
0603 kunit_debugfs_destroy_suite(suite);
0604 }
0605
0606 void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites)
0607 {
0608 unsigned int i;
0609
0610 for (i = 0; i < num_suites; i++)
0611 kunit_exit_suite(suites[i]);
0612
0613 kunit_suite_counter = 1;
0614 }
0615 EXPORT_SYMBOL_GPL(__kunit_test_suites_exit);
0616
0617 #ifdef CONFIG_MODULES
0618 static void kunit_module_init(struct module *mod)
0619 {
0620 __kunit_test_suites_init(mod->kunit_suites, mod->num_kunit_suites);
0621 }
0622
0623 static void kunit_module_exit(struct module *mod)
0624 {
0625 __kunit_test_suites_exit(mod->kunit_suites, mod->num_kunit_suites);
0626 }
0627
0628 static int kunit_module_notify(struct notifier_block *nb, unsigned long val,
0629 void *data)
0630 {
0631 struct module *mod = data;
0632
0633 switch (val) {
0634 case MODULE_STATE_LIVE:
0635 kunit_module_init(mod);
0636 break;
0637 case MODULE_STATE_GOING:
0638 kunit_module_exit(mod);
0639 break;
0640 case MODULE_STATE_COMING:
0641 case MODULE_STATE_UNFORMED:
0642 break;
0643 }
0644
0645 return 0;
0646 }
0647
0648 static struct notifier_block kunit_mod_nb = {
0649 .notifier_call = kunit_module_notify,
0650 .priority = 0,
0651 };
0652 #endif
0653
0654 struct kunit_kmalloc_array_params {
0655 size_t n;
0656 size_t size;
0657 gfp_t gfp;
0658 };
0659
0660 static int kunit_kmalloc_array_init(struct kunit_resource *res, void *context)
0661 {
0662 struct kunit_kmalloc_array_params *params = context;
0663
0664 res->data = kmalloc_array(params->n, params->size, params->gfp);
0665 if (!res->data)
0666 return -ENOMEM;
0667
0668 return 0;
0669 }
0670
0671 static void kunit_kmalloc_array_free(struct kunit_resource *res)
0672 {
0673 kfree(res->data);
0674 }
0675
0676 void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp)
0677 {
0678 struct kunit_kmalloc_array_params params = {
0679 .size = size,
0680 .n = n,
0681 .gfp = gfp
0682 };
0683
0684 return kunit_alloc_resource(test,
0685 kunit_kmalloc_array_init,
0686 kunit_kmalloc_array_free,
0687 gfp,
0688 ¶ms);
0689 }
0690 EXPORT_SYMBOL_GPL(kunit_kmalloc_array);
0691
0692 void kunit_kfree(struct kunit *test, const void *ptr)
0693 {
0694 struct kunit_resource *res;
0695
0696 res = kunit_find_resource(test, kunit_resource_instance_match,
0697 (void *)ptr);
0698
0699
0700
0701
0702
0703 kunit_remove_resource(test, res);
0704
0705 kunit_put_resource(res);
0706
0707 }
0708 EXPORT_SYMBOL_GPL(kunit_kfree);
0709
0710 void kunit_cleanup(struct kunit *test)
0711 {
0712 struct kunit_resource *res;
0713 unsigned long flags;
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724 while (true) {
0725 spin_lock_irqsave(&test->lock, flags);
0726 if (list_empty(&test->resources)) {
0727 spin_unlock_irqrestore(&test->lock, flags);
0728 break;
0729 }
0730 res = list_last_entry(&test->resources,
0731 struct kunit_resource,
0732 node);
0733
0734
0735
0736
0737
0738 spin_unlock_irqrestore(&test->lock, flags);
0739 kunit_remove_resource(test, res);
0740 }
0741 current->kunit_test = NULL;
0742 }
0743 EXPORT_SYMBOL_GPL(kunit_cleanup);
0744
0745 static int __init kunit_init(void)
0746 {
0747 kunit_debugfs_init();
0748 #ifdef CONFIG_MODULES
0749 return register_module_notifier(&kunit_mod_nb);
0750 #else
0751 return 0;
0752 #endif
0753 }
0754 late_initcall(kunit_init);
0755
0756 static void __exit kunit_exit(void)
0757 {
0758 #ifdef CONFIG_MODULES
0759 unregister_module_notifier(&kunit_mod_nb);
0760 #endif
0761 kunit_debugfs_cleanup();
0762 }
0763 module_exit(kunit_exit);
0764
0765 MODULE_LICENSE("GPL v2");