18c2ecf20Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci=========== 48c2ecf20Sopenharmony_ciUsing KUnit 58c2ecf20Sopenharmony_ci=========== 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ciThe purpose of this document is to describe what KUnit is, how it works, how it 88c2ecf20Sopenharmony_ciis intended to be used, and all the concepts and terminology that are needed to 98c2ecf20Sopenharmony_ciunderstand it. This guide assumes a working knowledge of the Linux kernel and 108c2ecf20Sopenharmony_cisome basic knowledge of testing. 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ciFor a high level introduction to KUnit, including setting up KUnit for your 138c2ecf20Sopenharmony_ciproject, see :doc:`start`. 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciOrganization of this document 168c2ecf20Sopenharmony_ci============================= 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciThis document is organized into two main sections: Testing and Isolating 198c2ecf20Sopenharmony_ciBehavior. The first covers what unit tests are and how to use KUnit to write 208c2ecf20Sopenharmony_cithem. The second covers how to use KUnit to isolate code and make it possible 218c2ecf20Sopenharmony_cito unit test code that was otherwise un-unit-testable. 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciTesting 248c2ecf20Sopenharmony_ci======= 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciWhat is KUnit? 278c2ecf20Sopenharmony_ci-------------- 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci"K" is short for "kernel" so "KUnit" is the "(Linux) Kernel Unit Testing 308c2ecf20Sopenharmony_ciFramework." KUnit is intended first and foremost for writing unit tests; it is 318c2ecf20Sopenharmony_cigeneral enough that it can be used to write integration tests; however, this is 328c2ecf20Sopenharmony_cia secondary goal. KUnit has no ambition of being the only testing framework for 338c2ecf20Sopenharmony_cithe kernel; for example, it does not intend to be an end-to-end testing 348c2ecf20Sopenharmony_ciframework. 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciWhat is Unit Testing? 378c2ecf20Sopenharmony_ci--------------------- 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ciA `unit test <https://martinfowler.com/bliki/UnitTest.html>`_ is a test that 408c2ecf20Sopenharmony_citests code at the smallest possible scope, a *unit* of code. In the C 418c2ecf20Sopenharmony_ciprogramming language that's a function. 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciUnit tests should be written for all the publicly exposed functions in a 448c2ecf20Sopenharmony_cicompilation unit; so that is all the functions that are exported in either a 458c2ecf20Sopenharmony_ci*class* (defined below) or all functions which are **not** static. 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ciWriting Tests 488c2ecf20Sopenharmony_ci------------- 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciTest Cases 518c2ecf20Sopenharmony_ci~~~~~~~~~~ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciThe fundamental unit in KUnit is the test case. A test case is a function with 548c2ecf20Sopenharmony_cithe signature ``void (*)(struct kunit *test)``. It calls a function to be tested 558c2ecf20Sopenharmony_ciand then sets *expectations* for what should happen. For example: 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci.. code-block:: c 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci void example_test_success(struct kunit *test) 608c2ecf20Sopenharmony_ci { 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci void example_test_failure(struct kunit *test) 648c2ecf20Sopenharmony_ci { 658c2ecf20Sopenharmony_ci KUNIT_FAIL(test, "This test never passes."); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciIn the above example ``example_test_success`` always passes because it does 698c2ecf20Sopenharmony_cinothing; no expectations are set, so all expectations pass. On the other hand 708c2ecf20Sopenharmony_ci``example_test_failure`` always fails because it calls ``KUNIT_FAIL``, which is 718c2ecf20Sopenharmony_cia special expectation that logs a message and causes the test case to fail. 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciExpectations 748c2ecf20Sopenharmony_ci~~~~~~~~~~~~ 758c2ecf20Sopenharmony_ciAn *expectation* is a way to specify that you expect a piece of code to do 768c2ecf20Sopenharmony_cisomething in a test. An expectation is called like a function. A test is made 778c2ecf20Sopenharmony_ciby setting expectations about the behavior of a piece of code under test; when 788c2ecf20Sopenharmony_cione or more of the expectations fail, the test case fails and information about 798c2ecf20Sopenharmony_cithe failure is logged. For example: 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci.. code-block:: c 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci void add_test_basic(struct kunit *test) 848c2ecf20Sopenharmony_ci { 858c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, 1, add(1, 0)); 868c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, 2, add(1, 1)); 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciIn the above example ``add_test_basic`` makes a number of assertions about the 908c2ecf20Sopenharmony_cibehavior of a function called ``add``; the first parameter is always of type 918c2ecf20Sopenharmony_ci``struct kunit *``, which contains information about the current test context; 928c2ecf20Sopenharmony_cithe second parameter, in this case, is what the value is expected to be; the 938c2ecf20Sopenharmony_cilast value is what the value actually is. If ``add`` passes all of these 948c2ecf20Sopenharmony_ciexpectations, the test case, ``add_test_basic`` will pass; if any one of these 958c2ecf20Sopenharmony_ciexpectations fails, the test case will fail. 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciIt is important to understand that a test case *fails* when any expectation is 988c2ecf20Sopenharmony_civiolated; however, the test will continue running, potentially trying other 998c2ecf20Sopenharmony_ciexpectations until the test case ends or is otherwise terminated. This is as 1008c2ecf20Sopenharmony_ciopposed to *assertions* which are discussed later. 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ciTo learn about more expectations supported by KUnit, see :doc:`api/test`. 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci.. note:: 1058c2ecf20Sopenharmony_ci A single test case should be pretty short, pretty easy to understand, 1068c2ecf20Sopenharmony_ci focused on a single behavior. 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciFor example, if we wanted to properly test the add function above, we would 1098c2ecf20Sopenharmony_cicreate additional tests cases which would each test a different property that an 1108c2ecf20Sopenharmony_ciadd function should have like this: 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci.. code-block:: c 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci void add_test_basic(struct kunit *test) 1158c2ecf20Sopenharmony_ci { 1168c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, 1, add(1, 0)); 1178c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, 2, add(1, 1)); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci void add_test_negative(struct kunit *test) 1218c2ecf20Sopenharmony_ci { 1228c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, 0, add(-1, 1)); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci void add_test_max(struct kunit *test) 1268c2ecf20Sopenharmony_ci { 1278c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, INT_MAX, add(0, INT_MAX)); 1288c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, -1, add(INT_MAX, INT_MIN)); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci void add_test_overflow(struct kunit *test) 1328c2ecf20Sopenharmony_ci { 1338c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, INT_MIN, add(INT_MAX, 1)); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciNotice how it is immediately obvious what all the properties that we are testing 1378c2ecf20Sopenharmony_cifor are. 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciAssertions 1408c2ecf20Sopenharmony_ci~~~~~~~~~~ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ciKUnit also has the concept of an *assertion*. An assertion is just like an 1438c2ecf20Sopenharmony_ciexpectation except the assertion immediately terminates the test case if it is 1448c2ecf20Sopenharmony_cinot satisfied. 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciFor example: 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci.. code-block:: c 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci static void mock_test_do_expect_default_return(struct kunit *test) 1518c2ecf20Sopenharmony_ci { 1528c2ecf20Sopenharmony_ci struct mock_test_context *ctx = test->priv; 1538c2ecf20Sopenharmony_ci struct mock *mock = ctx->mock; 1548c2ecf20Sopenharmony_ci int param0 = 5, param1 = -5; 1558c2ecf20Sopenharmony_ci const char *two_param_types[] = {"int", "int"}; 1568c2ecf20Sopenharmony_ci const void *two_params[] = {¶m0, ¶m1}; 1578c2ecf20Sopenharmony_ci const void *ret; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ret = mock->do_expect(mock, 1608c2ecf20Sopenharmony_ci "test_printk", test_printk, 1618c2ecf20Sopenharmony_ci two_param_types, two_params, 1628c2ecf20Sopenharmony_ci ARRAY_SIZE(two_params)); 1638c2ecf20Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); 1648c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, -4, *((int *) ret)); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciIn this example, the method under test should return a pointer to a value, so 1688c2ecf20Sopenharmony_ciif the pointer returned by the method is null or an errno, we don't want to 1698c2ecf20Sopenharmony_cibother continuing the test since the following expectation could crash the test 1708c2ecf20Sopenharmony_cicase. `ASSERT_NOT_ERR_OR_NULL(...)` allows us to bail out of the test case if 1718c2ecf20Sopenharmony_cithe appropriate conditions have not been satisfied to complete the test. 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciTest Suites 1748c2ecf20Sopenharmony_ci~~~~~~~~~~~ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ciNow obviously one unit test isn't very helpful; the power comes from having 1778c2ecf20Sopenharmony_cimany test cases covering all of a unit's behaviors. Consequently it is common 1788c2ecf20Sopenharmony_cito have many *similar* tests; in order to reduce duplication in these closely 1798c2ecf20Sopenharmony_cirelated tests most unit testing frameworks - including KUnit - provide the 1808c2ecf20Sopenharmony_ciconcept of a *test suite*. A *test suite* is just a collection of test cases 1818c2ecf20Sopenharmony_cifor a unit of code with a set up function that gets invoked before every test 1828c2ecf20Sopenharmony_cicase and then a tear down function that gets invoked after every test case 1838c2ecf20Sopenharmony_cicompletes. 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciExample: 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci.. code-block:: c 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci static struct kunit_case example_test_cases[] = { 1908c2ecf20Sopenharmony_ci KUNIT_CASE(example_test_foo), 1918c2ecf20Sopenharmony_ci KUNIT_CASE(example_test_bar), 1928c2ecf20Sopenharmony_ci KUNIT_CASE(example_test_baz), 1938c2ecf20Sopenharmony_ci {} 1948c2ecf20Sopenharmony_ci }; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci static struct kunit_suite example_test_suite = { 1978c2ecf20Sopenharmony_ci .name = "example", 1988c2ecf20Sopenharmony_ci .init = example_test_init, 1998c2ecf20Sopenharmony_ci .exit = example_test_exit, 2008c2ecf20Sopenharmony_ci .test_cases = example_test_cases, 2018c2ecf20Sopenharmony_ci }; 2028c2ecf20Sopenharmony_ci kunit_test_suite(example_test_suite); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ciIn the above example the test suite, ``example_test_suite``, would run the test 2058c2ecf20Sopenharmony_cicases ``example_test_foo``, ``example_test_bar``, and ``example_test_baz``; 2068c2ecf20Sopenharmony_cieach would have ``example_test_init`` called immediately before it and would 2078c2ecf20Sopenharmony_cihave ``example_test_exit`` called immediately after it. 2088c2ecf20Sopenharmony_ci``kunit_test_suite(example_test_suite)`` registers the test suite with the 2098c2ecf20Sopenharmony_ciKUnit test framework. 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci.. note:: 2128c2ecf20Sopenharmony_ci A test case will only be run if it is associated with a test suite. 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci``kunit_test_suite(...)`` is a macro which tells the linker to put the specified 2158c2ecf20Sopenharmony_citest suite in a special linker section so that it can be run by KUnit either 2168c2ecf20Sopenharmony_ciafter late_init, or when the test module is loaded (depending on whether the 2178c2ecf20Sopenharmony_citest was built in or not). 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciFor more information on these types of things see the :doc:`api/test`. 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ciIsolating Behavior 2228c2ecf20Sopenharmony_ci================== 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciThe most important aspect of unit testing that other forms of testing do not 2258c2ecf20Sopenharmony_ciprovide is the ability to limit the amount of code under test to a single unit. 2268c2ecf20Sopenharmony_ciIn practice, this is only possible by being able to control what code gets run 2278c2ecf20Sopenharmony_ciwhen the unit under test calls a function and this is usually accomplished 2288c2ecf20Sopenharmony_cithrough some sort of indirection where a function is exposed as part of an API 2298c2ecf20Sopenharmony_cisuch that the definition of that function can be changed without affecting the 2308c2ecf20Sopenharmony_cirest of the code base. In the kernel this primarily comes from two constructs, 2318c2ecf20Sopenharmony_ciclasses, structs that contain function pointers that are provided by the 2328c2ecf20Sopenharmony_ciimplementer, and architecture-specific functions which have definitions selected 2338c2ecf20Sopenharmony_ciat compile time. 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ciClasses 2368c2ecf20Sopenharmony_ci------- 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciClasses are not a construct that is built into the C programming language; 2398c2ecf20Sopenharmony_cihowever, it is an easily derived concept. Accordingly, pretty much every project 2408c2ecf20Sopenharmony_cithat does not use a standardized object oriented library (like GNOME's GObject) 2418c2ecf20Sopenharmony_cihas their own slightly different way of doing object oriented programming; the 2428c2ecf20Sopenharmony_ciLinux kernel is no exception. 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ciThe central concept in kernel object oriented programming is the class. In the 2458c2ecf20Sopenharmony_cikernel, a *class* is a struct that contains function pointers. This creates a 2468c2ecf20Sopenharmony_cicontract between *implementers* and *users* since it forces them to use the 2478c2ecf20Sopenharmony_cisame function signature without having to call the function directly. In order 2488c2ecf20Sopenharmony_cifor it to truly be a class, the function pointers must specify that a pointer 2498c2ecf20Sopenharmony_cito the class, known as a *class handle*, be one of the parameters; this makes 2508c2ecf20Sopenharmony_ciit possible for the member functions (also known as *methods*) to have access 2518c2ecf20Sopenharmony_cito member variables (more commonly known as *fields*) allowing the same 2528c2ecf20Sopenharmony_ciimplementation to have multiple *instances*. 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciTypically a class can be *overridden* by *child classes* by embedding the 2558c2ecf20Sopenharmony_ci*parent class* in the child class. Then when a method provided by the child 2568c2ecf20Sopenharmony_ciclass is called, the child implementation knows that the pointer passed to it is 2578c2ecf20Sopenharmony_ciof a parent contained within the child; because of this, the child can compute 2588c2ecf20Sopenharmony_cithe pointer to itself because the pointer to the parent is always a fixed offset 2598c2ecf20Sopenharmony_cifrom the pointer to the child; this offset is the offset of the parent contained 2608c2ecf20Sopenharmony_ciin the child struct. For example: 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci.. code-block:: c 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci struct shape { 2658c2ecf20Sopenharmony_ci int (*area)(struct shape *this); 2668c2ecf20Sopenharmony_ci }; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci struct rectangle { 2698c2ecf20Sopenharmony_ci struct shape parent; 2708c2ecf20Sopenharmony_ci int length; 2718c2ecf20Sopenharmony_ci int width; 2728c2ecf20Sopenharmony_ci }; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci int rectangle_area(struct shape *this) 2758c2ecf20Sopenharmony_ci { 2768c2ecf20Sopenharmony_ci struct rectangle *self = container_of(this, struct shape, parent); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return self->length * self->width; 2798c2ecf20Sopenharmony_ci }; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci void rectangle_new(struct rectangle *self, int length, int width) 2828c2ecf20Sopenharmony_ci { 2838c2ecf20Sopenharmony_ci self->parent.area = rectangle_area; 2848c2ecf20Sopenharmony_ci self->length = length; 2858c2ecf20Sopenharmony_ci self->width = width; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ciIn this example (as in most kernel code) the operation of computing the pointer 2898c2ecf20Sopenharmony_cito the child from the pointer to the parent is done by ``container_of``. 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciFaking Classes 2928c2ecf20Sopenharmony_ci~~~~~~~~~~~~~~ 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciIn order to unit test a piece of code that calls a method in a class, the 2958c2ecf20Sopenharmony_cibehavior of the method must be controllable, otherwise the test ceases to be a 2968c2ecf20Sopenharmony_ciunit test and becomes an integration test. 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciA fake just provides an implementation of a piece of code that is different than 2998c2ecf20Sopenharmony_ciwhat runs in a production instance, but behaves identically from the standpoint 3008c2ecf20Sopenharmony_ciof the callers; this is usually done to replace a dependency that is hard to 3018c2ecf20Sopenharmony_cideal with, or is slow. 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciA good example for this might be implementing a fake EEPROM that just stores the 3048c2ecf20Sopenharmony_ci"contents" in an internal buffer. For example, let's assume we have a class that 3058c2ecf20Sopenharmony_cirepresents an EEPROM: 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci.. code-block:: c 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci struct eeprom { 3108c2ecf20Sopenharmony_ci ssize_t (*read)(struct eeprom *this, size_t offset, char *buffer, size_t count); 3118c2ecf20Sopenharmony_ci ssize_t (*write)(struct eeprom *this, size_t offset, const char *buffer, size_t count); 3128c2ecf20Sopenharmony_ci }; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ciAnd we want to test some code that buffers writes to the EEPROM: 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci.. code-block:: c 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci struct eeprom_buffer { 3198c2ecf20Sopenharmony_ci ssize_t (*write)(struct eeprom_buffer *this, const char *buffer, size_t count); 3208c2ecf20Sopenharmony_ci int flush(struct eeprom_buffer *this); 3218c2ecf20Sopenharmony_ci size_t flush_count; /* Flushes when buffer exceeds flush_count. */ 3228c2ecf20Sopenharmony_ci }; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci struct eeprom_buffer *new_eeprom_buffer(struct eeprom *eeprom); 3258c2ecf20Sopenharmony_ci void destroy_eeprom_buffer(struct eeprom *eeprom); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ciWe can easily test this code by *faking out* the underlying EEPROM: 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci.. code-block:: c 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci struct fake_eeprom { 3328c2ecf20Sopenharmony_ci struct eeprom parent; 3338c2ecf20Sopenharmony_ci char contents[FAKE_EEPROM_CONTENTS_SIZE]; 3348c2ecf20Sopenharmony_ci }; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ssize_t fake_eeprom_read(struct eeprom *parent, size_t offset, char *buffer, size_t count) 3378c2ecf20Sopenharmony_ci { 3388c2ecf20Sopenharmony_ci struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci count = min(count, FAKE_EEPROM_CONTENTS_SIZE - offset); 3418c2ecf20Sopenharmony_ci memcpy(buffer, this->contents + offset, count); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return count; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ssize_t fake_eeprom_write(struct eeprom *parent, size_t offset, const char *buffer, size_t count) 3478c2ecf20Sopenharmony_ci { 3488c2ecf20Sopenharmony_ci struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci count = min(count, FAKE_EEPROM_CONTENTS_SIZE - offset); 3518c2ecf20Sopenharmony_ci memcpy(this->contents + offset, buffer, count); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return count; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci void fake_eeprom_init(struct fake_eeprom *this) 3578c2ecf20Sopenharmony_ci { 3588c2ecf20Sopenharmony_ci this->parent.read = fake_eeprom_read; 3598c2ecf20Sopenharmony_ci this->parent.write = fake_eeprom_write; 3608c2ecf20Sopenharmony_ci memset(this->contents, 0, FAKE_EEPROM_CONTENTS_SIZE); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciWe can now use it to test ``struct eeprom_buffer``: 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci.. code-block:: c 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci struct eeprom_buffer_test { 3688c2ecf20Sopenharmony_ci struct fake_eeprom *fake_eeprom; 3698c2ecf20Sopenharmony_ci struct eeprom_buffer *eeprom_buffer; 3708c2ecf20Sopenharmony_ci }; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci static void eeprom_buffer_test_does_not_write_until_flush(struct kunit *test) 3738c2ecf20Sopenharmony_ci { 3748c2ecf20Sopenharmony_ci struct eeprom_buffer_test *ctx = test->priv; 3758c2ecf20Sopenharmony_ci struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer; 3768c2ecf20Sopenharmony_ci struct fake_eeprom *fake_eeprom = ctx->fake_eeprom; 3778c2ecf20Sopenharmony_ci char buffer[] = {0xff}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci eeprom_buffer->flush_count = SIZE_MAX; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci eeprom_buffer->write(eeprom_buffer, buffer, 1); 3828c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci eeprom_buffer->write(eeprom_buffer, buffer, 1); 3858c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci eeprom_buffer->flush(eeprom_buffer); 3888c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff); 3898c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci static void eeprom_buffer_test_flushes_after_flush_count_met(struct kunit *test) 3938c2ecf20Sopenharmony_ci { 3948c2ecf20Sopenharmony_ci struct eeprom_buffer_test *ctx = test->priv; 3958c2ecf20Sopenharmony_ci struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer; 3968c2ecf20Sopenharmony_ci struct fake_eeprom *fake_eeprom = ctx->fake_eeprom; 3978c2ecf20Sopenharmony_ci char buffer[] = {0xff}; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci eeprom_buffer->flush_count = 2; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci eeprom_buffer->write(eeprom_buffer, buffer, 1); 4028c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci eeprom_buffer->write(eeprom_buffer, buffer, 1); 4058c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff); 4068c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci static void eeprom_buffer_test_flushes_increments_of_flush_count(struct kunit *test) 4108c2ecf20Sopenharmony_ci { 4118c2ecf20Sopenharmony_ci struct eeprom_buffer_test *ctx = test->priv; 4128c2ecf20Sopenharmony_ci struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer; 4138c2ecf20Sopenharmony_ci struct fake_eeprom *fake_eeprom = ctx->fake_eeprom; 4148c2ecf20Sopenharmony_ci char buffer[] = {0xff, 0xff}; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci eeprom_buffer->flush_count = 2; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci eeprom_buffer->write(eeprom_buffer, buffer, 1); 4198c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci eeprom_buffer->write(eeprom_buffer, buffer, 2); 4228c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff); 4238c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff); 4248c2ecf20Sopenharmony_ci /* Should have only flushed the first two bytes. */ 4258c2ecf20Sopenharmony_ci KUNIT_EXPECT_EQ(test, fake_eeprom->contents[2], 0); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci static int eeprom_buffer_test_init(struct kunit *test) 4298c2ecf20Sopenharmony_ci { 4308c2ecf20Sopenharmony_ci struct eeprom_buffer_test *ctx; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); 4338c2ecf20Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ctx->fake_eeprom = kunit_kzalloc(test, sizeof(*ctx->fake_eeprom), GFP_KERNEL); 4368c2ecf20Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->fake_eeprom); 4378c2ecf20Sopenharmony_ci fake_eeprom_init(ctx->fake_eeprom); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci ctx->eeprom_buffer = new_eeprom_buffer(&ctx->fake_eeprom->parent); 4408c2ecf20Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->eeprom_buffer); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci test->priv = ctx; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return 0; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci static void eeprom_buffer_test_exit(struct kunit *test) 4488c2ecf20Sopenharmony_ci { 4498c2ecf20Sopenharmony_ci struct eeprom_buffer_test *ctx = test->priv; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci destroy_eeprom_buffer(ctx->eeprom_buffer); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci.. _kunit-on-non-uml: 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciKUnit on non-UML architectures 4578c2ecf20Sopenharmony_ci============================== 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ciBy default KUnit uses UML as a way to provide dependencies for code under test. 4608c2ecf20Sopenharmony_ciUnder most circumstances KUnit's usage of UML should be treated as an 4618c2ecf20Sopenharmony_ciimplementation detail of how KUnit works under the hood. Nevertheless, there 4628c2ecf20Sopenharmony_ciare instances where being able to run architecture-specific code or test 4638c2ecf20Sopenharmony_ciagainst real hardware is desirable. For these reasons KUnit supports running on 4648c2ecf20Sopenharmony_ciother architectures. 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ciRunning existing KUnit tests on non-UML architectures 4678c2ecf20Sopenharmony_ci----------------------------------------------------- 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ciThere are some special considerations when running existing KUnit tests on 4708c2ecf20Sopenharmony_cinon-UML architectures: 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci* Hardware may not be deterministic, so a test that always passes or fails 4738c2ecf20Sopenharmony_ci when run under UML may not always do so on real hardware. 4748c2ecf20Sopenharmony_ci* Hardware and VM environments may not be hermetic. KUnit tries its best to 4758c2ecf20Sopenharmony_ci provide a hermetic environment to run tests; however, it cannot manage state 4768c2ecf20Sopenharmony_ci that it doesn't know about outside of the kernel. Consequently, tests that 4778c2ecf20Sopenharmony_ci may be hermetic on UML may not be hermetic on other architectures. 4788c2ecf20Sopenharmony_ci* Some features and tooling may not be supported outside of UML. 4798c2ecf20Sopenharmony_ci* Hardware and VMs are slower than UML. 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ciNone of these are reasons not to run your KUnit tests on real hardware; they are 4828c2ecf20Sopenharmony_cionly things to be aware of when doing so. 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ciThe biggest impediment will likely be that certain KUnit features and 4858c2ecf20Sopenharmony_ciinfrastructure may not support your target environment. For example, at this 4868c2ecf20Sopenharmony_citime the KUnit Wrapper (``tools/testing/kunit/kunit.py``) does not work outside 4878c2ecf20Sopenharmony_ciof UML. Unfortunately, there is no way around this. Using UML (or even just a 4888c2ecf20Sopenharmony_ciparticular architecture) allows us to make a lot of assumptions that make it 4898c2ecf20Sopenharmony_cipossible to do things which might otherwise be impossible. 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ciNevertheless, all core KUnit framework features are fully supported on all 4928c2ecf20Sopenharmony_ciarchitectures, and using them is straightforward: all you need to do is to take 4938c2ecf20Sopenharmony_ciyour kunitconfig, your Kconfig options for the tests you would like to run, and 4948c2ecf20Sopenharmony_cimerge them into whatever config your are using for your platform. That's it! 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ciFor example, let's say you have the following kunitconfig: 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci.. code-block:: none 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci CONFIG_KUNIT=y 5018c2ecf20Sopenharmony_ci CONFIG_KUNIT_EXAMPLE_TEST=y 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ciIf you wanted to run this test on an x86 VM, you might add the following config 5048c2ecf20Sopenharmony_cioptions to your ``.config``: 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci.. code-block:: none 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci CONFIG_KUNIT=y 5098c2ecf20Sopenharmony_ci CONFIG_KUNIT_EXAMPLE_TEST=y 5108c2ecf20Sopenharmony_ci CONFIG_SERIAL_8250=y 5118c2ecf20Sopenharmony_ci CONFIG_SERIAL_8250_CONSOLE=y 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ciAll these new options do is enable support for a common serial console needed 5148c2ecf20Sopenharmony_cifor logging. 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ciNext, you could build a kernel with these tests as follows: 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci.. code-block:: bash 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci make ARCH=x86 olddefconfig 5228c2ecf20Sopenharmony_ci make ARCH=x86 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciOnce you have built a kernel, you could run it on QEMU as follows: 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci.. code-block:: bash 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci qemu-system-x86_64 -enable-kvm \ 5298c2ecf20Sopenharmony_ci -m 1024 \ 5308c2ecf20Sopenharmony_ci -kernel arch/x86_64/boot/bzImage \ 5318c2ecf20Sopenharmony_ci -append 'console=ttyS0' \ 5328c2ecf20Sopenharmony_ci --nographic 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ciInterspersed in the kernel logs you might see the following: 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci.. code-block:: none 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci TAP version 14 5398c2ecf20Sopenharmony_ci # Subtest: example 5408c2ecf20Sopenharmony_ci 1..1 5418c2ecf20Sopenharmony_ci # example_simple_test: initializing 5428c2ecf20Sopenharmony_ci ok 1 - example_simple_test 5438c2ecf20Sopenharmony_ci ok 1 - example 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ciCongratulations, you just ran a KUnit test on the x86 architecture! 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ciIn a similar manner, kunit and kunit tests can also be built as modules, 5488c2ecf20Sopenharmony_ciso if you wanted to run tests in this way you might add the following config 5498c2ecf20Sopenharmony_cioptions to your ``.config``: 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci.. code-block:: none 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci CONFIG_KUNIT=m 5548c2ecf20Sopenharmony_ci CONFIG_KUNIT_EXAMPLE_TEST=m 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ciOnce the kernel is built and installed, a simple 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci.. code-block:: bash 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci modprobe example-test 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci...will run the tests. 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci.. note:: 5658c2ecf20Sopenharmony_ci Note that you should make sure your test depends on ``KUNIT=y`` in Kconfig 5668c2ecf20Sopenharmony_ci if the test does not support module build. Otherwise, it will trigger 5678c2ecf20Sopenharmony_ci compile errors if ``CONFIG_KUNIT`` is ``m``. 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ciWriting new tests for other architectures 5708c2ecf20Sopenharmony_ci----------------------------------------- 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ciThe first thing you must do is ask yourself whether it is necessary to write a 5738c2ecf20Sopenharmony_ciKUnit test for a specific architecture, and then whether it is necessary to 5748c2ecf20Sopenharmony_ciwrite that test for a particular piece of hardware. In general, writing a test 5758c2ecf20Sopenharmony_cithat depends on having access to a particular piece of hardware or software (not 5768c2ecf20Sopenharmony_ciincluded in the Linux source repo) should be avoided at all costs. 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ciEven if you only ever plan on running your KUnit test on your hardware 5798c2ecf20Sopenharmony_ciconfiguration, other people may want to run your tests and may not have access 5808c2ecf20Sopenharmony_cito your hardware. If you write your test to run on UML, then anyone can run your 5818c2ecf20Sopenharmony_citests without knowing anything about your particular setup, and you can still 5828c2ecf20Sopenharmony_cirun your tests on your hardware setup just by compiling for your architecture. 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci.. important:: 5858c2ecf20Sopenharmony_ci Always prefer tests that run on UML to tests that only run under a particular 5868c2ecf20Sopenharmony_ci architecture, and always prefer tests that run under QEMU or another easy 5878c2ecf20Sopenharmony_ci (and monetarily free) to obtain software environment to a specific piece of 5888c2ecf20Sopenharmony_ci hardware. 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ciNevertheless, there are still valid reasons to write an architecture or hardware 5918c2ecf20Sopenharmony_cispecific test: for example, you might want to test some code that really belongs 5928c2ecf20Sopenharmony_ciin ``arch/some-arch/*``. Even so, try your best to write the test so that it 5938c2ecf20Sopenharmony_cidoes not depend on physical hardware: if some of your test cases don't need the 5948c2ecf20Sopenharmony_cihardware, only require the hardware for tests that actually need it. 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ciNow that you have narrowed down exactly what bits are hardware specific, the 5978c2ecf20Sopenharmony_ciactual procedure for writing and running the tests is pretty much the same as 5988c2ecf20Sopenharmony_ciwriting normal KUnit tests. One special caveat is that you have to reset 5998c2ecf20Sopenharmony_cihardware state in between test cases; if this is not possible, you may only be 6008c2ecf20Sopenharmony_ciable to run one test case per invocation. 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci.. TODO(brendanhiggins@google.com): Add an actual example of an architecture- 6038c2ecf20Sopenharmony_ci dependent KUnit test. 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ciKUnit debugfs representation 6068c2ecf20Sopenharmony_ci============================ 6078c2ecf20Sopenharmony_ciWhen kunit test suites are initialized, they create an associated directory 6088c2ecf20Sopenharmony_ciin ``/sys/kernel/debug/kunit/<test-suite>``. The directory contains one file 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci- results: "cat results" displays results of each test case and the results 6118c2ecf20Sopenharmony_ci of the entire suite for the last test run. 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ciThe debugfs representation is primarily of use when kunit test suites are 6148c2ecf20Sopenharmony_cirun in a native environment, either as modules or builtin. Having a way 6158c2ecf20Sopenharmony_cito display results like this is valuable as otherwise results can be 6168c2ecf20Sopenharmony_ciintermixed with other events in dmesg output. The maximum size of each 6178c2ecf20Sopenharmony_ciresults file is KUNIT_LOG_SIZE bytes (defined in ``include/kunit/test.h``). 618