Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+880 -63
+337 -5
Documentation/dev-tools/kunit/usage.rst
··· 542 542 Parameterized Testing 543 543 ~~~~~~~~~~~~~~~~~~~~~ 544 544 545 - The table-driven testing pattern is common enough that KUnit has special 546 - support for it. 545 + To run a test case against multiple inputs, KUnit provides a parameterized 546 + testing framework. This feature formalizes and extends the concept of 547 + table-driven tests discussed previously. 547 548 548 - By reusing the same ``cases`` array from above, we can write the test as a 549 - "parameterized test" with the following. 549 + A KUnit test is determined to be parameterized if a parameter generator function 550 + is provided when registering the test case. A test user can either write their 551 + own generator function or use one that is provided by KUnit. The generator 552 + function is stored in ``kunit_case->generate_params`` and can be set using the 553 + macros described in the section below. 554 + 555 + To establish the terminology, a "parameterized test" is a test which is run 556 + multiple times (once per "parameter" or "parameter run"). Each parameter run has 557 + both its own independent ``struct kunit`` (the "parameter run context") and 558 + access to a shared parent ``struct kunit`` (the "parameterized test context"). 559 + 560 + Passing Parameters to a Test 561 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 562 + There are three ways to provide the parameters to a test: 563 + 564 + Array Parameter Macros: 565 + 566 + KUnit provides special support for the common table-driven testing pattern. 567 + By applying either ``KUNIT_ARRAY_PARAM`` or ``KUNIT_ARRAY_PARAM_DESC`` to the 568 + ``cases`` array from the previous section, we can create a parameterized test 569 + as shown below: 550 570 551 571 .. code-block:: c 552 572 ··· 575 555 const char *str; 576 556 const char *sha1; 577 557 }; 578 - const struct sha1_test_case cases[] = { 558 + static const struct sha1_test_case cases[] = { 579 559 { 580 560 .str = "hello world", 581 561 .sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", ··· 607 587 // function declared by KUNIT_ARRAY_PARAM or KUNIT_ARRAY_PARAM_DESC. 608 588 static struct kunit_case sha1_test_cases[] = { 609 589 KUNIT_CASE_PARAM(sha1_test, sha1_gen_params), 590 + {} 591 + }; 592 + 593 + Custom Parameter Generator Function: 594 + 595 + The generator function is responsible for generating parameters one-by-one 596 + and has the following signature: 597 + ``const void* (*)(struct kunit *test, const void *prev, char *desc)``. 598 + You can pass the generator function to the ``KUNIT_CASE_PARAM`` 599 + or ``KUNIT_CASE_PARAM_WITH_INIT`` macros. 600 + 601 + The function receives the previously generated parameter as the ``prev`` argument 602 + (which is ``NULL`` on the first call) and can also access the parameterized 603 + test context passed as the ``test`` argument. KUnit calls this function 604 + repeatedly until it returns ``NULL``, which signifies that a parameterized 605 + test ended. 606 + 607 + Below is an example of how it works: 608 + 609 + .. code-block:: c 610 + 611 + #define MAX_TEST_BUFFER_SIZE 8 612 + 613 + // Example generator function. It produces a sequence of buffer sizes that 614 + // are powers of two, starting at 1 (e.g., 1, 2, 4, 8). 615 + static const void *buffer_size_gen_params(struct kunit *test, const void *prev, char *desc) 616 + { 617 + long prev_buffer_size = (long)prev; 618 + long next_buffer_size = 1; // Start with an initial size of 1. 619 + 620 + // Stop generating parameters if the limit is reached or exceeded. 621 + if (prev_buffer_size >= MAX_TEST_BUFFER_SIZE) 622 + return NULL; 623 + 624 + // For subsequent calls, calculate the next size by doubling the previous one. 625 + if (prev) 626 + next_buffer_size = prev_buffer_size << 1; 627 + 628 + return (void *)next_buffer_size; 629 + } 630 + 631 + // Simple test to validate that kunit_kzalloc provides zeroed memory. 632 + static void buffer_zero_test(struct kunit *test) 633 + { 634 + long buffer_size = (long)test->param_value; 635 + // Use kunit_kzalloc to allocate a zero-initialized buffer. This makes the 636 + // memory "parameter run managed," meaning it's automatically cleaned up at 637 + // the end of each parameter run. 638 + int *buf = kunit_kzalloc(test, buffer_size * sizeof(int), GFP_KERNEL); 639 + 640 + // Ensure the allocation was successful. 641 + KUNIT_ASSERT_NOT_NULL(test, buf); 642 + 643 + // Loop through the buffer and confirm every element is zero. 644 + for (int i = 0; i < buffer_size; i++) 645 + KUNIT_EXPECT_EQ(test, buf[i], 0); 646 + } 647 + 648 + static struct kunit_case buffer_test_cases[] = { 649 + KUNIT_CASE_PARAM(buffer_zero_test, buffer_size_gen_params), 650 + {} 651 + }; 652 + 653 + Runtime Parameter Array Registration in the Init Function: 654 + 655 + For scenarios where you might need to initialize a parameterized test, you 656 + can directly register a parameter array to the parameterized test context. 657 + 658 + To do this, you must pass the parameterized test context, the array itself, 659 + the array size, and a ``get_description()`` function to the 660 + ``kunit_register_params_array()`` macro. This macro populates 661 + ``struct kunit_params`` within the parameterized test context, effectively 662 + storing a parameter array object. The ``get_description()`` function will 663 + be used for populating parameter descriptions and has the following signature: 664 + ``void (*)(struct kunit *test, const void *param, char *desc)``. Note that it 665 + also has access to the parameterized test context. 666 + 667 + .. important:: 668 + When using this way to register a parameter array, you will need to 669 + manually pass ``kunit_array_gen_params()`` as the generator function to 670 + ``KUNIT_CASE_PARAM_WITH_INIT``. ``kunit_array_gen_params()`` is a KUnit 671 + helper that will use the registered array to generate the parameters. 672 + 673 + If needed, instead of passing the KUnit helper, you can also pass your 674 + own custom generator function that utilizes the parameter array. To 675 + access the parameter array from within the parameter generator 676 + function use ``test->params_array.params``. 677 + 678 + The ``kunit_register_params_array()`` macro should be called within a 679 + ``param_init()`` function that initializes the parameterized test and has 680 + the following signature ``int (*)(struct kunit *test)``. For a detailed 681 + explanation of this mechanism please refer to the "Adding Shared Resources" 682 + section that is after this one. This method supports registering both 683 + dynamically built and static parameter arrays. 684 + 685 + The code snippet below shows the ``example_param_init_dynamic_arr`` test that 686 + utilizes ``make_fibonacci_params()`` to create a dynamic array, which is then 687 + registered using ``kunit_register_params_array()``. To see the full code 688 + please refer to lib/kunit/kunit-example-test.c. 689 + 690 + .. code-block:: c 691 + 692 + /* 693 + * Example of a parameterized test param_init() function that registers a dynamic 694 + * array of parameters. 695 + */ 696 + static int example_param_init_dynamic_arr(struct kunit *test) 697 + { 698 + size_t seq_size; 699 + int *fibonacci_params; 700 + 701 + kunit_info(test, "initializing parameterized test\n"); 702 + 703 + seq_size = 6; 704 + fibonacci_params = make_fibonacci_params(test, seq_size); 705 + if (!fibonacci_params) 706 + return -ENOMEM; 707 + /* 708 + * Passes the dynamic parameter array information to the parameterized test 709 + * context struct kunit. The array and its metadata will be stored in 710 + * test->parent->params_array. The array itself will be located in 711 + * params_data.params. 712 + */ 713 + kunit_register_params_array(test, fibonacci_params, seq_size, 714 + example_param_dynamic_arr_get_desc); 715 + return 0; 716 + } 717 + 718 + static struct kunit_case example_test_cases[] = { 719 + /* 720 + * Note how we pass kunit_array_gen_params() to use the array we 721 + * registered in example_param_init_dynamic_arr() to generate 722 + * parameters. 723 + */ 724 + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr, 725 + kunit_array_gen_params, 726 + example_param_init_dynamic_arr, 727 + example_param_exit_dynamic_arr), 728 + {} 729 + }; 730 + 731 + Adding Shared Resources 732 + ^^^^^^^^^^^^^^^^^^^^^^^ 733 + All parameter runs in this framework hold a reference to the parameterized test 734 + context, which can be accessed using the parent ``struct kunit`` pointer. The 735 + parameterized test context is not used to execute any test logic itself; instead, 736 + it serves as a container for shared resources. 737 + 738 + It's possible to add resources to share between parameter runs within a 739 + parameterized test by using ``KUNIT_CASE_PARAM_WITH_INIT``, to which you pass 740 + custom ``param_init()`` and ``param_exit()`` functions. These functions run once 741 + before and once after the parameterized test, respectively. 742 + 743 + The ``param_init()`` function, with the signature ``int (*)(struct kunit *test)``, 744 + can be used for adding resources to the ``resources`` or ``priv`` fields of 745 + the parameterized test context, registering the parameter array, and any other 746 + initialization logic. 747 + 748 + The ``param_exit()`` function, with the signature ``void (*)(struct kunit *test)``, 749 + can be used to release any resources that were not parameterized test managed (i.e. 750 + not automatically cleaned up after the parameterized test ends) and for any other 751 + exit logic. 752 + 753 + Both ``param_init()`` and ``param_exit()`` are passed the parameterized test 754 + context behind the scenes. However, the test case function receives the parameter 755 + run context. Therefore, to manage and access shared resources from within a test 756 + case function, you must use ``test->parent``. 757 + 758 + For instance, finding a shared resource allocated by the Resource API requires 759 + passing ``test->parent`` to ``kunit_find_resource()``. This principle extends to 760 + all other APIs that might be used in the test case function, including 761 + ``kunit_kzalloc()``, ``kunit_kmalloc_array()``, and others (see 762 + Documentation/dev-tools/kunit/api/test.rst and the 763 + Documentation/dev-tools/kunit/api/resource.rst). 764 + 765 + .. note:: 766 + The ``suite->init()`` function, which executes before each parameter run, 767 + receives the parameter run context. Therefore, any resources set up in 768 + ``suite->init()`` are cleaned up after each parameter run. 769 + 770 + The code below shows how you can add the shared resources. Note that this code 771 + utilizes the Resource API, which you can read more about here: 772 + Documentation/dev-tools/kunit/api/resource.rst. To see the full version of this 773 + code please refer to lib/kunit/kunit-example-test.c. 774 + 775 + .. code-block:: c 776 + 777 + static int example_resource_init(struct kunit_resource *res, void *context) 778 + { 779 + ... /* Code that allocates memory and stores context in res->data. */ 780 + } 781 + 782 + /* This function deallocates memory for the kunit_resource->data field. */ 783 + static void example_resource_free(struct kunit_resource *res) 784 + { 785 + kfree(res->data); 786 + } 787 + 788 + /* This match function locates a test resource based on defined criteria. */ 789 + static bool example_resource_alloc_match(struct kunit *test, struct kunit_resource *res, 790 + void *match_data) 791 + { 792 + return res->data && res->free == example_resource_free; 793 + } 794 + 795 + /* Function to initialize the parameterized test. */ 796 + static int example_param_init(struct kunit *test) 797 + { 798 + int ctx = 3; /* Data to be stored. */ 799 + void *data = kunit_alloc_resource(test, example_resource_init, 800 + example_resource_free, 801 + GFP_KERNEL, &ctx); 802 + if (!data) 803 + return -ENOMEM; 804 + kunit_register_params_array(test, example_params_array, 805 + ARRAY_SIZE(example_params_array)); 806 + return 0; 807 + } 808 + 809 + /* Example test that uses shared resources in test->resources. */ 810 + static void example_params_test_with_init(struct kunit *test) 811 + { 812 + int threshold; 813 + const struct example_param *param = test->param_value; 814 + /* Here we pass test->parent to access the parameterized test context. */ 815 + struct kunit_resource *res = kunit_find_resource(test->parent, 816 + example_resource_alloc_match, 817 + NULL); 818 + 819 + threshold = *((int *)res->data); 820 + KUNIT_ASSERT_LE(test, param->value, threshold); 821 + kunit_put_resource(res); 822 + } 823 + 824 + static struct kunit_case example_test_cases[] = { 825 + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen_params, 826 + example_param_init, NULL), 827 + {} 828 + }; 829 + 830 + As an alternative to using the KUnit Resource API for sharing resources, you can 831 + place them in ``test->parent->priv``. This serves as a more lightweight method 832 + for resource storage, best for scenarios where complex resource management is 833 + not required. 834 + 835 + As stated previously ``param_init()`` and ``param_exit()`` get the parameterized 836 + test context. So, you can directly use ``test->priv`` within ``param_init/exit`` 837 + to manage shared resources. However, from within the test case function, you must 838 + navigate up to the parent ``struct kunit`` i.e. the parameterized test context. 839 + Therefore, you need to use ``test->parent->priv`` to access those same 840 + resources. 841 + 842 + The resources placed in ``test->parent->priv`` will need to be allocated in 843 + memory to persist across the parameter runs. If memory is allocated using the 844 + KUnit memory allocation APIs (described more in the "Allocating Memory" section 845 + below), you won't need to worry about deallocation. The APIs will make the memory 846 + parameterized test 'managed', ensuring that it will automatically get cleaned up 847 + after the parameterized test concludes. 848 + 849 + The code below demonstrates example usage of the ``priv`` field for shared 850 + resources: 851 + 852 + .. code-block:: c 853 + 854 + static const struct example_param { 855 + int value; 856 + } example_params_array[] = { 857 + { .value = 3, }, 858 + { .value = 2, }, 859 + { .value = 1, }, 860 + { .value = 0, }, 861 + }; 862 + 863 + /* Initialize the parameterized test context. */ 864 + static int example_param_init_priv(struct kunit *test) 865 + { 866 + int ctx = 3; /* Data to be stored. */ 867 + int arr_size = ARRAY_SIZE(example_params_array); 868 + 869 + /* 870 + * Allocate memory using kunit_kzalloc(). Since the `param_init` 871 + * function receives the parameterized test context, this memory 872 + * allocation will be scoped to the lifetime of the parameterized test. 873 + */ 874 + test->priv = kunit_kzalloc(test, sizeof(int), GFP_KERNEL); 875 + 876 + /* Assign the context value to test->priv.*/ 877 + *((int *)test->priv) = ctx; 878 + 879 + /* Register the parameter array. */ 880 + kunit_register_params_array(test, example_params_array, arr_size, NULL); 881 + return 0; 882 + } 883 + 884 + static void example_params_test_with_init_priv(struct kunit *test) 885 + { 886 + int threshold; 887 + const struct example_param *param = test->param_value; 888 + 889 + /* By design, test->parent will not be NULL. */ 890 + KUNIT_ASSERT_NOT_NULL(test, test->parent); 891 + 892 + /* Here we use test->parent->priv to access the shared resource. */ 893 + threshold = *(int *)test->parent->priv; 894 + 895 + KUNIT_ASSERT_LE(test, param->value, threshold); 896 + } 897 + 898 + static struct kunit_case example_tests[] = { 899 + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_priv, 900 + kunit_array_gen_params, 901 + example_param_init_priv, NULL), 610 902 {} 611 903 }; 612 904
+7 -7
drivers/gpu/drm/xe/tests/xe_pci.c
··· 44 44 * 45 45 * Return: pointer to the next parameter or NULL if no more parameters 46 46 */ 47 - const void *xe_pci_graphics_ip_gen_param(const void *prev, char *desc) 47 + const void *xe_pci_graphics_ip_gen_param(struct kunit *test, const void *prev, char *desc) 48 48 { 49 - return graphics_ip_gen_params(prev, desc); 49 + return graphics_ip_gen_params(test, prev, desc); 50 50 } 51 51 EXPORT_SYMBOL_IF_KUNIT(xe_pci_graphics_ip_gen_param); 52 52 ··· 61 61 * 62 62 * Return: pointer to the next parameter or NULL if no more parameters 63 63 */ 64 - const void *xe_pci_media_ip_gen_param(const void *prev, char *desc) 64 + const void *xe_pci_media_ip_gen_param(struct kunit *test, const void *prev, char *desc) 65 65 { 66 - return media_ip_gen_params(prev, desc); 66 + return media_ip_gen_params(test, prev, desc); 67 67 } 68 68 EXPORT_SYMBOL_IF_KUNIT(xe_pci_media_ip_gen_param); 69 69 ··· 78 78 * 79 79 * Return: pointer to the next parameter or NULL if no more parameters 80 80 */ 81 - const void *xe_pci_id_gen_param(const void *prev, char *desc) 81 + const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char *desc) 82 82 { 83 - const struct pci_device_id *pci = pci_id_gen_params(prev, desc); 83 + const struct pci_device_id *pci = pci_id_gen_params(test, prev, desc); 84 84 85 85 return pci->driver_data ? pci : NULL; 86 86 } ··· 159 159 * Return: pointer to the next &struct xe_device ready to be used as a parameter 160 160 * or NULL if there are no more Xe devices on the system. 161 161 */ 162 - const void *xe_pci_live_device_gen_param(const void *prev, char *desc) 162 + const void *xe_pci_live_device_gen_param(struct kunit *test, const void *prev, char *desc) 163 163 { 164 164 const struct xe_device *xe = prev; 165 165 struct device *dev = xe ? xe->drm.dev : NULL;
+5 -4
drivers/gpu/drm/xe/tests/xe_pci_test.h
··· 7 7 #define _XE_PCI_TEST_H_ 8 8 9 9 #include <linux/types.h> 10 + #include <kunit/test.h> 10 11 11 12 #include "xe_platform_types.h" 12 13 #include "xe_sriov_types.h" ··· 26 25 27 26 int xe_pci_fake_device_init(struct xe_device *xe); 28 27 29 - const void *xe_pci_graphics_ip_gen_param(const void *prev, char *desc); 30 - const void *xe_pci_media_ip_gen_param(const void *prev, char *desc); 31 - const void *xe_pci_id_gen_param(const void *prev, char *desc); 32 - const void *xe_pci_live_device_gen_param(const void *prev, char *desc); 28 + const void *xe_pci_graphics_ip_gen_param(struct kunit *test, const void *prev, char *desc); 29 + const void *xe_pci_media_ip_gen_param(struct kunit *test, const void *prev, char *desc); 30 + const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char *desc); 31 + const void *xe_pci_live_device_gen_param(struct kunit *test, const void *prev, char *desc); 33 32 34 33 #endif
+90 -5
include/kunit/test.h
··· 92 92 * @name: the name of the test case. 93 93 * @generate_params: the generator function for parameterized tests. 94 94 * @attr: the attributes associated with the test 95 + * @param_init: The init function to run before a parameterized test. 96 + * @param_exit: The exit function to run after a parameterized test. 95 97 * 96 98 * A test case is a function with the signature, 97 99 * ``void (*)(struct kunit *)`` ··· 128 126 struct kunit_case { 129 127 void (*run_case)(struct kunit *test); 130 128 const char *name; 131 - const void* (*generate_params)(const void *prev, char *desc); 129 + const void* (*generate_params)(struct kunit *test, 130 + const void *prev, char *desc); 132 131 struct kunit_attributes attr; 132 + int (*param_init)(struct kunit *test); 133 + void (*param_exit)(struct kunit *test); 133 134 134 135 /* private: internal use only. */ 135 136 enum kunit_status status; ··· 224 219 .attr = attributes, .module_name = KBUILD_MODNAME} 225 220 226 221 /** 222 + * KUNIT_CASE_PARAM_WITH_INIT - Define a parameterized KUnit test case with custom 223 + * param_init() and param_exit() functions. 224 + * @test_name: The function implementing the test case. 225 + * @gen_params: The function to generate parameters for the test case. 226 + * @init: A reference to the param_init() function to run before a parameterized test. 227 + * @exit: A reference to the param_exit() function to run after a parameterized test. 228 + * 229 + * Provides the option to register param_init() and param_exit() functions. 230 + * param_init/exit will be passed the parameterized test context and run once 231 + * before and once after the parameterized test. The init function can be used 232 + * to add resources to share between parameter runs, pass parameter arrays, 233 + * and any other setup logic. The exit function can be used to clean up resources 234 + * that were not managed by the parameterized test, and any other teardown logic. 235 + * 236 + * Note: If you are registering a parameter array in param_init() with 237 + * kunit_register_param_array() then you need to pass kunit_array_gen_params() 238 + * to this as the generator function. 239 + */ 240 + #define KUNIT_CASE_PARAM_WITH_INIT(test_name, gen_params, init, exit) \ 241 + { .run_case = test_name, .name = #test_name, \ 242 + .generate_params = gen_params, \ 243 + .param_init = init, .param_exit = exit, \ 244 + .module_name = KBUILD_MODNAME} 245 + 246 + /** 227 247 * struct kunit_suite - describes a related collection of &struct kunit_case 228 248 * 229 249 * @name: the name of the test. Purely informational. ··· 293 263 struct kunit_suite * const *end; 294 264 }; 295 265 266 + /* Stores the pointer to the parameter array and its metadata. */ 267 + struct kunit_params { 268 + /* 269 + * Reference to the parameter array for a parameterized test. This 270 + * is NULL if a parameter array wasn't directly passed to the 271 + * parameterized test context struct kunit via kunit_register_params_array(). 272 + */ 273 + const void *params; 274 + /* Reference to a function that gets the description of a parameter. */ 275 + void (*get_description)(struct kunit *test, const void *param, char *desc); 276 + size_t num_params; 277 + size_t elem_size; 278 + }; 279 + 296 280 /** 297 281 * struct kunit - represents a running instance of a test. 298 282 * 299 283 * @priv: for user to store arbitrary data. Commonly used to pass data 300 284 * created in the init function (see &struct kunit_suite). 285 + * @parent: reference to the parent context of type struct kunit that can 286 + * be used for storing shared resources. 287 + * @params_array: for storing the parameter array. 301 288 * 302 289 * Used to store information about the current context under which the test 303 290 * is running. Most of this data is private and should only be accessed 304 - * indirectly via public functions; the one exception is @priv which can be 305 - * used by the test writer to store arbitrary data. 291 + * indirectly via public functions; the exceptions are @priv, @parent and 292 + * @params_array which can be used by the test writer to store arbitrary data, 293 + * access the parent context, and to store the parameter array, respectively. 306 294 */ 307 295 struct kunit { 308 296 void *priv; 297 + struct kunit *parent; 298 + struct kunit_params params_array; 309 299 310 300 /* private: internal use only. */ 311 301 const char *name; /* Read only after initialization! */ ··· 395 345 396 346 struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set, 397 347 struct kunit_suite_set suite_set); 348 + 349 + const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc); 398 350 399 351 #if IS_BUILTIN(CONFIG_KUNIT) 400 352 int kunit_run_all_tests(void); ··· 1726 1674 * Define function @name_gen_params which uses @array to generate parameters. 1727 1675 */ 1728 1676 #define KUNIT_ARRAY_PARAM(name, array, get_desc) \ 1729 - static const void *name##_gen_params(const void *prev, char *desc) \ 1677 + static const void *name##_gen_params(struct kunit *test, \ 1678 + const void *prev, char *desc) \ 1730 1679 { \ 1731 1680 typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \ 1681 + if (!prev) \ 1682 + kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \ 1732 1683 if (__next - (array) < ARRAY_SIZE((array))) { \ 1733 1684 void (*__get_desc)(typeof(__next), char *) = get_desc; \ 1734 1685 if (__get_desc) \ ··· 1750 1695 * Define function @name_gen_params which uses @array to generate parameters. 1751 1696 */ 1752 1697 #define KUNIT_ARRAY_PARAM_DESC(name, array, desc_member) \ 1753 - static const void *name##_gen_params(const void *prev, char *desc) \ 1698 + static const void *name##_gen_params(struct kunit *test, \ 1699 + const void *prev, char *desc) \ 1754 1700 { \ 1755 1701 typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \ 1702 + if (!prev) \ 1703 + kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \ 1756 1704 if (__next - (array) < ARRAY_SIZE((array))) { \ 1757 1705 strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \ 1758 1706 return __next; \ 1759 1707 } \ 1760 1708 return NULL; \ 1761 1709 } 1710 + 1711 + /** 1712 + * kunit_register_params_array() - Register parameter array for a KUnit test. 1713 + * @test: The KUnit test structure to which parameters will be added. 1714 + * @array: An array of test parameters. 1715 + * @param_count: Number of parameters. 1716 + * @get_desc: Function that generates a string description for a given parameter 1717 + * element. 1718 + * 1719 + * This macro initializes the @test's parameter array data, storing information 1720 + * including the parameter array, its count, the element size, and the parameter 1721 + * description function within `test->params_array`. 1722 + * 1723 + * Note: If using this macro in param_init(), kunit_array_gen_params() 1724 + * will then need to be manually provided as the parameter generator function to 1725 + * KUNIT_CASE_PARAM_WITH_INIT(). kunit_array_gen_params() is a KUnit 1726 + * function that uses the registered array to generate parameters 1727 + */ 1728 + #define kunit_register_params_array(test, array, param_count, get_desc) \ 1729 + do { \ 1730 + struct kunit *_test = (test); \ 1731 + const typeof((array)[0]) * _params_ptr = &(array)[0]; \ 1732 + _test->params_array.params = _params_ptr; \ 1733 + _test->params_array.num_params = (param_count); \ 1734 + _test->params_array.elem_size = sizeof(*_params_ptr); \ 1735 + _test->params_array.get_description = (get_desc); \ 1736 + } while (0) 1762 1737 1763 1738 // TODO(dlatypov@google.com): consider eventually migrating users to explicitly 1764 1739 // include resource.h themselves if they need it.
+1 -1
kernel/kcsan/kcsan_test.c
··· 1383 1383 * The thread counts are chosen to cover potentially interesting boundaries and 1384 1384 * corner cases (2 to 5), and then stress the system with larger counts. 1385 1385 */ 1386 - static const void *nthreads_gen_params(const void *prev, char *desc) 1386 + static const void *nthreads_gen_params(struct kunit *test, const void *prev, char *desc) 1387 1387 { 1388 1388 long nthreads = (long)prev; 1389 1389
-4
lib/Makefile
··· 109 109 CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU) 110 110 CFLAGS_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). 114 - ifdef CONFIG_KUNIT 115 112 obj-y += kunit/ 116 - endif 117 113 118 114 ifeq ($(CONFIG_DEBUG_KOBJECT),y) 119 115 CFLAGS_kobject.o += -DDEBUG
+11
lib/kunit/Kconfig
··· 106 106 If unsure, the default timeout of 300 seconds is suitable for most 107 107 cases. 108 108 109 + config 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 + 109 120 endif # KUNIT
+1 -1
lib/kunit/Makefile
··· 17 17 endif 18 18 19 19 # KUnit 'hooks' are built-in even when KUnit is built as a module. 20 - obj-y += hooks.o 20 + obj-$(if $(CONFIG_KUNIT),y) += hooks.o 21 21 22 22 obj-$(CONFIG_KUNIT_TEST) += kunit-test.o 23 23 obj-$(CONFIG_KUNIT_TEST) += platform-test.o
+217
lib/kunit/kunit-example-test.c
··· 278 278 } 279 279 280 280 /* 281 + * This custom function allocates memory and sets the information we want 282 + * stored in the kunit_resource->data field. 283 + */ 284 + static 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 + */ 298 + static 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 + */ 307 + static 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 + */ 318 + static 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 + */ 332 + static 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 + */ 364 + static 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 + */ 399 + static 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 + */ 427 + static 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 + */ 438 + static 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 + */ 471 + static 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 + */ 480 + static 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 + 492 + /* 281 493 * Here we make a list of all the test cases we want to add to the test suite 282 494 * below. 283 495 */ ··· 508 296 KUNIT_CASE(example_static_stub_using_fn_ptr_test), 509 297 KUNIT_CASE(example_priv_test), 510 298 KUNIT_CASE_PARAM(example_params_test, example_gen_params), 299 + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen_params, 300 + example_param_init, NULL), 301 + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr, 302 + kunit_array_gen_params, example_param_init_dynamic_arr, 303 + example_param_exit_dynamic_arr), 511 304 KUNIT_CASE_SLOW(example_slow_test), 512 305 {} 513 306 };
+79 -15
lib/kunit/test.c
··· 337 337 } 338 338 EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion); 339 339 340 + static 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 + 340 348 void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log) 341 349 { 342 350 spin_lock_init(&test->lock); ··· 355 347 string_stream_clear(log); 356 348 test->status = KUNIT_SUCCESS; 357 349 test->status_comment[0] = '\0'; 350 + kunit_init_params(test); 358 351 } 359 352 EXPORT_SYMBOL_GPL(kunit_init_test); 360 353 ··· 650 641 total->total += add.total; 651 642 } 652 643 644 + const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc) 645 + { 646 + struct kunit_params *params_arr = &test->params_array; 647 + const void *param; 648 + 649 + if (test->param_index < params_arr->num_params) { 650 + param = (char *)params_arr->params 651 + + test->param_index * params_arr->elem_size; 652 + 653 + if (params_arr->get_description) 654 + params_arr->get_description(test, param, desc); 655 + return param; 656 + } 657 + return NULL; 658 + } 659 + EXPORT_SYMBOL_GPL(kunit_array_gen_params); 660 + 661 + static void kunit_init_parent_param_test(struct kunit_case *test_case, struct kunit *test) 662 + { 663 + if (test_case->param_init) { 664 + int err = test_case->param_init(test); 665 + 666 + if (err) { 667 + kunit_err(test_case, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 668 + "# failed to initialize parent parameter test (%d)", err); 669 + test->status = KUNIT_FAILURE; 670 + test_case->status = KUNIT_FAILURE; 671 + } 672 + } 673 + } 674 + 653 675 int kunit_run_tests(struct kunit_suite *suite) 654 676 { 655 677 char param_desc[KUNIT_PARAM_DESC_SIZE]; 656 678 struct kunit_case *test_case; 657 679 struct kunit_result_stats suite_stats = { 0 }; 658 680 struct kunit_result_stats total_stats = { 0 }; 681 + const void *curr_param; 659 682 660 683 /* Taint the kernel so we know we've run tests. */ 661 684 add_taint(TAINT_TEST, LOCKDEP_STILL_OK); ··· 718 677 kunit_run_case_catch_errors(suite, test_case, &test); 719 678 kunit_update_stats(&param_stats, test.status); 720 679 } else { 680 + kunit_init_parent_param_test(test_case, &test); 681 + if (test_case->status == KUNIT_FAILURE) { 682 + kunit_update_stats(&param_stats, test.status); 683 + goto test_case_end; 684 + } 721 685 /* Get initial param. */ 722 686 param_desc[0] = '\0'; 723 - test.param_value = test_case->generate_params(NULL, param_desc); 687 + /* TODO: Make generate_params try-catch */ 688 + curr_param = test_case->generate_params(&test, NULL, param_desc); 724 689 test_case->status = KUNIT_SKIPPED; 725 690 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 726 691 "KTAP version 1\n"); 727 692 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 728 693 "# Subtest: %s", test_case->name); 694 + if (test.params_array.params && 695 + test_case->generate_params == kunit_array_gen_params) { 696 + kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT 697 + KUNIT_SUBTEST_INDENT "1..%zd\n", 698 + test.params_array.num_params); 699 + } 729 700 730 - while (test.param_value) { 731 - kunit_run_case_catch_errors(suite, test_case, &test); 701 + while (curr_param) { 702 + struct kunit param_test = { 703 + .param_value = curr_param, 704 + .param_index = ++test.param_index, 705 + .parent = &test, 706 + }; 707 + kunit_init_test(&param_test, test_case->name, test_case->log); 708 + kunit_run_case_catch_errors(suite, test_case, &param_test); 732 709 733 710 if (param_desc[0] == '\0') { 734 711 snprintf(param_desc, sizeof(param_desc), 735 - "param-%d", test.param_index); 712 + "param-%d", param_test.param_index); 736 713 } 737 714 738 - kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE_PARAM, 739 - test.status, 740 - test.param_index + 1, 715 + kunit_print_ok_not_ok(&param_test, KUNIT_LEVEL_CASE_PARAM, 716 + param_test.status, 717 + param_test.param_index, 741 718 param_desc, 742 - test.status_comment); 719 + param_test.status_comment); 743 720 744 - kunit_update_stats(&param_stats, test.status); 721 + kunit_update_stats(&param_stats, param_test.status); 745 722 746 723 /* Get next param. */ 747 724 param_desc[0] = '\0'; 748 - test.param_value = test_case->generate_params(test.param_value, param_desc); 749 - test.param_index++; 750 - test.status = KUNIT_SUCCESS; 751 - test.status_comment[0] = '\0'; 752 - test.priv = NULL; 725 + curr_param = test_case->generate_params(&test, curr_param, 726 + param_desc); 753 727 } 728 + /* 729 + * TODO: Put into a try catch. Since we don't need suite->exit 730 + * for it we can't reuse kunit_try_run_cleanup for this yet. 731 + */ 732 + if (test_case->param_exit) 733 + test_case->param_exit(&test); 734 + /* TODO: Put this kunit_cleanup into a try-catch. */ 735 + kunit_cleanup(&test); 754 736 } 755 - 737 + test_case_end: 756 738 kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE); 757 739 758 740 kunit_print_test_stats(&test, param_stats);
+11
rust/kernel/kunit.rs
··· 210 210 status: kernel::bindings::kunit_status_KUNIT_SUCCESS, 211 211 module_name: core::ptr::null_mut(), 212 212 log: core::ptr::null_mut(), 213 + param_init: None, 214 + param_exit: None, 213 215 } 214 216 } 215 217 ··· 231 229 status: kernel::bindings::kunit_status_KUNIT_SUCCESS, 232 230 module_name: core::ptr::null_mut(), 233 231 log: core::ptr::null_mut(), 232 + param_init: None, 233 + param_exit: None, 234 234 } 235 235 } 236 236 ··· 360 356 #[test] 361 357 fn rust_test_kunit_in_kunit_test() { 362 358 assert!(in_kunit_test()); 359 + } 360 + 361 + #[test] 362 + #[cfg(not(all()))] 363 + fn rust_test_kunit_always_disabled_test() { 364 + // This test should never run because of the `cfg`. 365 + assert!(false); 363 366 } 364 367 }
+36 -12
rust/macros/kunit.rs
··· 5 5 //! Copyright (c) 2023 José Expósito <jose.exposito89@gmail.com> 6 6 7 7 use proc_macro::{Delimiter, Group, TokenStream, TokenTree}; 8 + use std::collections::HashMap; 8 9 use std::fmt::Write; 9 10 10 11 pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream { ··· 42 41 // Get the functions set as tests. Search for `[test]` -> `fn`. 43 42 let mut body_it = body.stream().into_iter(); 44 43 let mut tests = Vec::new(); 44 + let mut attributes: HashMap<String, TokenStream> = HashMap::new(); 45 45 while let Some(token) = body_it.next() { 46 46 match token { 47 - TokenTree::Group(ident) if ident.to_string() == "[test]" => match body_it.next() { 48 - Some(TokenTree::Ident(ident)) if ident.to_string() == "fn" => { 49 - let test_name = match body_it.next() { 50 - Some(TokenTree::Ident(ident)) => ident.to_string(), 51 - _ => continue, 52 - }; 53 - tests.push(test_name); 47 + TokenTree::Punct(ref p) if p.as_char() == '#' => match body_it.next() { 48 + Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Bracket => { 49 + if let Some(TokenTree::Ident(name)) = g.stream().into_iter().next() { 50 + // Collect attributes because we need to find which are tests. We also 51 + // need to copy `cfg` attributes so tests can be conditionally enabled. 52 + attributes 53 + .entry(name.to_string()) 54 + .or_default() 55 + .extend([token, TokenTree::Group(g)]); 56 + } 57 + continue; 54 58 } 55 - _ => continue, 59 + _ => (), 56 60 }, 61 + TokenTree::Ident(i) if i.to_string() == "fn" && attributes.contains_key("test") => { 62 + if let Some(TokenTree::Ident(test_name)) = body_it.next() { 63 + tests.push((test_name, attributes.remove("cfg").unwrap_or_default())) 64 + } 65 + } 66 + 57 67 _ => (), 58 68 } 69 + attributes.clear(); 59 70 } 60 71 61 72 // Add `#[cfg(CONFIG_KUNIT="y")]` before the module declaration. ··· 113 100 let mut test_cases = "".to_owned(); 114 101 let mut assert_macros = "".to_owned(); 115 102 let path = crate::helpers::file(); 116 - for test in &tests { 103 + let num_tests = tests.len(); 104 + for (test, cfg_attr) in tests { 117 105 let kunit_wrapper_fn_name = format!("kunit_rust_wrapper_{test}"); 118 - // An extra `use` is used here to reduce the length of the message. 106 + // Append any `cfg` attributes the user might have written on their tests so we don't 107 + // attempt to call them when they are `cfg`'d out. An extra `use` is used here to reduce 108 + // the length of the assert message. 119 109 let kunit_wrapper = format!( 120 - "unsafe extern \"C\" fn {kunit_wrapper_fn_name}(_test: *mut ::kernel::bindings::kunit) {{ use ::kernel::kunit::is_test_result_ok; assert!(is_test_result_ok({test}())); }}", 110 + r#"unsafe extern "C" fn {kunit_wrapper_fn_name}(_test: *mut ::kernel::bindings::kunit) 111 + {{ 112 + (*_test).status = ::kernel::bindings::kunit_status_KUNIT_SKIPPED; 113 + {cfg_attr} {{ 114 + (*_test).status = ::kernel::bindings::kunit_status_KUNIT_SUCCESS; 115 + use ::kernel::kunit::is_test_result_ok; 116 + assert!(is_test_result_ok({test}())); 117 + }} 118 + }}"#, 121 119 ); 122 120 writeln!(kunit_macros, "{kunit_wrapper}").unwrap(); 123 121 writeln!( ··· 163 139 writeln!( 164 140 kunit_macros, 165 141 "static mut TEST_CASES: [::kernel::bindings::kunit_case; {}] = [\n{test_cases} ::kernel::kunit::kunit_case_null(),\n];", 166 - tests.len() + 1 142 + num_tests + 1 167 143 ) 168 144 .unwrap(); 169 145
+2 -3
tools/testing/kunit/configs/arch_uml.config
··· 1 1 # Config options which are added to UML builds by default 2 2 3 - # Enable virtio/pci, as a lot of tests require it. 4 - CONFIG_VIRTIO_UML=y 5 - CONFIG_UML_PCI_OVER_VIRTIO=y 3 + # Enable pci, as a lot of tests require it. 4 + CONFIG_KUNIT_UML_PCI=y 6 5 7 6 # Enable FORTIFY_SOURCE for wider checking. 8 7 CONFIG_FORTIFY_SOURCE=y
+2 -2
tools/testing/kunit/kunit.py
··· 228 228 fake_test.counts.passed = 1 229 229 230 230 output: Iterable[str] = input_data 231 - if request.raw_output == 'all': 231 + if request.raw_output == 'all' or request.raw_output == 'full': 232 232 pass 233 233 elif request.raw_output == 'kunit': 234 234 output = kunit_parser.extract_tap_lines(output) ··· 425 425 parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. ' 426 426 'By default, filters to just KUnit output. Use ' 427 427 '--raw_output=all to show everything', 428 - type=str, nargs='?', const='all', default=None, choices=['all', 'kunit']) 428 + type=str, nargs='?', const='all', default=None, choices=['all', 'full', 'kunit']) 429 429 parser.add_argument('--json', 430 430 nargs='?', 431 431 help='Prints parsed test results as JSON to stdout or a file if '
+5 -3
tools/testing/kunit/kunit_parser.py
··· 352 352 lines.pop() 353 353 return True 354 354 355 - TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$') 355 + TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?([^#]*)( # .*)?$') 356 356 357 - TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$') 357 + TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?(.*) # SKIP ?(.*)$') 358 358 359 359 def peek_test_name_match(lines: LineStream, test: Test) -> bool: 360 360 """ ··· 379 379 if not match: 380 380 return False 381 381 name = match.group(4) 382 + if not name: 383 + return False 382 384 return name == test.name 383 385 384 386 def parse_test_result(lines: LineStream, test: Test, ··· 418 416 419 417 # Set name of test object 420 418 if skip_match: 421 - test.name = skip_match.group(4) 419 + test.name = skip_match.group(4) or skip_match.group(5) 422 420 else: 423 421 test.name = match.group(4) 424 422
+18
tools/testing/kunit/qemu_configs/mips.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + from ..qemu_config import QemuArchParams 4 + 5 + QEMU_ARCH = QemuArchParams(linux_arch='mips', 6 + kconfig=''' 7 + CONFIG_32BIT=y 8 + CONFIG_CPU_BIG_ENDIAN=y 9 + CONFIG_MIPS_MALTA=y 10 + CONFIG_SERIAL_8250=y 11 + CONFIG_SERIAL_8250_CONSOLE=y 12 + CONFIG_POWER_RESET=y 13 + CONFIG_POWER_RESET_SYSCON=y 14 + ''', 15 + qemu_arch='mips', 16 + kernel_path='vmlinuz', 17 + kernel_command_line='console=ttyS0', 18 + extra_qemu_params=['-M', 'malta'])
+19
tools/testing/kunit/qemu_configs/mips64.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + from ..qemu_config import QemuArchParams 4 + 5 + QEMU_ARCH = QemuArchParams(linux_arch='mips', 6 + kconfig=''' 7 + CONFIG_CPU_MIPS64_R2=y 8 + CONFIG_64BIT=y 9 + CONFIG_CPU_BIG_ENDIAN=y 10 + CONFIG_MIPS_MALTA=y 11 + CONFIG_SERIAL_8250=y 12 + CONFIG_SERIAL_8250_CONSOLE=y 13 + CONFIG_POWER_RESET=y 14 + CONFIG_POWER_RESET_SYSCON=y 15 + ''', 16 + qemu_arch='mips64', 17 + kernel_path='vmlinuz', 18 + kernel_command_line='console=ttyS0', 19 + extra_qemu_params=['-M', 'malta', '-cpu', '5KEc'])
+19
tools/testing/kunit/qemu_configs/mips64el.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + from ..qemu_config import QemuArchParams 4 + 5 + QEMU_ARCH = QemuArchParams(linux_arch='mips', 6 + kconfig=''' 7 + CONFIG_CPU_MIPS64_R2=y 8 + CONFIG_64BIT=y 9 + CONFIG_CPU_LITTLE_ENDIAN=y 10 + CONFIG_MIPS_MALTA=y 11 + CONFIG_SERIAL_8250=y 12 + CONFIG_SERIAL_8250_CONSOLE=y 13 + CONFIG_POWER_RESET=y 14 + CONFIG_POWER_RESET_SYSCON=y 15 + ''', 16 + qemu_arch='mips64el', 17 + kernel_path='vmlinuz', 18 + kernel_command_line='console=ttyS0', 19 + extra_qemu_params=['-M', 'malta', '-cpu', '5KEc'])
+18
tools/testing/kunit/qemu_configs/mipsel.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + from ..qemu_config import QemuArchParams 4 + 5 + QEMU_ARCH = QemuArchParams(linux_arch='mips', 6 + kconfig=''' 7 + CONFIG_32BIT=y 8 + CONFIG_CPU_LITTLE_ENDIAN=y 9 + CONFIG_MIPS_MALTA=y 10 + CONFIG_SERIAL_8250=y 11 + CONFIG_SERIAL_8250_CONSOLE=y 12 + CONFIG_POWER_RESET=y 13 + CONFIG_POWER_RESET_SYSCON=y 14 + ''', 15 + qemu_arch='mipsel', 16 + kernel_path='vmlinuz', 17 + kernel_command_line='console=ttyS0', 18 + extra_qemu_params=['-M', 'malta'])
+2 -1
tools/testing/kunit/test_data/test_is_test_passed-kselftest.log
··· 1 1 TAP version 13 2 - 1..2 2 + 1..3 3 3 # selftests: membarrier: membarrier_test_single_thread 4 4 # TAP version 13 5 5 # 1..2 ··· 12 12 # ok 1 sys_membarrier available 13 13 # ok 2 sys membarrier invalid command test: command = -1, flags = 0, errno = 22. Failed as expected 14 14 ok 2 selftests: membarrier: membarrier_test_multi_thread 15 + ok 3 # SKIP selftests: membarrier: membarrier_test_multi_thread