mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 10:46:33 +00:00
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>
This commit is contained in:
parent
e047c5eaa7
commit
9ecc9cdd16
162
Documentation/dev-tools/kunit/api/functionredirection.rst
Normal file
162
Documentation/dev-tools/kunit/api/functionredirection.rst
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
========================
|
||||||
|
Function Redirection API
|
||||||
|
========================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
When writing unit tests, it's important to be able to isolate the code being
|
||||||
|
tested from other parts of the kernel. This ensures the reliability of the test
|
||||||
|
(it won't be affected by external factors), reduces dependencies on specific
|
||||||
|
hardware or config options (making the test easier to run), and protects the
|
||||||
|
stability of the rest of the system (making it less likely for test-specific
|
||||||
|
state to interfere with the rest of the system).
|
||||||
|
|
||||||
|
While for some code (typically generic data structures, helpers, and other
|
||||||
|
"pure functions") this is trivial, for others (like device drivers,
|
||||||
|
filesystems, core subsystems) the code is heavily coupled with other parts of
|
||||||
|
the kernel.
|
||||||
|
|
||||||
|
This coupling is often due to global state in some way: be it a global list of
|
||||||
|
devices, the filesystem, or some hardware state. Tests need to either carefully
|
||||||
|
manage, isolate, and restore state, or they can avoid it altogether by
|
||||||
|
replacing access to and mutation of this state with a "fake" or "mock" variant.
|
||||||
|
|
||||||
|
By refactoring access to such state, such as by introducing a layer of
|
||||||
|
indirection which can use or emulate a separate set of test state. However,
|
||||||
|
such refactoring comes with its own costs (and undertaking significant
|
||||||
|
refactoring before being able to write tests is suboptimal).
|
||||||
|
|
||||||
|
A simpler way to intercept and replace some of the function calls is to use
|
||||||
|
function redirection via static stubs.
|
||||||
|
|
||||||
|
|
||||||
|
Static Stubs
|
||||||
|
============
|
||||||
|
|
||||||
|
Static stubs are a way of redirecting calls to one function (the "real"
|
||||||
|
function) to another function (the "replacement" function).
|
||||||
|
|
||||||
|
It works by adding a macro to the "real" function which checks to see if a test
|
||||||
|
is running, and if a replacement function is available. If so, that function is
|
||||||
|
called in place of the original.
|
||||||
|
|
||||||
|
Using static stubs is pretty straightforward:
|
||||||
|
|
||||||
|
1. Add the KUNIT_STATIC_STUB_REDIRECT() macro to the start of the "real"
|
||||||
|
function.
|
||||||
|
|
||||||
|
This should be the first statement in the function, after any variable
|
||||||
|
declarations. KUNIT_STATIC_STUB_REDIRECT() takes the name of the
|
||||||
|
function, followed by all of the arguments passed to the real function.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void send_data_to_hardware(const char *str)
|
||||||
|
{
|
||||||
|
KUNIT_STATIC_STUB_REDIRECT(send_data_to_hardware, str);
|
||||||
|
/* real implementation */
|
||||||
|
}
|
||||||
|
|
||||||
|
2. Write one or more replacement functions.
|
||||||
|
|
||||||
|
These functions should have the same function signature as the real function.
|
||||||
|
In the event they need to access or modify test-specific state, they can use
|
||||||
|
kunit_get_current_test() to get a struct kunit pointer. This can then
|
||||||
|
be passed to the expectation/assertion macros, or used to look up KUnit
|
||||||
|
resources.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void fake_send_data_to_hardware(const char *str)
|
||||||
|
{
|
||||||
|
struct kunit *test = kunit_get_current_test();
|
||||||
|
KUNIT_EXPECT_STREQ(test, str, "Hello World!");
|
||||||
|
}
|
||||||
|
|
||||||
|
3. Activate the static stub from your test.
|
||||||
|
|
||||||
|
From within a test, the redirection can be enabled with
|
||||||
|
kunit_activate_static_stub(), which accepts a struct kunit pointer,
|
||||||
|
the real function, and the replacement function. You can call this several
|
||||||
|
times with different replacement functions to swap out implementations of the
|
||||||
|
function.
|
||||||
|
|
||||||
|
In our example, this would be
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
kunit_activate_static_stub(test,
|
||||||
|
send_data_to_hardware,
|
||||||
|
fake_send_data_to_hardware);
|
||||||
|
|
||||||
|
4. Call (perhaps indirectly) the real function.
|
||||||
|
|
||||||
|
Once the redirection is activated, any call to the real function will call
|
||||||
|
the replacement function instead. Such calls may be buried deep in the
|
||||||
|
implementation of another function, but must occur from the test's kthread.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
send_data_to_hardware("Hello World!"); /* Succeeds */
|
||||||
|
send_data_to_hardware("Something else"); /* Fails the test. */
|
||||||
|
|
||||||
|
5. (Optionally) disable the stub.
|
||||||
|
|
||||||
|
When you no longer need it, disable the redirection (and hence resume the
|
||||||
|
original behaviour of the 'real' function) using
|
||||||
|
kunit_deactivate_static_stub(). Otherwise, it will be automatically disabled
|
||||||
|
when the test exits.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
kunit_deactivate_static_stub(test, send_data_to_hardware);
|
||||||
|
|
||||||
|
|
||||||
|
It's also possible to use these replacement functions to test to see if a
|
||||||
|
function is called at all, for example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void send_data_to_hardware(const char *str)
|
||||||
|
{
|
||||||
|
KUNIT_STATIC_STUB_REDIRECT(send_data_to_hardware, str);
|
||||||
|
/* real implementation */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In test file */
|
||||||
|
int times_called = 0;
|
||||||
|
void fake_send_data_to_hardware(const char *str)
|
||||||
|
{
|
||||||
|
times_called++;
|
||||||
|
}
|
||||||
|
...
|
||||||
|
/* In the test case, redirect calls for the duration of the test */
|
||||||
|
kunit_activate_static_stub(test, send_data_to_hardware, fake_send_data_to_hardware);
|
||||||
|
|
||||||
|
send_data_to_hardware("hello");
|
||||||
|
KUNIT_EXPECT_EQ(test, times_called, 1);
|
||||||
|
|
||||||
|
/* Can also deactivate the stub early, if wanted */
|
||||||
|
kunit_deactivate_static_stub(test, send_data_to_hardware);
|
||||||
|
|
||||||
|
send_data_to_hardware("hello again");
|
||||||
|
KUNIT_EXPECT_EQ(test, times_called, 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. kernel-doc:: include/kunit/static_stub.h
|
||||||
|
:internal:
|
@ -4,17 +4,24 @@
|
|||||||
API Reference
|
API Reference
|
||||||
=============
|
=============
|
||||||
.. toctree::
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
test
|
test
|
||||||
resource
|
resource
|
||||||
|
functionredirection
|
||||||
|
|
||||||
This section documents the KUnit kernel testing API. It is divided into the
|
|
||||||
|
This page documents the KUnit kernel testing API. It is divided into the
|
||||||
following sections:
|
following sections:
|
||||||
|
|
||||||
Documentation/dev-tools/kunit/api/test.rst
|
Documentation/dev-tools/kunit/api/test.rst
|
||||||
|
|
||||||
- documents all of the standard testing API
|
- Documents all of the standard testing API
|
||||||
|
|
||||||
Documentation/dev-tools/kunit/api/resource.rst
|
Documentation/dev-tools/kunit/api/resource.rst
|
||||||
|
|
||||||
- documents the KUnit resource API
|
- Documents the KUnit resource API
|
||||||
|
|
||||||
|
Documentation/dev-tools/kunit/api/functionredirection.rst
|
||||||
|
|
||||||
|
- Documents the KUnit Function Redirection API
|
||||||
|
Loading…
x
Reference in New Issue
Block a user