History

Merge tag 'linux_kselftest-kunit-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kunit updates from Shuah Khan: - New parameterized test features KUnit parameterized tests supported two primary methods for getting parameters: - Defining custom logic within a generate_params() function. - Using the KUNIT_ARRAY_PARAM() and KUNIT_ARRAY_PARAM_DESC() macros with a pre-defined static array and passing the created *_gen_params() to KUNIT_CASE_PARAM(). These methods present limitations when dealing with dynamically generated parameter arrays, or in scenarios where populating parameters sequentially via generate_params() is inefficient or overly complex. These limitations are fixed with a parameterized test method - Fix issues in kunit build artifacts cleanup - Fix parsing skipped test problem in kselftest framework - Enable PCI on UML without triggering WARN() - a few other fixes and adds support for new configs such as MIPS * tag 'linux_kselftest-kunit-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: kunit: Extend kconfig help text for KUNIT_UML_PCI rust: kunit: allow `cfg` on `test`s kunit: qemu_configs: Add MIPS configurations kunit: Enable PCI on UML without triggering WARN() Documentation: kunit: Document new parameterized test features kunit: Add example parameterized test with direct dynamic parameter array setup kunit: Add example parameterized test with shared resource management using the Resource API kunit: Enable direct registration of parameter arrays to a KUnit test kunit: Pass parameterized test context to generate_params() kunit: Introduce param_init/exit for parameterized test context management kunit: Add parent kunit for parameterized test context kunit: tool: Accept --raw_output=full as an alias of 'all' kunit: tool: Parse skipped tests from kselftest.h kunit: Always descend into kunit directory during build

Linus Torvalds committed 1 year ago

Commit 30bbcb42 parents d2b2fea 285cae520 files · +880 −63Browse files

Showing the changes to lib (5 of 20 files). Show all

Unified · Split

5 files
  1. lib/Makefile +0 −4
  2. lib/kunit/Kconfig +11 −0
  3. lib/kunit/Makefile +1 −1
  4. lib/kunit/kunit-example-test.c +217 −0
  5. lib/kunit/test.c +79 −15
lib/Makefile+0−4
@@ -109,11 +109,7 @@ test_fpu-y := test_fpu_glue.o test_fpu_impl.o · 108 unmodified lines
109CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU)109CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU)
110CFLAGS_REMOVE_test_fpu_impl.o += $(CC_FLAGS_NO_FPU)110CFLAGS_REMOVE_test_fpu_impl.o += $(CC_FLAGS_NO_FPU)
111 111
112# Some KUnit files (hooks.o) need to be built-in even when KUnit is a module,
113# so we can't just use obj-$(CONFIG_KUNIT).
114ifdef CONFIG_KUNIT
115obj-y += kunit/112obj-y += kunit/
116endif
117 113
118ifeq ($(CONFIG_DEBUG_KOBJECT),y)114ifeq ($(CONFIG_DEBUG_KOBJECT),y)
119CFLAGS_kobject.o += -DDEBUG115CFLAGS_kobject.o += -DDEBUG
lib/kunit/Kconfig+11−0
@@ -106,4 +106,15 @@ config KUNIT_DEFAULT_TIMEOUT · 105 unmodified lines
106 If unsure, the default timeout of 300 seconds is suitable for most106 If unsure, the default timeout of 300 seconds is suitable for most
107 cases.107 cases.
108 108
109config KUNIT_UML_PCI
110 bool "KUnit UML PCI Support"
111 depends on UML
112 select UML_PCI
113 help
114 Enables the PCI subsystem on UML for use by KUnit tests.
115 Some KUnit tests require the PCI core which is not enabled by
116 default on UML.
117
118 If unsure, say N.
119
109endif # KUNIT120endif # KUNIT
lib/kunit/Makefile+1−1
@@ -17,7 +17,7 @@ kunit-objs += debugfs.o · 16 unmodified lines
17endif17endif
18 18
19# KUnit 'hooks' are built-in even when KUnit is built as a module.19# KUnit 'hooks' are built-in even when KUnit is built as a module.
20obj-y += hooks.o20obj-$(if $(CONFIG_KUNIT),y) += hooks.o
21 21
22obj-$(CONFIG_KUNIT_TEST) += kunit-test.o22obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
23obj-$(CONFIG_KUNIT_TEST) += platform-test.o23obj-$(CONFIG_KUNIT_TEST) += platform-test.o
lib/kunit/kunit-example-test.c+217−0
@@ -277,6 +277,218 @@ static void example_slow_test(struct kunit *test) · 276 unmodified lines
277 KUNIT_EXPECT_EQ(test, 1 + 1, 2);277 KUNIT_EXPECT_EQ(test, 1 + 1, 2);
278}278}
279 279
280/*
281 * This custom function allocates memory and sets the information we want
282 * stored in the kunit_resource->data field.
283 */
284static int example_resource_init(struct kunit_resource *res, void *context)
285{
286 int *info = kmalloc(sizeof(*info), GFP_KERNEL);
287
288 if (!info)
289 return -ENOMEM;
290 *info = *(int *)context;
291 res->data = info;
292 return 0;
293}
294
295/*
296 * This function deallocates memory for the kunit_resource->data field.
297 */
298static void example_resource_free(struct kunit_resource *res)
299{
300 kfree(res->data);
301}
302
303/*
304 * This match function is invoked by kunit_find_resource() to locate
305 * a test resource based on certain criteria.
306 */
307static bool example_resource_alloc_match(struct kunit *test,
308 struct kunit_resource *res,
309 void *match_data)
310{
311 return res->data && res->free == example_resource_free;
312}
313
314/*
315 * This is an example of a function that provides a description for each of the
316 * parameters in a parameterized test.
317 */
318static void example_param_array_get_desc(struct kunit *test, const void *p, char *desc)
319{
320 const struct example_param *param = p;
321
322 snprintf(desc, KUNIT_PARAM_DESC_SIZE,
323 "example check if %d is less than or equal to 3", param->value);
324}
325
326/*
327 * This function gets passed in the parameterized test context i.e. the
328 * struct kunit belonging to the parameterized test. You can use this function
329 * to add resources you want shared across the whole parameterized test or
330 * for additional setup.
331 */
332static int example_param_init(struct kunit *test)
333{
334 int ctx = 3; /* Data to be stored. */
335 size_t arr_size = ARRAY_SIZE(example_params_array);
336
337 /*
338 * This allocates a struct kunit_resource, sets its data field to
339 * ctx, and adds it to the struct kunit's resources list. Note that
340 * this is parameterized test managed. So, it doesn't need to have
341 * a custom exit function to deallocation as it will get cleaned up at
342 * the end of the parameterized test.
343 */
344 void *data = kunit_alloc_resource(test, example_resource_init, example_resource_free,
345 GFP_KERNEL, &ctx);
346
347 if (!data)
348 return -ENOMEM;
349 /*
350 * Pass the parameter array information to the parameterized test context
351 * struct kunit. Note that you will need to provide kunit_array_gen_params()
352 * as the generator function to KUNIT_CASE_PARAM_WITH_INIT() when registering
353 * a parameter array this route.
354 */
355 kunit_register_params_array(test, example_params_array, arr_size,
356 example_param_array_get_desc);
357 return 0;
358}
359
360/*
361 * This is an example of a test that uses shared resources available in the
362 * parameterized test context.
363 */
364static void example_params_test_with_init(struct kunit *test)
365{
366 int threshold;
367 struct kunit_resource *res;
368 const struct example_param *param = test->param_value;
369
370 /* By design, param pointer will not be NULL. */
371 KUNIT_ASSERT_NOT_NULL(test, param);
372
373 /*
374 * Here we pass test->parent to search for shared resources in the
375 * parameterized test context.
376 */
377 res = kunit_find_resource(test->parent, example_resource_alloc_match, NULL);
378
379 KUNIT_ASSERT_NOT_NULL(test, res);
380
381 /* Since kunit_resource->data is a void pointer we need to typecast it. */
382 threshold = *((int *)res->data);
383
384 /* Assert that the parameter is less than or equal to a certain threshold. */
385 KUNIT_ASSERT_LE(test, param->value, threshold);
386
387 /* This decreases the reference count after calling kunit_find_resource(). */
388 kunit_put_resource(res);
389}
390
391/*
392 * Helper function to create a parameter array of Fibonacci numbers. This example
393 * highlights a parameter generation scenario that is:
394 * 1. Not feasible to fully pre-generate at compile time.
395 * 2. Challenging to implement with a standard generate_params() function,
396 * as it only provides the previous parameter, while Fibonacci requires
397 * access to two preceding values for calculation.
398 */
399static void *make_fibonacci_params(struct kunit *test, size_t seq_size)
400{
401 int *seq;
402
403 if (seq_size <= 0)
404 return NULL;
405 /*
406 * Using kunit_kmalloc_array here ties the lifetime of the array to
407 * the parameterized test i.e. it will get automatically cleaned up
408 * by KUnit after the parameterized test finishes.
409 */
410 seq = kunit_kmalloc_array(test, seq_size, sizeof(int), GFP_KERNEL);
411
412 if (!seq)
413 return NULL;
414 if (seq_size >= 1)
415 seq[0] = 0;
416 if (seq_size >= 2)
417 seq[1] = 1;
418 for (int i = 2; i < seq_size; i++)
419 seq[i] = seq[i - 1] + seq[i - 2];
420 return seq;
421}
422
423/*
424 * This is an example of a function that provides a description for each of the
425 * parameters.
426 */
427static void example_param_dynamic_arr_get_desc(struct kunit *test, const void *p, char *desc)
428{
429 const int *fib_num = p;
430
431 snprintf(desc, KUNIT_PARAM_DESC_SIZE, "fibonacci param: %d", *fib_num);
432}
433
434/*
435 * Example of a parameterized test param_init() function that registers a dynamic
436 * array of parameters.
437 */
438static int example_param_init_dynamic_arr(struct kunit *test)
439{
440 size_t seq_size;
441 int *fibonacci_params;
442
443 kunit_info(test, "initializing parameterized test\n");
444
445 seq_size = 6;
446 fibonacci_params = make_fibonacci_params(test, seq_size);
447
448 if (!fibonacci_params)
449 return -ENOMEM;
450
451 /*
452 * Passes the dynamic parameter array information to the parameterized test
453 * context struct kunit. The array and its metadata will be stored in
454 * test->parent->params_array. The array itself will be located in
455 * params_data.params.
456 *
457 * Note that you will need to pass kunit_array_gen_params() as the
458 * generator function to KUNIT_CASE_PARAM_WITH_INIT() when registering
459 * a parameter array this route.
460 */
461 kunit_register_params_array(test, fibonacci_params, seq_size,
462 example_param_dynamic_arr_get_desc);
463 return 0;
464}
465
466/*
467 * Example of a parameterized test param_exit() function that outputs a log
468 * at the end of the parameterized test. It could also be used for any other
469 * teardown logic.
470 */
471static void example_param_exit_dynamic_arr(struct kunit *test)
472{
473 kunit_info(test, "exiting parameterized test\n");
474}
475
476/*
477 * Example of test that uses the registered dynamic array to perform assertions
478 * and expectations.
479 */
480static void example_params_test_with_init_dynamic_arr(struct kunit *test)
481{
482 const int *param = test->param_value;
483 int param_val;
484
485 /* By design, param pointer will not be NULL. */
486 KUNIT_ASSERT_NOT_NULL(test, param);
487
488 param_val = *param;
489 KUNIT_EXPECT_EQ(test, param_val - param_val, 0);
490}
491
280/*492/*
281 * Here we make a list of all the test cases we want to add to the test suite493 * Here we make a list of all the test cases we want to add to the test suite
282 * below.494 * below.
@@ -296,6 +508,11 @@ static struct kunit_case example_test_cases[] = { · 13 unmodified lines
296 KUNIT_CASE(example_static_stub_using_fn_ptr_test),508 KUNIT_CASE(example_static_stub_using_fn_ptr_test),
297 KUNIT_CASE(example_priv_test),509 KUNIT_CASE(example_priv_test),
298 KUNIT_CASE_PARAM(example_params_test, example_gen_params),510 KUNIT_CASE_PARAM(example_params_test, example_gen_params),
511 KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen_params,
512 example_param_init, NULL),
513 KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr,
514 kunit_array_gen_params, example_param_init_dynamic_arr,
515 example_param_exit_dynamic_arr),
299 KUNIT_CASE_SLOW(example_slow_test),516 KUNIT_CASE_SLOW(example_slow_test),
300 {}517 {}
301};518};
lib/kunit/test.c+79−15
@@ -337,6 +337,14 @@ void __kunit_do_failed_assertion(struct kunit *test, · 336 unmodified lines
337}337}
338EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion);338EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion);
339 339
340static void kunit_init_params(struct kunit *test)
341{
342 test->params_array.params = NULL;
343 test->params_array.get_description = NULL;
344 test->params_array.num_params = 0;
345 test->params_array.elem_size = 0;
346}
347
340void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log)348void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log)
341{349{
342 spin_lock_init(&test->lock);350 spin_lock_init(&test->lock);
@@ -347,6 +355,7 @@ void kunit_init_test(struct kunit *test, const char *name, struct string_stream · 4 unmodified lines
347 string_stream_clear(log);355 string_stream_clear(log);
348 test->status = KUNIT_SUCCESS;356 test->status = KUNIT_SUCCESS;
349 test->status_comment[0] = '\0';357 test->status_comment[0] = '\0';
358 kunit_init_params(test);
350}359}
351EXPORT_SYMBOL_GPL(kunit_init_test);360EXPORT_SYMBOL_GPL(kunit_init_test);
352 361
@@ -641,12 +650,44 @@ static void kunit_accumulate_stats(struct kunit_result_stats *total, · 288 unmodified lines
641 total->total += add.total;650 total->total += add.total;
642}651}
643 652
653const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc)
654{
655 struct kunit_params *params_arr = &test->params_array;
656 const void *param;
657
658 if (test->param_index < params_arr->num_params) {
659 param = (char *)params_arr->params
660 + test->param_index * params_arr->elem_size;
661
662 if (params_arr->get_description)
663 params_arr->get_description(test, param, desc);
664 return param;
665 }
666 return NULL;
667}
668EXPORT_SYMBOL_GPL(kunit_array_gen_params);
669
670static void kunit_init_parent_param_test(struct kunit_case *test_case, struct kunit *test)
671{
672 if (test_case->param_init) {
673 int err = test_case->param_init(test);
674
675 if (err) {
676 kunit_err(test_case, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
677 "# failed to initialize parent parameter test (%d)", err);
678 test->status = KUNIT_FAILURE;
679 test_case->status = KUNIT_FAILURE;
680 }
681 }
682}
683
644int kunit_run_tests(struct kunit_suite *suite)684int kunit_run_tests(struct kunit_suite *suite)
645{685{
646 char param_desc[KUNIT_PARAM_DESC_SIZE];686 char param_desc[KUNIT_PARAM_DESC_SIZE];
647 struct kunit_case *test_case;687 struct kunit_case *test_case;
648 struct kunit_result_stats suite_stats = { 0 };688 struct kunit_result_stats suite_stats = { 0 };
649 struct kunit_result_stats total_stats = { 0 };689 struct kunit_result_stats total_stats = { 0 };
690 const void *curr_param;
650 691
651 /* Taint the kernel so we know we've run tests. */692 /* Taint the kernel so we know we've run tests. */
652 add_taint(TAINT_TEST, LOCKDEP_STILL_OK);693 add_taint(TAINT_TEST, LOCKDEP_STILL_OK);
@@ -677,41 +718,64 @@ int kunit_run_tests(struct kunit_suite *suite) · 24 unmodified lines
677 kunit_run_case_catch_errors(suite, test_case, &test);718 kunit_run_case_catch_errors(suite, test_case, &test);
678 kunit_update_stats(&param_stats, test.status);719 kunit_update_stats(&param_stats, test.status);
679 } else {720 } else {
721 kunit_init_parent_param_test(test_case, &test);
722 if (test_case->status == KUNIT_FAILURE) {
723 kunit_update_stats(&param_stats, test.status);
724 goto test_case_end;
725 }
680 /* Get initial param. */726 /* Get initial param. */
681 param_desc[0] = '\0';727 param_desc[0] = '\0';
682 test.param_value = test_case->generate_params(NULL, param_desc);728 /* TODO: Make generate_params try-catch */
729 curr_param = test_case->generate_params(&test, NULL, param_desc);
683 test_case->status = KUNIT_SKIPPED;730 test_case->status = KUNIT_SKIPPED;
684 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT731 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
685 "KTAP version 1\n");732 "KTAP version 1\n");
686 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT733 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
687 "# Subtest: %s", test_case->name);734 "# Subtest: %s", test_case->name);
735 if (test.params_array.params &&
736 test_case->generate_params == kunit_array_gen_params) {
737 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT
738 KUNIT_SUBTEST_INDENT "1..%zd\n",
739 test.params_array.num_params);
740 }
688 741
689 while (test.param_value) {742 while (curr_param) {
690 kunit_run_case_catch_errors(suite, test_case, &test);743 struct kunit param_test = {
744 .param_value = curr_param,
745 .param_index = ++test.param_index,
746 .parent = &test,
747 };
748 kunit_init_test(&param_test, test_case->name, test_case->log);
749 kunit_run_case_catch_errors(suite, test_case, &param_test);
691 750
692 if (param_desc[0] == '\0') {751 if (param_desc[0] == '\0') {
693 snprintf(param_desc, sizeof(param_desc),752 snprintf(param_desc, sizeof(param_desc),
694 "param-%d", test.param_index);753 "param-%d", param_test.param_index);
695 }754 }
696 755
697 kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE_PARAM,756 kunit_print_ok_not_ok(&param_test, KUNIT_LEVEL_CASE_PARAM,
698 test.status,757 param_test.status,
699 test.param_index + 1,758 param_test.param_index,
700 param_desc,759 param_desc,
701 test.status_comment);760 param_test.status_comment);
702 761
703 kunit_update_stats(&param_stats, test.status);762 kunit_update_stats(&param_stats, param_test.status);
704 763
705 /* Get next param. */764 /* Get next param. */
706 param_desc[0] = '\0';765 param_desc[0] = '\0';
707 test.param_value = test_case->generate_params(test.param_value, param_desc);766 curr_param = test_case->generate_params(&test, curr_param,
708 test.param_index++;767 param_desc);
709 test.status = KUNIT_SUCCESS;
710 test.status_comment[0] = '\0';
711 test.priv = NULL;
712 }768 }
769 /*
770 * TODO: Put into a try catch. Since we don't need suite->exit
771 * for it we can't reuse kunit_try_run_cleanup for this yet.
772 */
773 if (test_case->param_exit)
774 test_case->param_exit(&test);
775 /* TODO: Put this kunit_cleanup into a try-catch. */
776 kunit_cleanup(&test);
713 }777 }
714 778test_case_end:
715 kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE);779 kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE);
716 780
717 kunit_print_test_stats(&test, param_stats);781 kunit_print_test_stats(&test, param_stats);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t