Skip to content

Commit

Permalink
kunit: flatten kunit_suite*** to kunit_suite** in .kunit_test_suites
Browse files Browse the repository at this point in the history
We currently store kunit suites in the .kunit_test_suites ELF section as
a `struct kunit_suite***` (modulo some `const`s).
For every test file, we store a struct kunit_suite** NULL-terminated array.

This adds quite a bit of complexity to the test filtering code in the
executor.

Instead, let's just make the .kunit_test_suites section contain a single
giant array of struct kunit_suite pointers, which can then be directly
manipulated. This array is not NULL-terminated, and so none of the test
filtering code needs to NULL-terminate anything.

Tested-by: Maíra Canal <[email protected]>
Reviewed-by: Brendan Higgins <[email protected]>
Signed-off-by: Daniel Latypov <[email protected]>
Co-developed-by: David Gow <[email protected]>
Signed-off-by: David Gow <[email protected]>
Signed-off-by: Shuah Khan <[email protected]>
  • Loading branch information
dlatypov authored and shuahkh committed Jul 11, 2022
1 parent 3d6e446 commit e5857d3
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 210 deletions.
13 changes: 6 additions & 7 deletions include/kunit/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ size_t kunit_suite_num_test_cases(struct kunit_suite *suite);
unsigned int kunit_test_case_num(struct kunit_suite *suite,
struct kunit_case *test_case);

int __kunit_test_suites_init(struct kunit_suite * const * const suites);
int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites);

void __kunit_test_suites_exit(struct kunit_suite **suites);
void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites);

#if IS_BUILTIN(CONFIG_KUNIT)
int kunit_run_all_tests(void);
Expand All @@ -250,11 +250,11 @@ static inline int kunit_run_all_tests(void)
}
#endif /* IS_BUILTIN(CONFIG_KUNIT) */

#define __kunit_test_suites(unique_array, unique_suites, ...) \
#define __kunit_test_suites(unique_array, ...) \
MODULE_INFO(test, "Y"); \
static struct kunit_suite *unique_array[] = { __VA_ARGS__, NULL }; \
static struct kunit_suite **unique_suites \
__used __section(".kunit_test_suites") = unique_array
static struct kunit_suite *unique_array[] \
__aligned(sizeof(struct kunit_suite *)) \
__used __section(".kunit_test_suites") = { __VA_ARGS__ }

/**
* kunit_test_suites() - used to register one or more &struct kunit_suite
Expand All @@ -272,7 +272,6 @@ static inline int kunit_run_all_tests(void)
*/
#define kunit_test_suites(__suites...) \
__kunit_test_suites(__UNIQUE_ID(array), \
__UNIQUE_ID(suites), \
##__suites)

#define kunit_test_suite(suite) kunit_test_suites(&suite)
Expand Down
2 changes: 1 addition & 1 deletion include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ struct module {
#endif
#if IS_ENABLED(CONFIG_KUNIT)
int num_kunit_suites;
struct kunit_suite ***kunit_suites;
struct kunit_suite **kunit_suites;
#endif


Expand Down
115 changes: 28 additions & 87 deletions lib/kunit/executor.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
* These symbols point to the .kunit_test_suites section and are defined in
* include/asm-generic/vmlinux.lds.h, and consequently must be extern.
*/
extern struct kunit_suite * const * const __kunit_suites_start[];
extern struct kunit_suite * const * const __kunit_suites_end[];
extern struct kunit_suite * const __kunit_suites_start[];
extern struct kunit_suite * const __kunit_suites_end[];

#if IS_BUILTIN(CONFIG_KUNIT)

Expand Down Expand Up @@ -90,62 +90,18 @@ kunit_filter_tests(const struct kunit_suite *const suite, const char *test_glob)
static char *kunit_shutdown;
core_param(kunit_shutdown, kunit_shutdown, charp, 0644);

static struct kunit_suite * const *
kunit_filter_subsuite(struct kunit_suite * const * const subsuite,
struct kunit_test_filter *filter)
{
int i, n = 0;
struct kunit_suite **filtered, *filtered_suite;

n = 0;
for (i = 0; subsuite[i]; ++i) {
if (glob_match(filter->suite_glob, subsuite[i]->name))
++n;
}

if (n == 0)
return NULL;

filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL);
if (!filtered)
return ERR_PTR(-ENOMEM);

n = 0;
for (i = 0; subsuite[i] != NULL; ++i) {
if (!glob_match(filter->suite_glob, subsuite[i]->name))
continue;
filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob);
if (IS_ERR(filtered_suite))
return ERR_CAST(filtered_suite);
else if (filtered_suite)
filtered[n++] = filtered_suite;
}
filtered[n] = NULL;

return filtered;
}

/* Stores an array of suites, end points one past the end */
struct suite_set {
struct kunit_suite * const * const *start;
struct kunit_suite * const * const *end;
struct kunit_suite * const *start;
struct kunit_suite * const *end;
};

static void kunit_free_subsuite(struct kunit_suite * const *subsuite)
{
unsigned int i;

for (i = 0; subsuite[i]; i++)
kfree(subsuite[i]);

kfree(subsuite);
}

static void kunit_free_suite_set(struct suite_set suite_set)
{
struct kunit_suite * const * const *suites;
struct kunit_suite * const *suites;

for (suites = suite_set.start; suites < suite_set.end; suites++)
kunit_free_subsuite(*suites);
kfree(*suites);
kfree(suite_set.start);
}

Expand All @@ -154,7 +110,7 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
int *err)
{
int i;
struct kunit_suite * const **copy, * const *filtered_subsuite;
struct kunit_suite **copy, *filtered_suite;
struct suite_set filtered;
struct kunit_test_filter filter;

Expand All @@ -169,14 +125,19 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,

kunit_parse_filter_glob(&filter, filter_glob);

for (i = 0; i < max; ++i) {
filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter);
if (IS_ERR(filtered_subsuite)) {
*err = PTR_ERR(filtered_subsuite);
for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
if (!glob_match(filter.suite_glob, suite_set->start[i]->name))
continue;

filtered_suite = kunit_filter_tests(suite_set->start[i], filter.test_glob);
if (IS_ERR(filtered_suite)) {
*err = PTR_ERR(filtered_suite);
return filtered;
}
if (filtered_subsuite)
*copy++ = filtered_subsuite;
if (!filtered_suite)
continue;

*copy++ = filtered_suite;
}
filtered.end = copy;

Expand All @@ -199,52 +160,33 @@ static void kunit_handle_shutdown(void)

}

static void kunit_print_tap_header(struct suite_set *suite_set)
{
struct kunit_suite * const * const *suites, * const *subsuite;
int num_of_suites = 0;

for (suites = suite_set->start; suites < suite_set->end; suites++)
for (subsuite = *suites; *subsuite != NULL; subsuite++)
num_of_suites++;

pr_info("TAP version 14\n");
pr_info("1..%d\n", num_of_suites);
}

static void kunit_exec_run_tests(struct suite_set *suite_set)
{
struct kunit_suite * const * const *suites;
size_t num_suites = suite_set->end - suite_set->start;

kunit_print_tap_header(suite_set);
pr_info("TAP version 14\n");
pr_info("1..%zu\n", num_suites);

for (suites = suite_set->start; suites < suite_set->end; suites++)
__kunit_test_suites_init(*suites);
__kunit_test_suites_init(suite_set->start, num_suites);
}

static void kunit_exec_list_tests(struct suite_set *suite_set)
{
unsigned int i;
struct kunit_suite * const * const *suites;
struct kunit_suite * const *suites;
struct kunit_case *test_case;

/* Hack: print a tap header so kunit.py can find the start of KUnit output. */
pr_info("TAP version 14\n");

for (suites = suite_set->start; suites < suite_set->end; suites++)
for (i = 0; (*suites)[i] != NULL; i++) {
kunit_suite_for_each_test_case((*suites)[i], test_case) {
pr_info("%s.%s\n", (*suites)[i]->name, test_case->name);
}
kunit_suite_for_each_test_case((*suites), test_case) {
pr_info("%s.%s\n", (*suites)->name, test_case->name);
}
}

int kunit_run_all_tests(void)
{
struct suite_set suite_set = {
.start = __kunit_suites_start,
.end = __kunit_suites_end,
};
struct suite_set suite_set = {__kunit_suites_start, __kunit_suites_end};
int err = 0;

if (filter_glob_param) {
Expand All @@ -262,11 +204,10 @@ int kunit_run_all_tests(void)
else
pr_err("kunit executor: unknown action '%s'\n", action_param);

if (filter_glob_param) { /* a copy was made of each array */
if (filter_glob_param) { /* a copy was made of each suite */
kunit_free_suite_set(suite_set);
}


out:
kunit_handle_shutdown();
return err;
Expand Down
Loading

0 comments on commit e5857d3

Please sign in to comment.