mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'linux_kselftest-kunit-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull KUnit updates from Shuah Khan:
- a new feature that adds APIs for managing devices introducing a set
of helper functions which allow devices (internally a struct
kunit_device) to be created and managed by KUnit.
These devices will be automatically unregistered on test exit. These
helpers can either use a user-provided struct device_driver, or have
one automatically created and managed by KUnit. In both cases, the
device lives on a new kunit_bus.
- changes to switch drm/tests to use kunit devices
- several fixes and enhancements to attribute feature
- changes to reorganize deferred action function introducing
KUNIT_DEFINE_ACTION_WRAPPER
- new feature adds ability to run tests after boot using debugfs
- fixes and enhancements to string-stream-test:
- parse ERR_PTR in string_stream_destroy()
- unchecked dereference in bug fix in debugfs_print_results()
- handling errors from alloc_string_stream()
- NULL-dereference bug fix in kunit_init_suite()
* tag 'linux_kselftest-kunit-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (27 commits)
kunit: Fix some comments which were mistakenly kerneldoc
kunit: Protect string comparisons against NULL
kunit: Add example of kunit_activate_static_stub() with pointer-to-function
kunit: Allow passing function pointer to kunit_activate_static_stub()
kunit: Fix NULL-dereference in kunit_init_suite() if suite->log is NULL
kunit: Reset test->priv after each param iteration
kunit: Add example for using test->priv
drm/tests: Switch to kunit devices
ASoC: topology: Replace fake root_device with kunit_device in tests
overflow: Replace fake root_device with kunit_device
fortify: test: Use kunit_device
kunit: Add APIs for managing devices
Documentation: Add debugfs docs with run after boot
kunit: add ability to run tests after boot using debugfs
kunit: add is_init test attribute
kunit: add example suite to test init suites
kunit: add KUNIT_INIT_TABLE to init linker section
kunit: move KUNIT_TABLE out of INIT_DATA
kunit: tool: add test for parsing attributes
kunit: tool: fix parsing of test attributes
...
This commit is contained in:
@@ -11,3 +11,12 @@ state on a per-test basis, register custom cleanup actions, and more.
|
||||
|
||||
.. kernel-doc:: include/kunit/resource.h
|
||||
:internal:
|
||||
|
||||
Managed Devices
|
||||
---------------
|
||||
|
||||
Functions for using KUnit-managed struct device and struct device_driver.
|
||||
Include ``kunit/device.h`` to use these.
|
||||
|
||||
.. kernel-doc:: include/kunit/device.h
|
||||
:internal:
|
||||
|
||||
@@ -49,9 +49,52 @@ loaded.
|
||||
|
||||
The results will appear in TAP format in ``dmesg``.
|
||||
|
||||
debugfs
|
||||
=======
|
||||
|
||||
KUnit can be accessed from userspace via the debugfs filesystem (See more
|
||||
information about debugfs at Documentation/filesystems/debugfs.rst).
|
||||
|
||||
If ``CONFIG_KUNIT_DEBUGFS`` is enabled, the KUnit debugfs filesystem is
|
||||
mounted at /sys/kernel/debug/kunit. You can use this filesystem to perform
|
||||
the following actions.
|
||||
|
||||
Retrieve Test Results
|
||||
=====================
|
||||
|
||||
You can use debugfs to retrieve KUnit test results. The test results are
|
||||
accessible from the debugfs filesystem in the following read-only file:
|
||||
|
||||
.. code-block :: bash
|
||||
|
||||
/sys/kernel/debug/kunit/<test_suite>/results
|
||||
|
||||
The test results are printed in a KTAP document. Note this document is separate
|
||||
to the kernel log and thus, may have different test suite numbering.
|
||||
|
||||
Run Tests After Kernel Has Booted
|
||||
=================================
|
||||
|
||||
You can use the debugfs filesystem to trigger built-in tests to run after
|
||||
boot. To run the test suite, you can use the following command to write to
|
||||
the ``/sys/kernel/debug/kunit/<test_suite>/run`` file:
|
||||
|
||||
.. code-block :: bash
|
||||
|
||||
echo "any string" > /sys/kernel/debugfs/kunit/<test_suite>/run
|
||||
|
||||
As a result, the test suite runs and the results are printed to the kernel
|
||||
log.
|
||||
|
||||
However, this feature is not available with KUnit suites that use init data,
|
||||
because init data may have been discarded after the kernel boots. KUnit
|
||||
suites that use init data should be defined using the
|
||||
kunit_test_init_section_suites() macro.
|
||||
|
||||
Also, you cannot use this feature to run tests concurrently. Instead a test
|
||||
will wait to run until other tests have completed or failed.
|
||||
|
||||
.. note ::
|
||||
|
||||
If ``CONFIG_KUNIT_DEBUGFS`` is enabled, KUnit test results will
|
||||
be accessible from the ``debugfs`` filesystem (if mounted).
|
||||
They will be in ``/sys/kernel/debug/kunit/<test_suite>/results``, in
|
||||
TAP format.
|
||||
For test authors, to use this feature, tests will need to correctly initialise
|
||||
and/or clean up any data, so the test runs correctly a second time.
|
||||
|
||||
@@ -428,3 +428,10 @@ This attribute indicates the name of the module associated with the test.
|
||||
|
||||
This attribute is automatically saved as a string and is printed for each suite.
|
||||
Tests can also be filtered using this attribute.
|
||||
|
||||
``is_init``
|
||||
|
||||
This attribute indicates whether the test uses init data or functions.
|
||||
|
||||
This attribute is automatically saved as a boolean and tests can also be
|
||||
filtered using this attribute.
|
||||
|
||||
@@ -651,12 +651,16 @@ For example:
|
||||
}
|
||||
|
||||
Note that, for functions like device_unregister which only accept a single
|
||||
pointer-sized argument, it's possible to directly cast that function to
|
||||
a ``kunit_action_t`` rather than writing a wrapper function, for example:
|
||||
pointer-sized argument, it's possible to automatically generate a wrapper
|
||||
with the ``KUNIT_DEFINE_ACTION_WRAPPER()`` macro, for example:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
kunit_add_action(test, (kunit_action_t *)&device_unregister, &dev);
|
||||
KUNIT_DEFINE_ACTION_WRAPPER(device_unregister, device_unregister_wrapper, struct device *);
|
||||
kunit_add_action(test, &device_unregister_wrapper, &dev);
|
||||
|
||||
You should do this in preference to manually casting to the ``kunit_action_t`` type,
|
||||
as casting function pointers will break Control Flow Integrity (CFI).
|
||||
|
||||
``kunit_add_action`` can fail if, for example, the system is out of memory.
|
||||
You can use ``kunit_add_action_or_reset`` instead which runs the action
|
||||
@@ -793,3 +797,53 @@ structures as shown below:
|
||||
KUnit is not enabled, or if no test is running in the current task, it will do
|
||||
nothing. This compiles down to either a no-op or a static key check, so will
|
||||
have a negligible performance impact when no test is running.
|
||||
|
||||
Managing Fake Devices and Drivers
|
||||
---------------------------------
|
||||
|
||||
When testing drivers or code which interacts with drivers, many functions will
|
||||
require a ``struct device`` or ``struct device_driver``. In many cases, setting
|
||||
up a real device is not required to test any given function, so a fake device
|
||||
can be used instead.
|
||||
|
||||
KUnit provides helper functions to create and manage these fake devices, which
|
||||
are internally of type ``struct kunit_device``, and are attached to a special
|
||||
``kunit_bus``. These devices support managed device resources (devres), as
|
||||
described in Documentation/driver-api/driver-model/devres.rst
|
||||
|
||||
To create a KUnit-managed ``struct device_driver``, use ``kunit_driver_create()``,
|
||||
which will create a driver with the given name, on the ``kunit_bus``. This driver
|
||||
will automatically be destroyed when the corresponding test finishes, but can also
|
||||
be manually destroyed with ``driver_unregister()``.
|
||||
|
||||
To create a fake device, use the ``kunit_device_register()``, which will create
|
||||
and register a device, using a new KUnit-managed driver created with ``kunit_driver_create()``.
|
||||
To provide a specific, non-KUnit-managed driver, use ``kunit_device_register_with_driver()``
|
||||
instead. Like with managed drivers, KUnit-managed fake devices are automatically
|
||||
cleaned up when the test finishes, but can be manually cleaned up early with
|
||||
``kunit_device_unregister()``.
|
||||
|
||||
The KUnit devices should be used in preference to ``root_device_register()``, and
|
||||
instead of ``platform_device_register()`` in cases where the device is not otherwise
|
||||
a platform device.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <kunit/device.h>
|
||||
|
||||
static void test_my_device(struct kunit *test)
|
||||
{
|
||||
struct device *fake_device;
|
||||
const char *dev_managed_string;
|
||||
|
||||
// Create a fake device.
|
||||
fake_device = kunit_device_register(test, "my_device");
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_device)
|
||||
|
||||
// Pass it to functions which need a device.
|
||||
dev_managed_string = devm_kstrdup(fake_device, "Hello, World!");
|
||||
|
||||
// Everything is cleaned up automatically when the test ends.
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <drm/drm_kunit_helpers.h>
|
||||
#include <drm/drm_managed.h>
|
||||
|
||||
#include <kunit/device.h>
|
||||
#include <kunit/resource.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
@@ -15,40 +16,6 @@
|
||||
static const struct drm_mode_config_funcs drm_mode_config_funcs = {
|
||||
};
|
||||
|
||||
static int fake_probe(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver fake_platform_driver = {
|
||||
.probe = fake_probe,
|
||||
.driver = {
|
||||
.name = KUNIT_DEVICE_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
static void kunit_action_platform_driver_unregister(void *ptr)
|
||||
{
|
||||
struct platform_driver *drv = ptr;
|
||||
|
||||
platform_driver_unregister(drv);
|
||||
|
||||
}
|
||||
|
||||
static void kunit_action_platform_device_put(void *ptr)
|
||||
{
|
||||
struct platform_device *pdev = ptr;
|
||||
|
||||
platform_device_put(pdev);
|
||||
}
|
||||
|
||||
static void kunit_action_platform_device_del(void *ptr)
|
||||
{
|
||||
struct platform_device *pdev = ptr;
|
||||
|
||||
platform_device_del(pdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
|
||||
* @test: The test context object
|
||||
@@ -66,34 +33,7 @@ static void kunit_action_platform_device_del(void *ptr)
|
||||
*/
|
||||
struct device *drm_kunit_helper_alloc_device(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&fake_platform_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = kunit_add_action_or_reset(test,
|
||||
kunit_action_platform_driver_unregister,
|
||||
&fake_platform_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
ret = kunit_add_action_or_reset(test,
|
||||
kunit_action_platform_device_put,
|
||||
pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = kunit_add_action_or_reset(test,
|
||||
kunit_action_platform_device_del,
|
||||
pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
return &pdev->dev;
|
||||
return kunit_device_register(test, KUNIT_DEVICE_NAME);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
|
||||
|
||||
@@ -106,19 +46,7 @@ EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
|
||||
*/
|
||||
void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
kunit_release_action(test,
|
||||
kunit_action_platform_device_del,
|
||||
pdev);
|
||||
|
||||
kunit_release_action(test,
|
||||
kunit_action_platform_device_put,
|
||||
pdev);
|
||||
|
||||
kunit_release_action(test,
|
||||
kunit_action_platform_driver_unregister,
|
||||
&fake_platform_driver);
|
||||
kunit_device_unregister(test, dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
|
||||
|
||||
|
||||
@@ -153,12 +153,9 @@ static int __build_mock(struct kunit *test, struct drm_device *drm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kunit_action_drm_dev_unregister(void *ptr)
|
||||
{
|
||||
struct drm_device *drm = ptr;
|
||||
|
||||
drm_dev_unregister(drm);
|
||||
}
|
||||
KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_drm_dev_unregister,
|
||||
drm_dev_unregister,
|
||||
struct drm_device *);
|
||||
|
||||
static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5)
|
||||
{
|
||||
|
||||
@@ -370,7 +370,8 @@
|
||||
BRANCH_PROFILE() \
|
||||
TRACE_PRINTKS() \
|
||||
BPF_RAW_TP() \
|
||||
TRACEPOINT_STR()
|
||||
TRACEPOINT_STR() \
|
||||
KUNIT_TABLE()
|
||||
|
||||
/*
|
||||
* Data section helpers
|
||||
@@ -700,7 +701,7 @@
|
||||
EARLYCON_TABLE() \
|
||||
LSM_TABLE() \
|
||||
EARLY_LSM_TABLE() \
|
||||
KUNIT_TABLE()
|
||||
KUNIT_INIT_TABLE()
|
||||
|
||||
#define INIT_TEXT \
|
||||
*(.init.text .init.text.*) \
|
||||
@@ -926,6 +927,12 @@
|
||||
. = ALIGN(8); \
|
||||
BOUNDED_SECTION_POST_LABEL(.kunit_test_suites, __kunit_suites, _start, _end)
|
||||
|
||||
/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
|
||||
#define KUNIT_INIT_TABLE() \
|
||||
. = ALIGN(8); \
|
||||
BOUNDED_SECTION_POST_LABEL(.kunit_init_test_suites, \
|
||||
__kunit_init_suites, _start, _end)
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
#define INIT_RAM_FS \
|
||||
. = ALIGN(4); \
|
||||
|
||||
80
include/kunit/device.h
Normal file
80
include/kunit/device.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* KUnit basic device implementation
|
||||
*
|
||||
* Helpers for creating and managing fake devices for KUnit tests.
|
||||
*
|
||||
* Copyright (C) 2023, Google LLC.
|
||||
* Author: David Gow <davidgow@google.com>
|
||||
*/
|
||||
|
||||
#ifndef _KUNIT_DEVICE_H
|
||||
#define _KUNIT_DEVICE_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_KUNIT)
|
||||
|
||||
#include <kunit/test.h>
|
||||
|
||||
struct device;
|
||||
struct device_driver;
|
||||
|
||||
/**
|
||||
* kunit_driver_create() - Create a struct device_driver attached to the kunit_bus
|
||||
* @test: The test context object.
|
||||
* @name: The name to give the created driver.
|
||||
*
|
||||
* Creates a struct device_driver attached to the kunit_bus, with the name @name.
|
||||
* This driver will automatically be cleaned up on test exit.
|
||||
*
|
||||
* Return: a stub struct device_driver, managed by KUnit, with the name @name.
|
||||
*/
|
||||
struct device_driver *kunit_driver_create(struct kunit *test, const char *name);
|
||||
|
||||
/**
|
||||
* kunit_device_register() - Create a struct device for use in KUnit tests
|
||||
* @test: The test context object.
|
||||
* @name: The name to give the created device.
|
||||
*
|
||||
* Creates a struct kunit_device (which is a struct device) with the given name,
|
||||
* and a corresponding driver. The device and driver will be cleaned up on test
|
||||
* exit, or when kunit_device_unregister is called. See also
|
||||
* kunit_device_register_with_driver, if you wish to provide your own
|
||||
* struct device_driver.
|
||||
*
|
||||
* Return: a pointer to a struct device which will be cleaned up when the test
|
||||
* exits, or an error pointer if the device could not be allocated or registered.
|
||||
*/
|
||||
struct device *kunit_device_register(struct kunit *test, const char *name);
|
||||
|
||||
/**
|
||||
* kunit_device_register_with_driver() - Create a struct device for use in KUnit tests
|
||||
* @test: The test context object.
|
||||
* @name: The name to give the created device.
|
||||
* @drv: The struct device_driver to associate with the device.
|
||||
*
|
||||
* Creates a struct kunit_device (which is a struct device) with the given
|
||||
* name, and driver. The device will be cleaned up on test exit, or when
|
||||
* kunit_device_unregister is called. See also kunit_device_register, if you
|
||||
* wish KUnit to create and manage a driver for you.
|
||||
*
|
||||
* Return: a pointer to a struct device which will be cleaned up when the test
|
||||
* exits, or an error pointer if the device could not be allocated or registered.
|
||||
*/
|
||||
struct device *kunit_device_register_with_driver(struct kunit *test,
|
||||
const char *name,
|
||||
const struct device_driver *drv);
|
||||
|
||||
/**
|
||||
* kunit_device_unregister() - Unregister a KUnit-managed device
|
||||
* @test: The test context object which created the device
|
||||
* @dev: The device.
|
||||
*
|
||||
* Unregisters and destroys a struct device which was created with
|
||||
* kunit_device_register or kunit_device_register_with_driver. If KUnit created
|
||||
* a driver, cleans it up as well.
|
||||
*/
|
||||
void kunit_device_unregister(struct kunit *test, struct device *dev);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -390,6 +390,27 @@ void kunit_remove_resource(struct kunit *test, struct kunit_resource *res);
|
||||
/* A 'deferred action' function to be used with kunit_add_action. */
|
||||
typedef void (kunit_action_t)(void *);
|
||||
|
||||
/**
|
||||
* KUNIT_DEFINE_ACTION_WRAPPER() - Wrap a function for use as a deferred action.
|
||||
*
|
||||
* @wrapper: The name of the new wrapper function define.
|
||||
* @orig: The original function to wrap.
|
||||
* @arg_type: The type of the argument accepted by @orig.
|
||||
*
|
||||
* Defines a wrapper for a function which accepts a single, pointer-sized
|
||||
* argument. This wrapper can then be passed to kunit_add_action() and
|
||||
* similar. This should be used in preference to casting a function
|
||||
* directly to kunit_action_t, as casting function pointers will break
|
||||
* control flow integrity (CFI), leading to crashes.
|
||||
*/
|
||||
#define KUNIT_DEFINE_ACTION_WRAPPER(wrapper, orig, arg_type) \
|
||||
static void wrapper(void *in) \
|
||||
{ \
|
||||
arg_type arg = (arg_type)in; \
|
||||
orig(arg); \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* kunit_add_action() - Call a function when the test ends.
|
||||
* @test: Test case to associate the action with.
|
||||
|
||||
@@ -93,7 +93,7 @@ void __kunit_activate_static_stub(struct kunit *test,
|
||||
* The redirection can be disabled again with kunit_deactivate_static_stub().
|
||||
*/
|
||||
#define kunit_activate_static_stub(test, real_fn_addr, replacement_addr) do { \
|
||||
typecheck_fn(typeof(&real_fn_addr), replacement_addr); \
|
||||
typecheck_fn(typeof(&replacement_addr), real_fn_addr); \
|
||||
__kunit_activate_static_stub(test, real_fn_addr, replacement_addr); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -253,6 +253,7 @@ struct kunit_suite {
|
||||
struct dentry *debugfs;
|
||||
struct string_stream *log;
|
||||
int suite_init_err;
|
||||
bool is_init;
|
||||
};
|
||||
|
||||
/* Stores an array of suites, end points one past the end */
|
||||
@@ -337,6 +338,9 @@ void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites);
|
||||
void kunit_exec_run_tests(struct kunit_suite_set *suite_set, bool builtin);
|
||||
void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool include_attr);
|
||||
|
||||
struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set,
|
||||
struct kunit_suite_set suite_set);
|
||||
|
||||
#if IS_BUILTIN(CONFIG_KUNIT)
|
||||
int kunit_run_all_tests(void);
|
||||
#else
|
||||
@@ -371,6 +375,11 @@ static inline int kunit_run_all_tests(void)
|
||||
|
||||
#define kunit_test_suite(suite) kunit_test_suites(&suite)
|
||||
|
||||
#define __kunit_init_test_suites(unique_array, ...) \
|
||||
static struct kunit_suite *unique_array[] \
|
||||
__aligned(sizeof(struct kunit_suite *)) \
|
||||
__used __section(".kunit_init_test_suites") = { __VA_ARGS__ }
|
||||
|
||||
/**
|
||||
* kunit_test_init_section_suites() - used to register one or more &struct
|
||||
* kunit_suite containing init functions or
|
||||
@@ -378,21 +387,21 @@ static inline int kunit_run_all_tests(void)
|
||||
*
|
||||
* @__suites: a statically allocated list of &struct kunit_suite.
|
||||
*
|
||||
* This functions identically as kunit_test_suites() except that it suppresses
|
||||
* modpost warnings for referencing functions marked __init or data marked
|
||||
* __initdata; this is OK because currently KUnit only runs tests upon boot
|
||||
* during the init phase or upon loading a module during the init phase.
|
||||
* This functions similar to kunit_test_suites() except that it compiles the
|
||||
* list of suites during init phase.
|
||||
*
|
||||
* NOTE TO KUNIT DEVS: If we ever allow KUnit tests to be run after boot, these
|
||||
* tests must be excluded.
|
||||
* This macro also suffixes the array and suite declarations it makes with
|
||||
* _probe; so that modpost suppresses warnings about referencing init data
|
||||
* for symbols named in this manner.
|
||||
*
|
||||
* The only thing this macro does that's different from kunit_test_suites is
|
||||
* that it suffixes the array and suite declarations it makes with _probe;
|
||||
* modpost suppresses warnings about referencing init data for symbols named in
|
||||
* this manner.
|
||||
* Note: these init tests are not able to be run after boot so there is no
|
||||
* "run" debugfs file generated for these tests.
|
||||
*
|
||||
* Also, do not mark the suite or test case structs with __initdata because
|
||||
* they will be used after the init phase with debugfs.
|
||||
*/
|
||||
#define kunit_test_init_section_suites(__suites...) \
|
||||
__kunit_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe), \
|
||||
__kunit_init_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe), \
|
||||
##__suites)
|
||||
|
||||
#define kunit_test_init_section_suite(suite) \
|
||||
@@ -749,7 +758,7 @@ do { \
|
||||
.right_text = #right, \
|
||||
}; \
|
||||
\
|
||||
if (likely(strcmp(__left, __right) op 0)) \
|
||||
if (likely((__left) && (__right) && (strcmp(__left, __right) op 0))) \
|
||||
break; \
|
||||
\
|
||||
\
|
||||
|
||||
@@ -540,6 +540,8 @@ struct module {
|
||||
struct static_call_site *static_call_sites;
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_KUNIT)
|
||||
int num_kunit_init_suites;
|
||||
struct kunit_suite **kunit_init_suites;
|
||||
int num_kunit_suites;
|
||||
struct kunit_suite **kunit_suites;
|
||||
#endif
|
||||
|
||||
@@ -2199,6 +2199,9 @@ static int find_module_sections(struct module *mod, struct load_info *info)
|
||||
mod->kunit_suites = section_objs(info, ".kunit_test_suites",
|
||||
sizeof(*mod->kunit_suites),
|
||||
&mod->num_kunit_suites);
|
||||
mod->kunit_init_suites = section_objs(info, ".kunit_init_test_suites",
|
||||
sizeof(*mod->kunit_init_suites),
|
||||
&mod->num_kunit_init_suites);
|
||||
#endif
|
||||
|
||||
mod->extable = section_objs(info, "__ex_table",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <kunit/device.h>
|
||||
#include <kunit/test.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -269,7 +270,7 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(kvmalloc)
|
||||
size_t len; \
|
||||
\
|
||||
/* Create dummy device for devm_kmalloc()-family tests. */ \
|
||||
dev = root_device_register(dev_name); \
|
||||
dev = kunit_device_register(test, dev_name); \
|
||||
KUNIT_ASSERT_FALSE_MSG(test, IS_ERR(dev), \
|
||||
"Cannot register test device\n"); \
|
||||
\
|
||||
@@ -303,7 +304,7 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(kvmalloc)
|
||||
checker(len, devm_kmemdup(dev, "Ohai", len, gfp), \
|
||||
devm_kfree(dev, p)); \
|
||||
\
|
||||
device_unregister(dev); \
|
||||
kunit_device_unregister(test, dev); \
|
||||
} while (0)
|
||||
DEFINE_ALLOC_SIZE_TEST_PAIR(devm_kmalloc)
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ kunit-objs += test.o \
|
||||
assert.o \
|
||||
try-catch.o \
|
||||
executor.o \
|
||||
attributes.o
|
||||
attributes.o \
|
||||
device.o
|
||||
|
||||
ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
|
||||
kunit-objs += debugfs.o
|
||||
|
||||
@@ -58,6 +58,16 @@ static const char *attr_enum_to_string(void *attr, const char * const str_list[]
|
||||
return str_list[val];
|
||||
}
|
||||
|
||||
static const char *attr_bool_to_string(void *attr, bool *to_free)
|
||||
{
|
||||
bool val = (bool)attr;
|
||||
|
||||
*to_free = false;
|
||||
if (val)
|
||||
return "true";
|
||||
return "false";
|
||||
}
|
||||
|
||||
static const char *attr_speed_to_string(void *attr, bool *to_free)
|
||||
{
|
||||
return attr_enum_to_string(attr, speed_str_list, to_free);
|
||||
@@ -166,6 +176,37 @@ static int attr_string_filter(void *attr, const char *input, int *err)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int attr_bool_filter(void *attr, const char *input, int *err)
|
||||
{
|
||||
int i, input_int = -1;
|
||||
long val = (long)attr;
|
||||
const char *input_str = NULL;
|
||||
|
||||
for (i = 0; input[i]; i++) {
|
||||
if (!strchr(op_list, input[i])) {
|
||||
input_str = input + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!input_str) {
|
||||
*err = -EINVAL;
|
||||
pr_err("kunit executor: filter value not found: %s\n", input);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strcmp(input_str, "true"))
|
||||
input_int = (int)true;
|
||||
else if (!strcmp(input_str, "false"))
|
||||
input_int = (int)false;
|
||||
else {
|
||||
*err = -EINVAL;
|
||||
pr_err("kunit executor: invalid filter input: %s\n", input);
|
||||
return false;
|
||||
}
|
||||
|
||||
return int_filter(val, input, input_int, err);
|
||||
}
|
||||
|
||||
/* Get Attribute Methods */
|
||||
|
||||
@@ -194,6 +235,17 @@ static void *attr_module_get(void *test_or_suite, bool is_test)
|
||||
return (void *) "";
|
||||
}
|
||||
|
||||
static void *attr_is_init_get(void *test_or_suite, bool is_test)
|
||||
{
|
||||
struct kunit_suite *suite = is_test ? NULL : test_or_suite;
|
||||
struct kunit_case *test = is_test ? test_or_suite : NULL;
|
||||
|
||||
if (test)
|
||||
return ((void *) NULL);
|
||||
else
|
||||
return ((void *) suite->is_init);
|
||||
}
|
||||
|
||||
/* List of all Test Attributes */
|
||||
|
||||
static struct kunit_attr kunit_attr_list[] = {
|
||||
@@ -212,6 +264,14 @@ static struct kunit_attr kunit_attr_list[] = {
|
||||
.filter = attr_string_filter,
|
||||
.attr_default = (void *)"",
|
||||
.print = PRINT_SUITE,
|
||||
},
|
||||
{
|
||||
.name = "is_init",
|
||||
.get_attr = attr_is_init_get,
|
||||
.to_string = attr_bool_to_string,
|
||||
.filter = attr_bool_filter,
|
||||
.attr_default = (void *)false,
|
||||
.print = PRINT_SUITE,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/test-bug.h>
|
||||
|
||||
#include "string-stream.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
#define KUNIT_DEBUGFS_ROOT "kunit"
|
||||
#define KUNIT_DEBUGFS_RESULTS "results"
|
||||
#define KUNIT_DEBUGFS_RUN "run"
|
||||
|
||||
/*
|
||||
* Create a debugfs representation of test suites:
|
||||
@@ -21,6 +23,8 @@
|
||||
* Path Semantics
|
||||
* /sys/kernel/debug/kunit/<testsuite>/results Show results of last run for
|
||||
* testsuite
|
||||
* /sys/kernel/debug/kunit/<testsuite>/run Write to this file to trigger
|
||||
* testsuite to run
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -60,12 +64,14 @@ static void debugfs_print_result(struct seq_file *seq, struct string_stream *log
|
||||
static int debugfs_print_results(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct kunit_suite *suite = (struct kunit_suite *)seq->private;
|
||||
enum kunit_status success = kunit_suite_has_succeeded(suite);
|
||||
enum kunit_status success;
|
||||
struct kunit_case *test_case;
|
||||
|
||||
if (!suite)
|
||||
return 0;
|
||||
|
||||
success = kunit_suite_has_succeeded(suite);
|
||||
|
||||
/* Print KTAP header so the debugfs log can be parsed as valid KTAP. */
|
||||
seq_puts(seq, "KTAP version 1\n");
|
||||
seq_puts(seq, "1..1\n");
|
||||
@@ -99,6 +105,51 @@ static int debugfs_results_open(struct inode *inode, struct file *file)
|
||||
return single_open(file, debugfs_print_results, suite);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a usage message to the debugfs "run" file
|
||||
* (/sys/kernel/debug/kunit/<testsuite>/run) if opened.
|
||||
*/
|
||||
static int debugfs_print_run(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct kunit_suite *suite = (struct kunit_suite *)seq->private;
|
||||
|
||||
seq_puts(seq, "Write to this file to trigger the test suite to run.\n");
|
||||
seq_printf(seq, "usage: echo \"any string\" > /sys/kernel/debugfs/kunit/%s/run\n",
|
||||
suite->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The debugfs "run" file (/sys/kernel/debug/kunit/<testsuite>/run)
|
||||
* contains no information. Write to the file to trigger the test suite
|
||||
* to run.
|
||||
*/
|
||||
static int debugfs_run_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct kunit_suite *suite;
|
||||
|
||||
suite = (struct kunit_suite *)inode->i_private;
|
||||
|
||||
return single_open(file, debugfs_print_run, suite);
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger a test suite to run by writing to the suite's "run" debugfs
|
||||
* file found at: /sys/kernel/debug/kunit/<testsuite>/run
|
||||
*
|
||||
* Note: what is written to this file will not be saved.
|
||||
*/
|
||||
static ssize_t debugfs_run(struct file *file,
|
||||
const char __user *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct inode *f_inode = file->f_inode;
|
||||
struct kunit_suite *suite = (struct kunit_suite *) f_inode->i_private;
|
||||
|
||||
__kunit_test_suites_init(&suite, 1);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations debugfs_results_fops = {
|
||||
.open = debugfs_results_open,
|
||||
.read = seq_read,
|
||||
@@ -106,17 +157,43 @@ static const struct file_operations debugfs_results_fops = {
|
||||
.release = debugfs_release,
|
||||
};
|
||||
|
||||
static const struct file_operations debugfs_run_fops = {
|
||||
.open = debugfs_run_open,
|
||||
.read = seq_read,
|
||||
.write = debugfs_run,
|
||||
.llseek = seq_lseek,
|
||||
.release = debugfs_release,
|
||||
};
|
||||
|
||||
void kunit_debugfs_create_suite(struct kunit_suite *suite)
|
||||
{
|
||||
struct kunit_case *test_case;
|
||||
struct string_stream *stream;
|
||||
|
||||
/* Allocate logs before creating debugfs representation. */
|
||||
suite->log = alloc_string_stream(GFP_KERNEL);
|
||||
string_stream_set_append_newlines(suite->log, true);
|
||||
/* If suite log already allocated, do not create new debugfs files. */
|
||||
if (suite->log)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Allocate logs before creating debugfs representation.
|
||||
* The suite->log and test_case->log pointer are expected to be NULL
|
||||
* if there isn't a log, so only set it if the log stream was created
|
||||
* successfully.
|
||||
*/
|
||||
stream = alloc_string_stream(GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(stream))
|
||||
return;
|
||||
|
||||
string_stream_set_append_newlines(stream, true);
|
||||
suite->log = stream;
|
||||
|
||||
kunit_suite_for_each_test_case(suite, test_case) {
|
||||
test_case->log = alloc_string_stream(GFP_KERNEL);
|
||||
string_stream_set_append_newlines(test_case->log, true);
|
||||
stream = alloc_string_stream(GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(stream))
|
||||
goto err;
|
||||
|
||||
string_stream_set_append_newlines(stream, true);
|
||||
test_case->log = stream;
|
||||
}
|
||||
|
||||
suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir);
|
||||
@@ -124,6 +201,19 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite)
|
||||
debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444,
|
||||
suite->debugfs,
|
||||
suite, &debugfs_results_fops);
|
||||
|
||||
/* Do not create file to re-run test if test runs on init */
|
||||
if (!suite->is_init) {
|
||||
debugfs_create_file(KUNIT_DEBUGFS_RUN, S_IFREG | 0644,
|
||||
suite->debugfs,
|
||||
suite, &debugfs_run_fops);
|
||||
}
|
||||
return;
|
||||
|
||||
err:
|
||||
string_stream_destroy(suite->log);
|
||||
kunit_suite_for_each_test_case(suite, test_case)
|
||||
string_stream_destroy(test_case->log);
|
||||
}
|
||||
|
||||
void kunit_debugfs_destroy_suite(struct kunit_suite *suite)
|
||||
|
||||
17
lib/kunit/device-impl.h
Normal file
17
lib/kunit/device-impl.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* KUnit internal header for device helpers
|
||||
*
|
||||
* Header for KUnit-internal driver / bus management.
|
||||
*
|
||||
* Copyright (C) 2023, Google LLC.
|
||||
* Author: David Gow <davidgow@google.com>
|
||||
*/
|
||||
|
||||
#ifndef _KUNIT_DEVICE_IMPL_H
|
||||
#define _KUNIT_DEVICE_IMPL_H
|
||||
|
||||
// For internal use only -- registers the kunit_bus.
|
||||
int kunit_bus_init(void);
|
||||
|
||||
#endif //_KUNIT_DEVICE_IMPL_H
|
||||
181
lib/kunit/device.c
Normal file
181
lib/kunit/device.c
Normal file
@@ -0,0 +1,181 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* KUnit-managed device implementation
|
||||
*
|
||||
* Implementation of struct kunit_device helpers for fake devices whose
|
||||
* lifecycle is managed by KUnit.
|
||||
*
|
||||
* Copyright (C) 2023, Google LLC.
|
||||
* Author: David Gow <davidgow@google.com>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/device.h>
|
||||
#include <kunit/resource.h>
|
||||
|
||||
#include "device-impl.h"
|
||||
|
||||
/* Wrappers for use with kunit_add_action() */
|
||||
KUNIT_DEFINE_ACTION_WRAPPER(device_unregister_wrapper, device_unregister, struct device *);
|
||||
KUNIT_DEFINE_ACTION_WRAPPER(driver_unregister_wrapper, driver_unregister, struct device_driver *);
|
||||
|
||||
/* The root device for the KUnit bus, parent of all kunit_devices. */
|
||||
static struct device *kunit_bus_device;
|
||||
|
||||
/* A device owned by a KUnit test. */
|
||||
struct kunit_device {
|
||||
struct device dev;
|
||||
/* The KUnit test which owns this device. */
|
||||
struct kunit *owner;
|
||||
/* If the driver is managed by KUnit and unique to this device. */
|
||||
const struct device_driver *driver;
|
||||
};
|
||||
|
||||
#define to_kunit_device(d) container_of_const(d, struct kunit_device, dev)
|
||||
|
||||
static struct bus_type kunit_bus_type = {
|
||||
.name = "kunit",
|
||||
};
|
||||
|
||||
/* Register the 'kunit_bus' used for fake devices. */
|
||||
int kunit_bus_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
kunit_bus_device = root_device_register("kunit");
|
||||
if (!kunit_bus_device)
|
||||
return -ENOMEM;
|
||||
|
||||
error = bus_register(&kunit_bus_type);
|
||||
if (error)
|
||||
bus_unregister(&kunit_bus_type);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Release a 'fake' KUnit device. */
|
||||
static void kunit_device_release(struct device *d)
|
||||
{
|
||||
kfree(to_kunit_device(d));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and register a KUnit-managed struct device_driver on the kunit_bus.
|
||||
* Returns an error pointer on failure.
|
||||
*/
|
||||
struct device_driver *kunit_driver_create(struct kunit *test, const char *name)
|
||||
{
|
||||
struct device_driver *driver;
|
||||
int err = -ENOMEM;
|
||||
|
||||
driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL);
|
||||
|
||||
if (!driver)
|
||||
return ERR_PTR(err);
|
||||
|
||||
driver->name = name;
|
||||
driver->bus = &kunit_bus_type;
|
||||
driver->owner = THIS_MODULE;
|
||||
|
||||
err = driver_register(driver);
|
||||
if (err) {
|
||||
kunit_kfree(test, driver);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
kunit_add_action(test, driver_unregister_wrapper, driver);
|
||||
return driver;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_driver_create);
|
||||
|
||||
/* Helper which creates a kunit_device, attaches it to the kunit_bus*/
|
||||
static struct kunit_device *kunit_device_register_internal(struct kunit *test,
|
||||
const char *name,
|
||||
const struct device_driver *drv)
|
||||
{
|
||||
struct kunit_device *kunit_dev;
|
||||
int err = -ENOMEM;
|
||||
|
||||
kunit_dev = kzalloc(sizeof(*kunit_dev), GFP_KERNEL);
|
||||
if (!kunit_dev)
|
||||
return ERR_PTR(err);
|
||||
|
||||
kunit_dev->owner = test;
|
||||
|
||||
err = dev_set_name(&kunit_dev->dev, "%s.%s", test->name, name);
|
||||
if (err) {
|
||||
kfree(kunit_dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
kunit_dev->dev.release = kunit_device_release;
|
||||
kunit_dev->dev.bus = &kunit_bus_type;
|
||||
kunit_dev->dev.parent = kunit_bus_device;
|
||||
|
||||
err = device_register(&kunit_dev->dev);
|
||||
if (err) {
|
||||
put_device(&kunit_dev->dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
kunit_add_action(test, device_unregister_wrapper, &kunit_dev->dev);
|
||||
|
||||
return kunit_dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and register a new KUnit-managed device, using the user-supplied device_driver.
|
||||
* On failure, returns an error pointer.
|
||||
*/
|
||||
struct device *kunit_device_register_with_driver(struct kunit *test,
|
||||
const char *name,
|
||||
const struct device_driver *drv)
|
||||
{
|
||||
struct kunit_device *kunit_dev = kunit_device_register_internal(test, name, drv);
|
||||
|
||||
if (IS_ERR_OR_NULL(kunit_dev))
|
||||
return ERR_CAST(kunit_dev);
|
||||
|
||||
return &kunit_dev->dev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_device_register_with_driver);
|
||||
|
||||
/*
|
||||
* Create and register a new KUnit-managed device, including a matching device_driver.
|
||||
* On failure, returns an error pointer.
|
||||
*/
|
||||
struct device *kunit_device_register(struct kunit *test, const char *name)
|
||||
{
|
||||
struct device_driver *drv;
|
||||
struct kunit_device *dev;
|
||||
|
||||
drv = kunit_driver_create(test, name);
|
||||
if (IS_ERR(drv))
|
||||
return ERR_CAST(drv);
|
||||
|
||||
dev = kunit_device_register_internal(test, name, drv);
|
||||
if (IS_ERR(dev)) {
|
||||
kunit_release_action(test, driver_unregister_wrapper, (void *)drv);
|
||||
return ERR_CAST(dev);
|
||||
}
|
||||
|
||||
/* Request the driver be freed. */
|
||||
dev->driver = drv;
|
||||
|
||||
|
||||
return &dev->dev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_device_register);
|
||||
|
||||
/* Unregisters a KUnit-managed device early (including the driver, if automatically created). */
|
||||
void kunit_device_unregister(struct kunit *test, struct device *dev)
|
||||
{
|
||||
const struct device_driver *driver = to_kunit_device(dev)->driver;
|
||||
|
||||
kunit_release_action(test, device_unregister_wrapper, dev);
|
||||
if (driver)
|
||||
kunit_release_action(test, driver_unregister_wrapper, (void *)driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_device_unregister);
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
*/
|
||||
extern struct kunit_suite * const __kunit_suites_start[];
|
||||
extern struct kunit_suite * const __kunit_suites_end[];
|
||||
extern struct kunit_suite * const __kunit_init_suites_start[];
|
||||
extern struct kunit_suite * const __kunit_init_suites_end[];
|
||||
|
||||
static char *action_param;
|
||||
|
||||
@@ -292,6 +294,37 @@ void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool include_attr)
|
||||
}
|
||||
}
|
||||
|
||||
struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set,
|
||||
struct kunit_suite_set suite_set)
|
||||
{
|
||||
struct kunit_suite_set total_suite_set = {NULL, NULL};
|
||||
struct kunit_suite **total_suite_start = NULL;
|
||||
size_t init_num_suites, num_suites, suite_size;
|
||||
int i = 0;
|
||||
|
||||
init_num_suites = init_suite_set.end - init_suite_set.start;
|
||||
num_suites = suite_set.end - suite_set.start;
|
||||
suite_size = sizeof(suite_set.start);
|
||||
|
||||
/* Allocate memory for array of all kunit suites */
|
||||
total_suite_start = kmalloc_array(init_num_suites + num_suites, suite_size, GFP_KERNEL);
|
||||
if (!total_suite_start)
|
||||
return total_suite_set;
|
||||
|
||||
/* Append and mark init suites and then append all other kunit suites */
|
||||
memcpy(total_suite_start, init_suite_set.start, init_num_suites * suite_size);
|
||||
for (i = 0; i < init_num_suites; i++)
|
||||
total_suite_start[i]->is_init = true;
|
||||
|
||||
memcpy(total_suite_start + init_num_suites, suite_set.start, num_suites * suite_size);
|
||||
|
||||
/* Set kunit suite set start and end */
|
||||
total_suite_set.start = total_suite_start;
|
||||
total_suite_set.end = total_suite_start + (init_num_suites + num_suites);
|
||||
|
||||
return total_suite_set;
|
||||
}
|
||||
|
||||
#if IS_BUILTIN(CONFIG_KUNIT)
|
||||
|
||||
static char *kunit_shutdown;
|
||||
@@ -313,21 +346,41 @@ static void kunit_handle_shutdown(void)
|
||||
|
||||
int kunit_run_all_tests(void)
|
||||
{
|
||||
struct kunit_suite_set suite_set = {
|
||||
struct kunit_suite_set suite_set = {NULL, NULL};
|
||||
struct kunit_suite_set filtered_suite_set = {NULL, NULL};
|
||||
struct kunit_suite_set init_suite_set = {
|
||||
__kunit_init_suites_start, __kunit_init_suites_end,
|
||||
};
|
||||
struct kunit_suite_set normal_suite_set = {
|
||||
__kunit_suites_start, __kunit_suites_end,
|
||||
};
|
||||
size_t init_num_suites = init_suite_set.end - init_suite_set.start;
|
||||
int err = 0;
|
||||
|
||||
if (init_num_suites > 0) {
|
||||
suite_set = kunit_merge_suite_sets(init_suite_set, normal_suite_set);
|
||||
if (!suite_set.start)
|
||||
goto out;
|
||||
} else
|
||||
suite_set = normal_suite_set;
|
||||
|
||||
if (!kunit_enabled()) {
|
||||
pr_info("kunit: disabled\n");
|
||||
goto out;
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
if (filter_glob_param || filter_param) {
|
||||
suite_set = kunit_filter_suites(&suite_set, filter_glob_param,
|
||||
filtered_suite_set = kunit_filter_suites(&suite_set, filter_glob_param,
|
||||
filter_param, filter_action_param, &err);
|
||||
|
||||
/* Free original suite set before using filtered suite set */
|
||||
if (init_num_suites > 0)
|
||||
kfree(suite_set.start);
|
||||
suite_set = filtered_suite_set;
|
||||
|
||||
if (err) {
|
||||
pr_err("kunit executor: error filtering suites: %d\n", err);
|
||||
goto out;
|
||||
goto free_out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,9 +393,12 @@ int kunit_run_all_tests(void)
|
||||
else
|
||||
pr_err("kunit executor: unknown action '%s'\n", action_param);
|
||||
|
||||
if (filter_glob_param || filter_param) { /* a copy was made of each suite */
|
||||
free_out:
|
||||
if (filter_glob_param || filter_param)
|
||||
kunit_free_suite_set(suite_set);
|
||||
}
|
||||
else if (init_num_suites > 0)
|
||||
/* Don't use kunit_free_suite_set because suites aren't individually allocated */
|
||||
kfree(suite_set.start);
|
||||
|
||||
out:
|
||||
kunit_handle_shutdown();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user