Skip to content

Commit 64276f0

Browse files
sveissanakryiko
authored andcommitted
selftests/bpf: Test_progs can read test lists from file
Improve test selection logic when using -a/-b/-d/-t options. The list of tests to include or exclude can now be read from a file, specified as @<filename>. The file contains one name (or wildcard pattern) per line, and comments beginning with # are ignored. These options can be passed multiple times to read more than one file. Signed-off-by: Stephen Veiss <sveiss@meta.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/bpf/20230427225333.3506052-3-sveiss@meta.com
1 parent 0a5c0de commit 64276f0

File tree

4 files changed

+132
-10
lines changed

4 files changed

+132
-10
lines changed

tools/testing/selftests/bpf/prog_tests/arg_parsing.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,63 @@ static void test_parse_test_list(void)
113113
free_test_filter_set(&set);
114114
}
115115

116+
static void test_parse_test_list_file(void)
117+
{
118+
struct test_filter_set set;
119+
char tmpfile[80];
120+
FILE *fp;
121+
int fd;
122+
123+
snprintf(tmpfile, sizeof(tmpfile), "/tmp/bpf_arg_parsing_test.XXXXXX");
124+
fd = mkstemp(tmpfile);
125+
if (!ASSERT_GE(fd, 0, "create tmp"))
126+
return;
127+
128+
fp = fdopen(fd, "w");
129+
if (!ASSERT_NEQ(fp, NULL, "fdopen tmp")) {
130+
close(fd);
131+
goto out_remove;
132+
}
133+
134+
fprintf(fp, "# comment\n");
135+
fprintf(fp, " test_with_spaces \n");
136+
fprintf(fp, "testA/subtest # comment\n");
137+
fprintf(fp, "testB#comment with no space\n");
138+
fprintf(fp, "testB # duplicate\n");
139+
fprintf(fp, "testA/subtest # subtest duplicate\n");
140+
fprintf(fp, "testA/subtest2\n");
141+
fprintf(fp, "testC_no_eof_newline");
142+
fflush(fp);
143+
144+
if (!ASSERT_OK(ferror(fp), "prepare tmp"))
145+
goto out_fclose;
146+
147+
init_test_filter_set(&set);
148+
149+
ASSERT_OK(parse_test_list_file(tmpfile, &set, true), "parse file");
150+
151+
ASSERT_EQ(set.cnt, 4, "test count");
152+
ASSERT_OK(strcmp("test_with_spaces", set.tests[0].name), "test 0 name");
153+
ASSERT_EQ(set.tests[0].subtest_cnt, 0, "test 0 subtest count");
154+
ASSERT_OK(strcmp("testA", set.tests[1].name), "test 1 name");
155+
ASSERT_EQ(set.tests[1].subtest_cnt, 2, "test 1 subtest count");
156+
ASSERT_OK(strcmp("subtest", set.tests[1].subtests[0]), "test 1 subtest 0");
157+
ASSERT_OK(strcmp("subtest2", set.tests[1].subtests[1]), "test 1 subtest 1");
158+
ASSERT_OK(strcmp("testB", set.tests[2].name), "test 2 name");
159+
ASSERT_OK(strcmp("testC_no_eof_newline", set.tests[3].name), "test 3 name");
160+
161+
free_test_filter_set(&set);
162+
163+
out_fclose:
164+
fclose(fp);
165+
out_remove:
166+
remove(tmpfile);
167+
}
168+
116169
void test_arg_parsing(void)
117170
{
118171
if (test__start_subtest("test_parse_test_list"))
119172
test_parse_test_list();
173+
if (test__start_subtest("test_parse_test_list_file"))
174+
test_parse_test_list_file();
120175
}

tools/testing/selftests/bpf/test_progs.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,13 @@ static struct test_state test_states[ARRAY_SIZE(prog_test_defs)];
714714

715715
const char *argp_program_version = "test_progs 0.1";
716716
const char *argp_program_bug_address = "<bpf@vger.kernel.org>";
717-
static const char argp_program_doc[] = "BPF selftests test runner";
717+
static const char argp_program_doc[] =
718+
"BPF selftests test runner\v"
719+
"Options accepting the NAMES parameter take either a comma-separated list\n"
720+
"of test names, or a filename prefixed with @. The file contains one name\n"
721+
"(or wildcard pattern) per line, and comments beginning with # are ignored.\n"
722+
"\n"
723+
"These options can be passed repeatedly to read multiple files.\n";
718724

719725
enum ARG_KEYS {
720726
ARG_TEST_NUM = 'n',
@@ -797,6 +803,7 @@ extern int extra_prog_load_log_flags;
797803
static error_t parse_arg(int key, char *arg, struct argp_state *state)
798804
{
799805
struct test_env *env = state->input;
806+
int err = 0;
800807

801808
switch (key) {
802809
case ARG_TEST_NUM: {
@@ -821,18 +828,28 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
821828
}
822829
case ARG_TEST_NAME_GLOB_ALLOWLIST:
823830
case ARG_TEST_NAME: {
824-
if (parse_test_list(arg,
825-
&env->test_selector.whitelist,
826-
key == ARG_TEST_NAME_GLOB_ALLOWLIST))
827-
return -ENOMEM;
831+
if (arg[0] == '@')
832+
err = parse_test_list_file(arg + 1,
833+
&env->test_selector.whitelist,
834+
key == ARG_TEST_NAME_GLOB_ALLOWLIST);
835+
else
836+
err = parse_test_list(arg,
837+
&env->test_selector.whitelist,
838+
key == ARG_TEST_NAME_GLOB_ALLOWLIST);
839+
828840
break;
829841
}
830842
case ARG_TEST_NAME_GLOB_DENYLIST:
831843
case ARG_TEST_NAME_BLACKLIST: {
832-
if (parse_test_list(arg,
833-
&env->test_selector.blacklist,
834-
key == ARG_TEST_NAME_GLOB_DENYLIST))
835-
return -ENOMEM;
844+
if (arg[0] == '@')
845+
err = parse_test_list_file(arg + 1,
846+
&env->test_selector.blacklist,
847+
key == ARG_TEST_NAME_GLOB_DENYLIST);
848+
else
849+
err = parse_test_list(arg,
850+
&env->test_selector.blacklist,
851+
key == ARG_TEST_NAME_GLOB_DENYLIST);
852+
836853
break;
837854
}
838855
case ARG_VERIFIER_STATS:
@@ -900,7 +917,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
900917
default:
901918
return ARGP_ERR_UNKNOWN;
902919
}
903-
return 0;
920+
return err;
904921
}
905922

906923
/*

tools/testing/selftests/bpf/testing_helpers.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
22
/* Copyright (C) 2019 Netronome Systems, Inc. */
33
/* Copyright (C) 2020 Facebook, Inc. */
4+
#include <ctype.h>
45
#include <stdlib.h>
56
#include <string.h>
67
#include <errno.h>
@@ -167,6 +168,52 @@ static int insert_test(struct test_filter_set *set,
167168
return -ENOMEM;
168169
}
169170

171+
int parse_test_list_file(const char *path,
172+
struct test_filter_set *set,
173+
bool is_glob_pattern)
174+
{
175+
char *buf = NULL, *capture_start, *capture_end, *scan_end;
176+
size_t buflen = 0;
177+
int err = 0;
178+
FILE *f;
179+
180+
f = fopen(path, "r");
181+
if (!f) {
182+
err = -errno;
183+
fprintf(stderr, "Failed to open '%s': %d\n", path, err);
184+
return err;
185+
}
186+
187+
while (getline(&buf, &buflen, f) != -1) {
188+
capture_start = buf;
189+
190+
while (isspace(*capture_start))
191+
++capture_start;
192+
193+
capture_end = capture_start;
194+
scan_end = capture_start;
195+
196+
while (*scan_end && *scan_end != '#') {
197+
if (!isspace(*scan_end))
198+
capture_end = scan_end;
199+
200+
++scan_end;
201+
}
202+
203+
if (capture_end == capture_start)
204+
continue;
205+
206+
*(++capture_end) = '\0';
207+
208+
err = insert_test(set, capture_start, is_glob_pattern);
209+
if (err)
210+
break;
211+
}
212+
213+
fclose(f);
214+
return err;
215+
}
216+
170217
int parse_test_list(const char *s,
171218
struct test_filter_set *set,
172219
bool is_glob_pattern)

tools/testing/selftests/bpf/testing_helpers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,8 @@ struct test_filter_set;
2020
int parse_test_list(const char *s,
2121
struct test_filter_set *test_set,
2222
bool is_glob_pattern);
23+
int parse_test_list_file(const char *path,
24+
struct test_filter_set *test_set,
25+
bool is_glob_pattern);
2326

2427
__u64 read_perf_max_sample_freq(void);

0 commit comments

Comments
 (0)