Re: [PATCH 2/2] Documentation: Add Function Redirection API docs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Dec 08, 2022 at 02:18:41PM +0800, David Gow wrote:
> From: Sadiya Kazi <sadiyakazi@xxxxxxxxxx>
> 
> 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: signature.asc
Description: PGP signature


[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux