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

Documentation: Add Function Redirection API docs

Added a new page (functionredirection.rst) that describes the Function
Redirection (static stubbing) API. This page will be expanded if we add,
for example, ftrace-based stubbing.

In addition,
1. Updated the api/index.rst page to create an entry for function
redirection api
2. Updated the toctree to be hidden, reducing redundancy on the
generated page.

Signed-off-by: Sadiya Kazi <sadiyakazi@google.com>
Co-developed-by: Daniel Latypov <dlatypov@google.com>
Signed-off-by: Daniel Latypov <dlatypov@google.com>
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Reviewed-by: Brendan Higgins <brendanhiggins@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Sadiya Kazi and committed by
Shuah Khan
9ecc9cdd e047c5ea

+172 -3
+162
Documentation/dev-tools/kunit/api/functionredirection.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ======================== 4 + Function Redirection API 5 + ======================== 6 + 7 + Overview 8 + ======== 9 + 10 + When writing unit tests, it's important to be able to isolate the code being 11 + tested from other parts of the kernel. This ensures the reliability of the test 12 + (it won't be affected by external factors), reduces dependencies on specific 13 + hardware or config options (making the test easier to run), and protects the 14 + stability of the rest of the system (making it less likely for test-specific 15 + state to interfere with the rest of the system). 16 + 17 + While for some code (typically generic data structures, helpers, and other 18 + "pure functions") this is trivial, for others (like device drivers, 19 + filesystems, core subsystems) the code is heavily coupled with other parts of 20 + the kernel. 21 + 22 + This coupling is often due to global state in some way: be it a global list of 23 + devices, the filesystem, or some hardware state. Tests need to either carefully 24 + manage, isolate, and restore state, or they can avoid it altogether by 25 + replacing access to and mutation of this state with a "fake" or "mock" variant. 26 + 27 + By refactoring access to such state, such as by introducing a layer of 28 + indirection which can use or emulate a separate set of test state. However, 29 + such refactoring comes with its own costs (and undertaking significant 30 + refactoring before being able to write tests is suboptimal). 31 + 32 + A simpler way to intercept and replace some of the function calls is to use 33 + function redirection via static stubs. 34 + 35 + 36 + Static Stubs 37 + ============ 38 + 39 + Static stubs are a way of redirecting calls to one function (the "real" 40 + function) to another function (the "replacement" function). 41 + 42 + It works by adding a macro to the "real" function which checks to see if a test 43 + is running, and if a replacement function is available. If so, that function is 44 + called in place of the original. 45 + 46 + Using static stubs is pretty straightforward: 47 + 48 + 1. Add the KUNIT_STATIC_STUB_REDIRECT() macro to the start of the "real" 49 + function. 50 + 51 + This should be the first statement in the function, after any variable 52 + declarations. KUNIT_STATIC_STUB_REDIRECT() takes the name of the 53 + function, followed by all of the arguments passed to the real function. 54 + 55 + For example: 56 + 57 + .. code-block:: c 58 + 59 + void send_data_to_hardware(const char *str) 60 + { 61 + KUNIT_STATIC_STUB_REDIRECT(send_data_to_hardware, str); 62 + /* real implementation */ 63 + } 64 + 65 + 2. Write one or more replacement functions. 66 + 67 + These functions should have the same function signature as the real function. 68 + In the event they need to access or modify test-specific state, they can use 69 + kunit_get_current_test() to get a struct kunit pointer. This can then 70 + be passed to the expectation/assertion macros, or used to look up KUnit 71 + resources. 72 + 73 + For example: 74 + 75 + .. code-block:: c 76 + 77 + void fake_send_data_to_hardware(const char *str) 78 + { 79 + struct kunit *test = kunit_get_current_test(); 80 + KUNIT_EXPECT_STREQ(test, str, "Hello World!"); 81 + } 82 + 83 + 3. Activate the static stub from your test. 84 + 85 + From within a test, the redirection can be enabled with 86 + kunit_activate_static_stub(), which accepts a struct kunit pointer, 87 + the real function, and the replacement function. You can call this several 88 + times with different replacement functions to swap out implementations of the 89 + function. 90 + 91 + In our example, this would be 92 + 93 + .. code-block:: c 94 + 95 + kunit_activate_static_stub(test, 96 + send_data_to_hardware, 97 + fake_send_data_to_hardware); 98 + 99 + 4. Call (perhaps indirectly) the real function. 100 + 101 + Once the redirection is activated, any call to the real function will call 102 + the replacement function instead. Such calls may be buried deep in the 103 + implementation of another function, but must occur from the test's kthread. 104 + 105 + For example: 106 + 107 + .. code-block:: c 108 + 109 + send_data_to_hardware("Hello World!"); /* Succeeds */ 110 + send_data_to_hardware("Something else"); /* Fails the test. */ 111 + 112 + 5. (Optionally) disable the stub. 113 + 114 + When you no longer need it, disable the redirection (and hence resume the 115 + original behaviour of the 'real' function) using 116 + kunit_deactivate_static_stub(). Otherwise, it will be automatically disabled 117 + when the test exits. 118 + 119 + For example: 120 + 121 + .. code-block:: c 122 + 123 + kunit_deactivate_static_stub(test, send_data_to_hardware); 124 + 125 + 126 + It's also possible to use these replacement functions to test to see if a 127 + function is called at all, for example: 128 + 129 + .. code-block:: c 130 + 131 + void send_data_to_hardware(const char *str) 132 + { 133 + KUNIT_STATIC_STUB_REDIRECT(send_data_to_hardware, str); 134 + /* real implementation */ 135 + } 136 + 137 + /* In test file */ 138 + int times_called = 0; 139 + void fake_send_data_to_hardware(const char *str) 140 + { 141 + times_called++; 142 + } 143 + ... 144 + /* In the test case, redirect calls for the duration of the test */ 145 + kunit_activate_static_stub(test, send_data_to_hardware, fake_send_data_to_hardware); 146 + 147 + send_data_to_hardware("hello"); 148 + KUNIT_EXPECT_EQ(test, times_called, 1); 149 + 150 + /* Can also deactivate the stub early, if wanted */ 151 + kunit_deactivate_static_stub(test, send_data_to_hardware); 152 + 153 + send_data_to_hardware("hello again"); 154 + KUNIT_EXPECT_EQ(test, times_called, 1); 155 + 156 + 157 + 158 + API Reference 159 + ============= 160 + 161 + .. kernel-doc:: include/kunit/static_stub.h 162 + :internal:
+10 -3
Documentation/dev-tools/kunit/api/index.rst
··· 4 4 API Reference 5 5 ============= 6 6 .. toctree:: 7 + :hidden: 7 8 8 9 test 9 10 resource 11 + functionredirection 10 12 11 - This section documents the KUnit kernel testing API. It is divided into the 13 + 14 + This page documents the KUnit kernel testing API. It is divided into the 12 15 following sections: 13 16 14 17 Documentation/dev-tools/kunit/api/test.rst 15 18 16 - - documents all of the standard testing API 19 + - Documents all of the standard testing API 17 20 18 21 Documentation/dev-tools/kunit/api/resource.rst 19 22 20 - - documents the KUnit resource API 23 + - Documents the KUnit resource API 24 + 25 + Documentation/dev-tools/kunit/api/functionredirection.rst 26 + 27 + - Documents the KUnit Function Redirection API