summaryrefslogtreecommitdiff
path: root/lib/kunit/executor.c
diff options
context:
space:
mode:
authorRae Moar <rmoar@google.com>2023-07-25 21:25:15 +0000
committerShuah Khan <skhan@linuxfoundation.org>2023-07-26 13:29:15 -0600
commit529534e8cba3e60f843a682e2a3149612b30d608 (patch)
treeca29d679b1bf5bb328bd22b7e747aa3389413991 /lib/kunit/executor.c
parenta00a72709175a4d53096301a8792b8171d1223e5 (diff)
kunit: Add ability to filter attributes
Add filtering of test attributes. Users can filter tests using the module_param called "filter". Filters are imputed in the format: <attribute_name><operation><value> Example: kunit.filter="speed>slow" Operations include: >, <, >=, <=, !=, and =. These operations will act the same for attributes of the same type but may not between types. Note multiple filters can be inputted by separating them with a comma. Example: kunit.filter="speed=slow, module!=example" Since both suites and test cases can have attributes, there may be conflicts. The process of filtering follows these rules: - Filtering always operates at a per-test level. - If a test has an attribute set, then the test's value is filtered on. - Otherwise, the value falls back to the suite's value. - If neither are set, the attribute has a global "default" value, which is used. Filtered tests will not be run or show in output. The tests can instead be skipped using the configurable option "kunit.filter_action=skip". Note the default settings for running tests remains unfiltered. Finally, add "filter" methods for the speed and module attributes to parse and compare attribute values. Note this filtering functionality will be added to kunit.py in the next patch. Reviewed-by: David Gow <davidgow@google.com> Signed-off-by: Rae Moar <rmoar@google.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Diffstat (limited to 'lib/kunit/executor.c')
-rw-r--r--lib/kunit/executor.c93
1 files changed, 74 insertions, 19 deletions
diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 12e38a48a5cc..483f7b7873a7 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -17,6 +17,8 @@ extern struct kunit_suite * const __kunit_suites_end[];
static char *filter_glob_param;
static char *action_param;
+static char *filter_param;
+static char *filter_action_param;
module_param_named(filter_glob, filter_glob_param, charp, 0);
MODULE_PARM_DESC(filter_glob,
@@ -27,15 +29,23 @@ MODULE_PARM_DESC(action,
"<none>: run the tests like normal\n"
"'list' to list test names instead of running them.\n"
"'list_attr' to list test names and attributes instead of running them.\n");
+module_param_named(filter, filter_param, charp, 0);
+MODULE_PARM_DESC(filter,
+ "Filter which KUnit test suites/tests run at boot-time using attributes, e.g. speed>slow");
+module_param_named(filter_action, filter_action_param, charp, 0);
+MODULE_PARM_DESC(filter_action,
+ "Changes behavior of filtered tests using attributes, valid values are:\n"
+ "<none>: do not run filtered tests as normal\n"
+ "'skip': skip all filtered tests instead so tests will appear in output\n");
/* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */
-struct kunit_test_filter {
+struct kunit_glob_filter {
char *suite_glob;
char *test_glob;
};
/* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */
-static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,
+static void kunit_parse_glob_filter(struct kunit_glob_filter *parsed,
const char *filter_glob)
{
const int len = strlen(filter_glob);
@@ -57,7 +67,7 @@ static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,
/* Create a copy of suite with only tests that match test_glob. */
static struct kunit_suite *
-kunit_filter_tests(const struct kunit_suite *const suite, const char *test_glob)
+kunit_filter_glob_tests(const struct kunit_suite *const suite, const char *test_glob)
{
int n = 0;
struct kunit_case *filtered, *test_case;
@@ -111,12 +121,15 @@ static void kunit_free_suite_set(struct suite_set suite_set)
static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
const char *filter_glob,
+ char *filters,
+ char *filter_action,
int *err)
{
- int i;
- struct kunit_suite **copy, *filtered_suite;
+ int i, j, k, filter_count;
+ struct kunit_suite **copy, *filtered_suite, *new_filtered_suite;
struct suite_set filtered;
- struct kunit_test_filter filter;
+ struct kunit_glob_filter parsed_glob;
+ struct kunit_attr_filter *parsed_filters;
const size_t max = suite_set->end - suite_set->start;
@@ -127,17 +140,52 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
return filtered;
}
- kunit_parse_filter_glob(&filter, filter_glob);
+ if (filter_glob)
+ kunit_parse_glob_filter(&parsed_glob, filter_glob);
- 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);
+ /* Parse attribute filters */
+ if (filters) {
+ filter_count = kunit_get_filter_count(filters);
+ parsed_filters = kcalloc(filter_count + 1, sizeof(*parsed_filters), GFP_KERNEL);
+ for (j = 0; j < filter_count; j++)
+ parsed_filters[j] = kunit_next_attr_filter(&filters, err);
+ if (*err)
return filtered;
+ }
+
+ for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
+ filtered_suite = suite_set->start[i];
+ if (filter_glob) {
+ if (!glob_match(parsed_glob.suite_glob, filtered_suite->name))
+ continue;
+ filtered_suite = kunit_filter_glob_tests(filtered_suite,
+ parsed_glob.test_glob);
+ if (IS_ERR(filtered_suite)) {
+ *err = PTR_ERR(filtered_suite);
+ return filtered;
+ }
}
+ if (filter_count) {
+ for (k = 0; k < filter_count; k++) {
+ new_filtered_suite = kunit_filter_attr_tests(filtered_suite,
+ parsed_filters[k], filter_action, err);
+
+ /* Free previous copy of suite */
+ if (k > 0 || filter_glob)
+ kfree(filtered_suite);
+ filtered_suite = new_filtered_suite;
+
+ if (*err)
+ return filtered;
+ if (IS_ERR(filtered_suite)) {
+ *err = PTR_ERR(filtered_suite);
+ return filtered;
+ }
+ if (!filtered_suite)
+ break;
+ }
+ }
+
if (!filtered_suite)
continue;
@@ -145,8 +193,14 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
}
filtered.end = copy;
- kfree(filter.suite_glob);
- kfree(filter.test_glob);
+ if (filter_glob) {
+ kfree(parsed_glob.suite_glob);
+ kfree(parsed_glob.test_glob);
+ }
+
+ if (filter_count)
+ kfree(parsed_filters);
+
return filtered;
}
@@ -206,8 +260,9 @@ int kunit_run_all_tests(void)
goto out;
}
- if (filter_glob_param) {
- suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err);
+ if (filter_glob_param || filter_param) {
+ suite_set = kunit_filter_suites(&suite_set, filter_glob_param,
+ filter_param, filter_action_param, &err);
if (err) {
pr_err("kunit executor: error filtering suites: %d\n", err);
goto out;
@@ -223,7 +278,7 @@ 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 suite */
+ if (filter_glob_param || filter_param) { /* a copy was made of each suite */
kunit_free_suite_set(suite_set);
}