mbox series

[v2,0/6] kunit: Add macros to help write more complex tests

Message ID 20240826222015.1484-1-michal.wajdeczko@intel.com
Headers show
Series kunit: Add macros to help write more complex tests | expand

Message

Michal Wajdeczko Aug. 26, 2024, 10:20 p.m. UTC
v1: https://groups.google.com/g/kunit-dev/c/f4LIMLyofj8
v2: make it more complex and attempt to be thread safe
    s/FIXED_STUB/GLOBAL_STUB (David, Lucas)
    make it little more thread safe (Rae, David)
    wait until stub call finishes before test end (David)
    wait until stub call finishes before changing stub (David)
    allow stub deactivation (Rae)
    prefer kunit log (David)
    add simple selftest (Michal)
    also introduce ONLY_IF_KUNIT macro (Michal)

Sample output from the tests:

    $ tools/testing/kunit/kunit.py run *example*.*global* \
        --kunitconfig lib/kunit/.kunitconfig --raw_output

    KTAP version 1
    1..1
    # example: initializing suite
    KTAP version 1
    # Subtest: example
    # module: kunit_example_test
    1..1
    # example_global_stub_test: initializing
    # example_global_stub_test: add_two: redirecting to subtract_one
    # example_global_stub_test: add_two: redirecting to subtract_one
    # example_global_stub_test: cleaning up
    ok 1 example_global_stub_test
    # example: exiting suite
    ok 1 example

    $ tools/testing/kunit/kunit.py run *global*.*global* \
        --kunitconfig lib/kunit/.kunitconfig --raw_output

    KTAP version 1
    1..1
        KTAP version 1
        # Subtest: kunit_global_stub
        # module: kunit_test
        1..4
        # kunit_global_stub_test_activate: real_void_func: redirecting to replacement_void_func
        # kunit_global_stub_test_activate: real_func: redirecting to replacement_func
        # kunit_global_stub_test_activate: real_func: redirecting to replacement_func
        # kunit_global_stub_test_activate: real_func: redirecting to other_replacement_func
        # kunit_global_stub_test_activate: real_func: redirecting to other_replacement_func
        # kunit_global_stub_test_activate: real_func: redirecting to super_replacement_func
        # kunit_global_stub_test_activate: real_func: redirecting to super_replacement_func
        ok 1 kunit_global_stub_test_activate
        ok 2 kunit_global_stub_test_deactivate
        # kunit_global_stub_test_slow_deactivate: real_func: redirecting to slow_replacement_func
        # kunit_global_stub_test_slow_deactivate: real_func: redirecting to slow_replacement_func
        # kunit_global_stub_test_slow_deactivate: waiting for slow_replacement_func
        # kunit_global_stub_test_slow_deactivate.speed: slow
        ok 3 kunit_global_stub_test_slow_deactivate
        # kunit_global_stub_test_slow_replace: real_func: redirecting to slow_replacement_func
        # kunit_global_stub_test_slow_replace: real_func: redirecting to slow_replacement_func
        # kunit_global_stub_test_slow_replace: waiting for slow_replacement_func
        # kunit_global_stub_test_slow_replace: real_func: redirecting to other_replacement_func
        # kunit_global_stub_test_slow_replace.speed: slow
        ok 4 kunit_global_stub_test_slow_replace
    # kunit_global_stub: pass:4 fail:0 skip:0 total:4
    # Totals: pass:4 fail:0 skip:0 total:4
    ok 1 kunit_global_stub

Cc: Rae Moar <rmoar@google.com>
Cc: David Gow <davidgow@google.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>

Michal Wajdeczko (6):
  kunit: Introduce kunit_is_running()
  kunit: Add macro to conditionally expose declarations to tests
  kunit: Add macro to conditionally expose expressions to tests
  kunit: Allow function redirection outside of the KUnit thread
  kunit: Add example with alternate function redirection method
  kunit: Add some selftests for global stub redirection macros

 include/kunit/static_stub.h    | 158 ++++++++++++++++++++
 include/kunit/test-bug.h       |  12 +-
 include/kunit/visibility.h     |  16 +++
 lib/kunit/kunit-example-test.c |  67 +++++++++
 lib/kunit/kunit-test.c         | 254 ++++++++++++++++++++++++++++++++-
 lib/kunit/static_stub.c        |  49 +++++++
 6 files changed, 553 insertions(+), 3 deletions(-)

Comments

Lucas De Marchi Aug. 27, 2024, 2:18 p.m. UTC | #1
On Tue, Aug 27, 2024 at 12:20:14AM GMT, Michal Wajdeczko wrote:
>Add example how to use KUNIT_FIXED_STUB_REDIRECT and compare its

s/FIXED/GLOBAL/

>usage with the KUNIT_STATIC_STUB_REDIRECT. Also show how the
>DECLARE_IF_KUNIT macro could be helpful in declaring test data in
>the non-test data structures.
>
>Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
>Reviewed-by: Rae Moar <rmoar@google.com> #v1
>Reviewed-by: David Gow <davidgow@google.com> #v1
>---
>Cc: Daniel Latypov <dlatypov@google.com>
>Cc: Lucas De Marchi <lucas.demarchi@intel.com>
>---
>v2: add missing testcase description (Rae) and rebase
>---
> lib/kunit/kunit-example-test.c | 67 ++++++++++++++++++++++++++++++++++
> 1 file changed, 67 insertions(+)
>
>diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
>index 3056d6bc705d..146935a16883 100644
>--- a/lib/kunit/kunit-example-test.c
>+++ b/lib/kunit/kunit-example-test.c
>@@ -6,8 +6,10 @@
>  * Author: Brendan Higgins <brendanhiggins@google.com>
>  */
>
>+#include <linux/workqueue.h>
> #include <kunit/test.h>
> #include <kunit/static_stub.h>
>+#include <kunit/visibility.h>
>
> /*
>  * This is the most fundamental element of KUnit, the test case. A test case
>@@ -221,6 +223,70 @@ static void example_static_stub_using_fn_ptr_test(struct kunit *test)
> 	KUNIT_EXPECT_EQ(test, add_one(1), 2);
> }
>
>+/* This could be a location of various global stub functions. */
>+static struct {
>+	KUNIT_DECLARE_GLOBAL_STUB(add_two, int (*)(int i));
>+} stubs;
>+
>+/* This is a function we'll replace with stubs. */
>+static int add_two(int i)
>+{
>+	/* This will trigger the stub if active. */
>+	KUNIT_STATIC_STUB_REDIRECT(add_two, i);
>+	KUNIT_GLOBAL_STUB_REDIRECT(stubs.add_two, i);

Nice use of an outer storage so we can give it the same name. IMO this
should be encouraged.

>+
>+	return i + 2;
>+}
>+
>+struct add_two_async_work {
>+	struct work_struct work;
>+	int param;
>+	int result;
>+};
>+
>+static void add_two_async_func(struct work_struct *work)
>+{
>+	struct add_two_async_work *w = container_of(work, typeof(*w), work);
>+
>+	w->result = add_two(w->param);
>+}
>+
>+static int add_two_async(int i)
>+{
>+	struct add_two_async_work w = { .param = i };
>+
>+	INIT_WORK_ONSTACK(&w.work, add_two_async_func);
>+	schedule_work(&w.work);
>+	flush_work(&w.work);
>+	destroy_work_on_stack(&w.work);
>+
>+	return w.result;
>+}
>+
>+/*
>+ * This test shows how to use KUNIT_GLOBAL_STUB_REDIRECT and compares its
>+ * usage with the KUNIT_STATIC_STUB_REDIRECT.
>+ */
>+static void example_global_stub_test(struct kunit *test)
>+{
>+	/* static stub redirection works only for KUnit thread */
>+	kunit_activate_static_stub(test, add_two, subtract_one);
>+	KUNIT_EXPECT_EQ(test, add_two(1), subtract_one(1));
>+	KUNIT_EXPECT_NE_MSG(test, add_two_async(1), subtract_one(1),
>+			    "stub shouldn't be active outside KUnit thread!");
>+
>+	kunit_deactivate_static_stub(test, add_two);
>+	KUNIT_EXPECT_EQ(test, add_two(1), add_two(1));
>+
>+	/* fixed stub redirection works for KUnit and other threads */

s/fixed/global/


with those fixes,


Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>

thanks
Lucas De Marchi

>+	kunit_activate_global_stub(test, stubs.add_two, subtract_one);
>+	KUNIT_EXPECT_EQ(test, add_two(1), subtract_one(1));
>+	KUNIT_EXPECT_EQ(test, add_two_async(1), subtract_one(1));
>+
>+	kunit_deactivate_global_stub(test, stubs.add_two);
>+	KUNIT_EXPECT_EQ(test, add_two(1), add_two(1));
>+}
>+
> static const struct example_param {
> 	int value;
> } example_params_array[] = {
>@@ -294,6 +360,7 @@ static struct kunit_case example_test_cases[] = {
> 	KUNIT_CASE(example_all_expect_macros_test),
> 	KUNIT_CASE(example_static_stub_test),
> 	KUNIT_CASE(example_static_stub_using_fn_ptr_test),
>+	KUNIT_CASE(example_global_stub_test),
> 	KUNIT_CASE(example_priv_test),
> 	KUNIT_CASE_PARAM(example_params_test, example_gen_params),
> 	KUNIT_CASE_SLOW(example_slow_test),
>-- 
>2.43.0
>
Rae Moar Aug. 27, 2024, 7:04 p.m. UTC | #2
On Mon, Aug 26, 2024 at 3:20 PM Michal Wajdeczko
<michal.wajdeczko@intel.com> wrote:
>
> The ONLY_IF_KUNIT macro will add expression statement only if the
> CONFIG_KUNIT is enabled. Otherwise if CONFIG_KUNIT is not enabled
> it will evaluate always to 0.
>
> Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>

Hello!

Thanks for the second version of this patch series!

I definitely could see this new macro as being useful but I currently
don't see an example of its use in the rest of the patch series. How
do you see this macro as being used or do you have a current use case
for this macro?

I would be fine adding this macro without being used as long as
examples on how and why to use it are clearly documented.

Thanks!
-Rae

> ---
> Cc: Rae Moar <rmoar@google.com>
> Cc: David Gow <davidgow@google.com>
> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
> ---
>  include/kunit/visibility.h | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/include/kunit/visibility.h b/include/kunit/visibility.h
> index 1c23773f826c..69c71eacf368 100644
> --- a/include/kunit/visibility.h
> +++ b/include/kunit/visibility.h
> @@ -18,6 +18,13 @@
>       * @body: identifiers to be introduced conditionally
>       */
>      #define DECLARE_IF_KUNIT(body...)  body
> +    /**
> +     * ONLY_IF_KUNIT - A macro that adds expression statement only if
> +     * CONFIG_KUNIT is enabled. Otherwise if CONFIG_KUNIT is not enabled
> +     * it will evaluate always to 0.
> +     * @expr: expression to be introduced conditionally
> +     */
> +    #define ONLY_IF_KUNIT(expr...)     expr
>      /**
>       * VISIBLE_IF_KUNIT - A macro that sets symbols to be static if
>       * CONFIG_KUNIT is not enabled. Otherwise if CONFIG_KUNIT is enabled
> @@ -34,6 +41,7 @@
>             EXPORTED_FOR_KUNIT_TESTING)
>  #else
>      #define DECLARE_IF_KUNIT(body...)
> +    #define ONLY_IF_KUNIT(expr...) 0
>      #define VISIBLE_IF_KUNIT static
>      #define EXPORT_SYMBOL_IF_KUNIT(symbol)
>  #endif
> --
> 2.43.0
>
Michal Wajdeczko Aug. 27, 2024, 7:47 p.m. UTC | #3
On 27.08.2024 21:04, Rae Moar wrote:
> On Mon, Aug 26, 2024 at 3:20 PM Michal Wajdeczko
> <michal.wajdeczko@intel.com> wrote:
>>
>> The ONLY_IF_KUNIT macro will add expression statement only if the
>> CONFIG_KUNIT is enabled. Otherwise if CONFIG_KUNIT is not enabled
>> it will evaluate always to 0.
>>
>> Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
> 
> Hello!
> 
> Thanks for the second version of this patch series!
> 
> I definitely could see this new macro as being useful but I currently
> don't see an example of its use in the rest of the patch series. How
> do you see this macro as being used or do you have a current use case
> for this macro?

in Xe driver we have this macro defined as XE_TEST_ONLY [1]

[1] https://elixir.bootlin.com/linux/v6.11-rc5/A/ident/XE_TEST_ONLY

> 
> I would be fine adding this macro without being used as long as
> examples on how and why to use it are clearly documented.

sure, I'll try to add some usage in the example patch 5/6

> 
> Thanks!
> -Rae
> 
>> ---
>> Cc: Rae Moar <rmoar@google.com>
>> Cc: David Gow <davidgow@google.com>
>> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
>> ---
>>  include/kunit/visibility.h | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/include/kunit/visibility.h b/include/kunit/visibility.h
>> index 1c23773f826c..69c71eacf368 100644
>> --- a/include/kunit/visibility.h
>> +++ b/include/kunit/visibility.h
>> @@ -18,6 +18,13 @@
>>       * @body: identifiers to be introduced conditionally
>>       */
>>      #define DECLARE_IF_KUNIT(body...)  body
>> +    /**
>> +     * ONLY_IF_KUNIT - A macro that adds expression statement only if
>> +     * CONFIG_KUNIT is enabled. Otherwise if CONFIG_KUNIT is not enabled
>> +     * it will evaluate always to 0.
>> +     * @expr: expression to be introduced conditionally
>> +     */
>> +    #define ONLY_IF_KUNIT(expr...)     expr
>>      /**
>>       * VISIBLE_IF_KUNIT - A macro that sets symbols to be static if
>>       * CONFIG_KUNIT is not enabled. Otherwise if CONFIG_KUNIT is enabled
>> @@ -34,6 +41,7 @@
>>             EXPORTED_FOR_KUNIT_TESTING)
>>  #else
>>      #define DECLARE_IF_KUNIT(body...)
>> +    #define ONLY_IF_KUNIT(expr...) 0
>>      #define VISIBLE_IF_KUNIT static
>>      #define EXPORT_SYMBOL_IF_KUNIT(symbol)
>>  #endif
>> --
>> 2.43.0
>>