Skip to content

Commit 81c7908

Browse files
mykola-lysenkoKernel Patches Daemon
authored and
Kernel Patches Daemon
committed
selftests/bpf: Improve by-name subtest selection logic in prog_tests
Improve subtest selection logic when using -t/-a/-d parameters. In particular, more than one subtest can be specified or a combination of tests / subtests. -a send_signal -d send_signal/send_signal_nmi* - runs send_signal test without nmi tests -a send_signal/send_signal_nmi*,find_vma - runs two send_signal subtests and find_vma test -a 'send_signal*' -a find_vma -d send_signal/send_signal_nmi* - runs 2 send_signal test and find_vma test. Disables two send_signal nmi subtests -t send_signal -t find_vma - runs two *send_signal* tests and one *find_vma* test This will allow us to have granular control over which subtests to disable in the CI system instead of disabling whole tests. Also, add new selftest to avoid possible regression when changing prog_test test name selection logic. Signed-off-by: Mykola Lysenko <[email protected]>
1 parent 7312c53 commit 81c7908

File tree

5 files changed

+275
-87
lines changed

5 files changed

+275
-87
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2+
3+
#include "test_progs.h"
4+
#include "testing_helpers.h"
5+
6+
static void init_test_filter_set(struct test_filter_set *set)
7+
{
8+
set->cnt = 0;
9+
set->tests = NULL;
10+
}
11+
12+
static void free_test_filter_set(struct test_filter_set *set)
13+
{
14+
int i, j;
15+
16+
for (i = 0; i < set->cnt; i++) {
17+
for (j = 0; j < set->tests[i].subtest_cnt; j++)
18+
free((void *)set->tests[i].subtests[j]);
19+
free(set->tests[i].subtests);
20+
free(set->tests[i].name);
21+
}
22+
23+
free(set->tests);
24+
init_test_filter_set(set);
25+
}
26+
27+
static void test_parse_test_list(void)
28+
{
29+
struct test_filter_set set;
30+
31+
init_test_filter_set(&set);
32+
33+
ASSERT_OK(parse_test_list("arg_parsing", &set, true), "parsing");
34+
if (!ASSERT_EQ(set.cnt, 1, "test filters count"))
35+
goto error;
36+
if (!ASSERT_OK_PTR(set.tests, "test filters initialized"))
37+
goto error;
38+
ASSERT_EQ(set.tests[0].subtest_cnt, 0, "subtest filters count");
39+
ASSERT_OK(strcmp("arg_parsing", set.tests[0].name), "subtest name");
40+
free_test_filter_set(&set);
41+
42+
ASSERT_OK(parse_test_list("arg_parsing,bpf_cookie", &set, true),
43+
"parsing");
44+
if (!ASSERT_EQ(set.cnt, 2, "count of test filters"))
45+
goto error;
46+
if (!ASSERT_OK_PTR(set.tests, "test filters initialized"))
47+
goto error;
48+
ASSERT_EQ(set.tests[0].subtest_cnt, 0, "subtest filters count");
49+
ASSERT_EQ(set.tests[1].subtest_cnt, 0, "subtest filters count");
50+
ASSERT_OK(strcmp("arg_parsing", set.tests[0].name), "test name");
51+
ASSERT_OK(strcmp("bpf_cookie", set.tests[1].name), "test name");
52+
free_test_filter_set(&set);
53+
54+
ASSERT_OK(parse_test_list("arg_parsing/arg_parsing,bpf_cookie",
55+
&set,
56+
true),
57+
"parsing");
58+
if (!ASSERT_EQ(set.cnt, 2, "count of test filters"))
59+
goto error;
60+
if (!ASSERT_OK_PTR(set.tests, "test filters initialized"))
61+
goto error;
62+
if (!ASSERT_EQ(set.tests[0].subtest_cnt, 1, "subtest filters count"))
63+
goto error;
64+
if (!ASSERT_EQ(set.tests[1].subtest_cnt, 0, "subtest filters count"))
65+
goto error;
66+
ASSERT_OK(strcmp("arg_parsing", set.tests[0].name), "test name");
67+
ASSERT_OK(strcmp("arg_parsing", set.tests[0].subtests[0]),
68+
"subtest name");
69+
ASSERT_OK(strcmp("bpf_cookie", set.tests[1].name), "test name");
70+
free_test_filter_set(&set);
71+
72+
ASSERT_OK(parse_test_list("arg_parsing/arg_parsing", &set, true),
73+
"parsing");
74+
ASSERT_OK(parse_test_list("bpf_cookie", &set, true), "parsing");
75+
ASSERT_OK(parse_test_list("send_signal", &set, true), "parsing");
76+
if (!ASSERT_EQ(set.cnt, 3, "count of test filters"))
77+
goto error;
78+
if (!ASSERT_OK_PTR(set.tests, "test filters initialized"))
79+
goto error;
80+
if (!ASSERT_EQ(set.tests[0].subtest_cnt, 1, "subtest filters count"))
81+
goto error;
82+
if (!ASSERT_EQ(set.tests[1].subtest_cnt, 0, "subtest filters count"))
83+
goto error;
84+
if (!ASSERT_EQ(set.tests[2].subtest_cnt, 0, "subtest filters count"))
85+
goto error;
86+
ASSERT_OK(strcmp("arg_parsing", set.tests[0].name), "test name");
87+
ASSERT_OK(strcmp("arg_parsing", set.tests[0].subtests[0]),
88+
"subtest name");
89+
ASSERT_OK(strcmp("bpf_cookie", set.tests[1].name), "test name");
90+
ASSERT_OK(strcmp("send_signal", set.tests[2].name), "test name");
91+
error:
92+
free_test_filter_set(&set);
93+
}
94+
95+
void test_arg_parsing(void)
96+
{
97+
if (test__start_subtest("test_parse_test_list"))
98+
test_parse_test_list();
99+
}

tools/testing/selftests/bpf/test_progs.c

Lines changed: 74 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
#define _GNU_SOURCE
55
#include "test_progs.h"
6+
#include "testing_helpers.h"
67
#include "cgroup_helpers.h"
78
#include <argp.h>
89
#include <pthread.h>
@@ -84,12 +85,13 @@ static bool should_run(struct test_selector *sel, int num, const char *name)
8485
int i;
8586

8687
for (i = 0; i < sel->blacklist.cnt; i++) {
87-
if (glob_match(name, sel->blacklist.strs[i]))
88+
if (glob_match(name, sel->blacklist.tests[i].name) &&
89+
!sel->blacklist.tests[i].subtest_cnt)
8890
return false;
8991
}
9092

9193
for (i = 0; i < sel->whitelist.cnt; i++) {
92-
if (glob_match(name, sel->whitelist.strs[i]))
94+
if (glob_match(name, sel->whitelist.tests[i].name))
9395
return true;
9496
}
9597

@@ -99,6 +101,46 @@ static bool should_run(struct test_selector *sel, int num, const char *name)
99101
return num < sel->num_set_len && sel->num_set[num];
100102
}
101103

104+
static bool should_run_subtest(struct test_selector *sel,
105+
struct test_selector *subtest_sel,
106+
int subtest_num,
107+
const char *test_name,
108+
const char *subtest_name)
109+
{
110+
int i, j;
111+
112+
for (i = 0; i < sel->blacklist.cnt; i++) {
113+
if (glob_match(test_name, sel->blacklist.tests[i].name)) {
114+
if (!sel->blacklist.tests[i].subtest_cnt)
115+
return false;
116+
117+
for (j = 0; j < sel->blacklist.tests[i].subtest_cnt; j++) {
118+
if (glob_match(subtest_name,
119+
sel->blacklist.tests[i].subtests[j]))
120+
return false;
121+
}
122+
}
123+
}
124+
125+
for (i = 0; i < sel->whitelist.cnt; i++) {
126+
if (glob_match(test_name, sel->whitelist.tests[i].name)) {
127+
if (!sel->whitelist.tests[i].subtest_cnt)
128+
return true;
129+
130+
for (j = 0; j < sel->whitelist.tests[i].subtest_cnt; j++) {
131+
if (glob_match(subtest_name,
132+
sel->whitelist.tests[i].subtests[j]))
133+
return true;
134+
}
135+
}
136+
}
137+
138+
if (!sel->whitelist.cnt && !subtest_sel->num_set)
139+
return true;
140+
141+
return subtest_num < subtest_sel->num_set_len && subtest_sel->num_set[subtest_num];
142+
}
143+
102144
static void dump_test_log(const struct prog_test_def *test, bool failed)
103145
{
104146
if (stdout == env.stdout)
@@ -196,7 +238,7 @@ void test__end_subtest(void)
196238
test->subtest_name = NULL;
197239
}
198240

199-
bool test__start_subtest(const char *name)
241+
bool test__start_subtest(const char *subtest_name)
200242
{
201243
struct prog_test_def *test = env.test;
202244

@@ -205,17 +247,21 @@ bool test__start_subtest(const char *name)
205247

206248
test->subtest_num++;
207249

208-
if (!name || !name[0]) {
250+
if (!subtest_name || !subtest_name[0]) {
209251
fprintf(env.stderr,
210252
"Subtest #%d didn't provide sub-test name!\n",
211253
test->subtest_num);
212254
return false;
213255
}
214256

215-
if (!should_run(&env.subtest_selector, test->subtest_num, name))
257+
if (!should_run_subtest(&env.test_selector,
258+
&env.subtest_selector,
259+
test->subtest_num,
260+
test->test_name,
261+
subtest_name))
216262
return false;
217263

218-
test->subtest_name = strdup(name);
264+
test->subtest_name = strdup(subtest_name);
219265
if (!test->subtest_name) {
220266
fprintf(env.stderr,
221267
"Subtest #%d: failed to copy subtest name!\n",
@@ -527,63 +573,29 @@ static int libbpf_print_fn(enum libbpf_print_level level,
527573
return 0;
528574
}
529575

530-
static void free_str_set(const struct str_set *set)
576+
static void free_test_filter_set(const struct test_filter_set *set)
531577
{
532-
int i;
578+
int i, j;
533579

534580
if (!set)
535581
return;
536582

537-
for (i = 0; i < set->cnt; i++)
538-
free((void *)set->strs[i]);
539-
free(set->strs);
540-
}
541-
542-
static int parse_str_list(const char *s, struct str_set *set, bool is_glob_pattern)
543-
{
544-
char *input, *state = NULL, *next, **tmp, **strs = NULL;
545-
int i, cnt = 0;
546-
547-
input = strdup(s);
548-
if (!input)
549-
return -ENOMEM;
550-
551-
while ((next = strtok_r(state ? NULL : input, ",", &state))) {
552-
tmp = realloc(strs, sizeof(*strs) * (cnt + 1));
553-
if (!tmp)
554-
goto err;
555-
strs = tmp;
556-
557-
if (is_glob_pattern) {
558-
strs[cnt] = strdup(next);
559-
if (!strs[cnt])
560-
goto err;
561-
} else {
562-
strs[cnt] = malloc(strlen(next) + 2 + 1);
563-
if (!strs[cnt])
564-
goto err;
565-
sprintf(strs[cnt], "*%s*", next);
566-
}
583+
for (i = 0; i < set->cnt; i++) {
584+
free((void *)set->tests[i].name);
585+
for (j = 0; j < set->tests[i].subtest_cnt; j++)
586+
free((void *)set->tests[i].subtests[j]);
567587

568-
cnt++;
588+
free((void *)set->tests[i].subtests);
569589
}
570590

571-
tmp = realloc(set->strs, sizeof(*strs) * (cnt + set->cnt));
572-
if (!tmp)
573-
goto err;
574-
memcpy(tmp + set->cnt, strs, sizeof(*strs) * cnt);
575-
set->strs = (const char **)tmp;
576-
set->cnt += cnt;
591+
free((void *)set->tests);
592+
}
577593

578-
free(input);
579-
free(strs);
580-
return 0;
581-
err:
582-
for (i = 0; i < cnt; i++)
583-
free(strs[i]);
584-
free(strs);
585-
free(input);
586-
return -ENOMEM;
594+
static void free_test_selector(struct test_selector *test_selector)
595+
{
596+
free_test_filter_set(&test_selector->blacklist);
597+
free_test_filter_set(&test_selector->whitelist);
598+
free(test_selector->num_set);
587599
}
588600

589601
extern int extra_prog_load_log_flags;
@@ -615,33 +627,17 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
615627
}
616628
case ARG_TEST_NAME_GLOB_ALLOWLIST:
617629
case ARG_TEST_NAME: {
618-
char *subtest_str = strchr(arg, '/');
619-
620-
if (subtest_str) {
621-
*subtest_str = '\0';
622-
if (parse_str_list(subtest_str + 1,
623-
&env->subtest_selector.whitelist,
624-
key == ARG_TEST_NAME_GLOB_ALLOWLIST))
625-
return -ENOMEM;
626-
}
627-
if (parse_str_list(arg, &env->test_selector.whitelist,
628-
key == ARG_TEST_NAME_GLOB_ALLOWLIST))
630+
if (parse_test_list(arg,
631+
&env->test_selector.whitelist,
632+
key == ARG_TEST_NAME_GLOB_ALLOWLIST))
629633
return -ENOMEM;
630634
break;
631635
}
632636
case ARG_TEST_NAME_GLOB_DENYLIST:
633637
case ARG_TEST_NAME_BLACKLIST: {
634-
char *subtest_str = strchr(arg, '/');
635-
636-
if (subtest_str) {
637-
*subtest_str = '\0';
638-
if (parse_str_list(subtest_str + 1,
639-
&env->subtest_selector.blacklist,
640-
key == ARG_TEST_NAME_GLOB_DENYLIST))
641-
return -ENOMEM;
642-
}
643-
if (parse_str_list(arg, &env->test_selector.blacklist,
644-
key == ARG_TEST_NAME_GLOB_DENYLIST))
638+
if (parse_test_list(arg,
639+
&env->test_selector.blacklist,
640+
key == ARG_TEST_NAME_GLOB_DENYLIST))
645641
return -ENOMEM;
646642
break;
647643
}
@@ -1493,12 +1489,8 @@ int main(int argc, char **argv)
14931489
out:
14941490
if (!env.list_test_names && env.has_testmod)
14951491
unload_bpf_testmod();
1496-
free_str_set(&env.test_selector.blacklist);
1497-
free_str_set(&env.test_selector.whitelist);
1498-
free(env.test_selector.num_set);
1499-
free_str_set(&env.subtest_selector.blacklist);
1500-
free_str_set(&env.subtest_selector.whitelist);
1501-
free(env.subtest_selector.num_set);
1492+
1493+
free_test_selector(&env.test_selector);
15021494

15031495
if (env.succ_cnt + env.fail_cnt + env.skip_cnt == 0)
15041496
return EXIT_NO_TEST;

tools/testing/selftests/bpf/test_progs.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ typedef __u16 __sum16;
3737
#include <bpf/bpf_endian.h>
3838
#include "trace_helpers.h"
3939
#include "testing_helpers.h"
40-
#include "flow_dissector_load.h"
4140

4241
enum verbosity {
4342
VERBOSE_NONE,
@@ -46,14 +45,20 @@ enum verbosity {
4645
VERBOSE_SUPER,
4746
};
4847

49-
struct str_set {
50-
const char **strs;
48+
struct test_filter {
49+
char *name;
50+
char **subtests;
51+
int subtest_cnt;
52+
};
53+
54+
struct test_filter_set {
55+
struct test_filter *tests;
5156
int cnt;
5257
};
5358

5459
struct test_selector {
55-
struct str_set whitelist;
56-
struct str_set blacklist;
60+
struct test_filter_set whitelist;
61+
struct test_filter_set blacklist;
5762
bool *num_set;
5863
int num_set_len;
5964
};

0 commit comments

Comments
 (0)