From: Bagas Sanjaya <bagasdotme@gmail.com>
To: David Gow <davidgow@google.com>
Cc: Brendan Higgins <brendan.higgins@linux.dev>,
Shuah Khan <skhan@linuxfoundation.org>,
Daniel Latypov <dlatypov@google.com>,
Kees Cook <keescook@chromium.org>,
Sadiya Kazi <sadiyakazi@google.com>,
Steven Rostedt <rostedt@goodmis.org>,
Joe Fradley <joefradley@google.com>,
Steve Muckle <smuckle@google.com>,
Jonathan Corbet <corbet@lwn.net>,
linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/2] Documentation: Add Function Redirection API docs
Date: Thu, 8 Dec 2022 17:07:05 +0700 [thread overview]
Message-ID: <Y5G3SVt+oQvLjW1e@debian.me> (raw)
In-Reply-To: <20221208061841.2186447-3-davidgow@google.com>
[-- Attachment #1: Type: text/plain, Size: 7777 bytes --]
On Thu, Dec 08, 2022 at 02:18:41PM +0800, David Gow wrote:
> From: Sadiya Kazi <sadiyakazi@google.com>
>
> 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.
s/Added/Add
> diff --git a/Documentation/dev-tools/kunit/api/functionredirection.rst b/Documentation/dev-tools/kunit/api/functionredirection.rst
> new file mode 100644
> index 000000000000..fc7644dfea65
> --- /dev/null
> +++ b/Documentation/dev-tools/kunit/api/functionredirection.rst
> @@ -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).
Test reliability is test independence, right?
> +
> +While for some code (typically generic data structures, helpers, and toher
> +"pure function") this is trivial, for others (like device drivers, filesystems,
> +core subsystems) the code is heavily coupled with other parts of the kernel.
> +
> +This often involves global state in some way: be it global lists of devices,
> +the filesystem, or hardware state, this needs to be either carefully managed,
> +isolated, and restored, or avoided altogether by replacing access to and
> +mutation of this state with a "fake" or "mock" variant.
"... or hardware state; this needs ..."
> +
> +This can be done by refactoring the code to abstract out access to such state,
> +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 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, the redirection can be disabled (and hence the
> + original behaviour of the 'real' function resumed) using
> + kunit_deactivate_static_stub(). If the stub is not manually deactivated, it
> + will nevertheless be disabled when the test finishes.
> +
> + 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)
> + {
> + /* fake implementation */
> + 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:
> diff --git a/Documentation/dev-tools/kunit/api/index.rst b/Documentation/dev-tools/kunit/api/index.rst
> index 45ce04823f9f..2d8f756aab56 100644
> --- a/Documentation/dev-tools/kunit/api/index.rst
> +++ b/Documentation/dev-tools/kunit/api/index.rst
> @@ -4,17 +4,24 @@
> API Reference
> =============
> .. toctree::
> + :hidden:
>
> test
> 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:
>
> 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
>
> - - documents the KUnit resource API
> + - Documents the KUnit resource API
> +
> +Documentation/dev-tools/kunit/api/functionredirection.rst
> +
> + - Documents the KUnit Function Redirection API
Otherwise LGTM.
--
An old man doll... just what I always wanted! - Clara
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
next prev parent reply other threads:[~2022-12-08 10:07 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-12-08 6:18 [PATCH 0/2] kunit: Function Redirection ("static stub") support David Gow
2022-12-08 6:18 ` [PATCH 1/2] kunit: Expose 'static stub' API to redirect functions David Gow
2022-12-17 5:09 ` Brendan Higgins
2022-12-08 6:18 ` [PATCH 2/2] Documentation: Add Function Redirection API docs David Gow
2022-12-08 10:07 ` Bagas Sanjaya [this message]
2022-12-15 19:01 ` Daniel Latypov
2022-12-15 18:54 ` Daniel Latypov
2022-12-16 7:17 ` David Gow
2022-12-17 5:14 ` Brendan Higgins
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Y5G3SVt+oQvLjW1e@debian.me \
--to=bagasdotme@gmail.com \
--cc=brendan.higgins@linux.dev \
--cc=corbet@lwn.net \
--cc=davidgow@google.com \
--cc=dlatypov@google.com \
--cc=joefradley@google.com \
--cc=keescook@chromium.org \
--cc=kunit-dev@googlegroups.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=sadiyakazi@google.com \
--cc=skhan@linuxfoundation.org \
--cc=smuckle@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox