summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/test_progs.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/bpf/test_progs.c')
-rw-r--r--tools/testing/selftests/bpf/test_progs.c181
1 files changed, 136 insertions, 45 deletions
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 0929f4a7bda4..46eb201b96a3 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -165,6 +165,8 @@ struct prog_test_def {
void (*run_test)(void);
void (*run_serial_test)(void);
bool should_run;
+ bool not_built;
+ bool selected;
bool need_cgroup_cleanup;
bool should_tmon;
};
@@ -308,16 +310,34 @@ static bool match_subtest(struct test_filter_set *filter,
return false;
}
+static bool match_subtest_desc(struct test_filter_set *filter,
+ const char *test_name,
+ const char *subtest_name,
+ const char *subtest_desc)
+{
+ if (match_subtest(filter, test_name, subtest_name))
+ return true;
+
+ if (!subtest_desc || !subtest_desc[0] ||
+ strcmp(subtest_name, subtest_desc) == 0)
+ return false;
+
+ return match_subtest(filter, test_name, subtest_desc);
+}
+
static bool should_run_subtest(struct test_selector *sel,
struct test_selector *subtest_sel,
int subtest_num,
const char *test_name,
- const char *subtest_name)
+ const char *subtest_name,
+ const char *subtest_desc)
{
- if (match_subtest(&sel->blacklist, test_name, subtest_name))
+ if (match_subtest_desc(&sel->blacklist, test_name,
+ subtest_name, subtest_desc))
return false;
- if (match_subtest(&sel->whitelist, test_name, subtest_name))
+ if (match_subtest_desc(&sel->whitelist, test_name,
+ subtest_name, subtest_desc))
return true;
if (!sel->whitelist.cnt && !subtest_sel->num_set)
@@ -354,6 +374,8 @@ static void print_test_result(const struct prog_test_def *test, const struct tes
fprintf(env.stdout_saved, "#%-*d %s:", TEST_NUM_WIDTH, test->test_num, test->test_name);
if (test_state->error_cnt)
fprintf(env.stdout_saved, "FAIL");
+ else if (test->not_built)
+ fprintf(env.stdout_saved, "SKIP (not built)");
else if (!skipped_cnt)
fprintf(env.stdout_saved, "OK");
else if (skipped_cnt == subtests_cnt || !subtests_cnt)
@@ -402,10 +424,12 @@ static void jsonw_write_log_message(json_writer_t *w, char *log_buf, size_t log_
}
}
+/* @quiet elides the human readable output, the JSON report is unaffected */
static void dump_test_log(const struct prog_test_def *test,
const struct test_state *test_state,
bool skip_ok_subtests,
bool par_exec_result,
+ bool quiet,
json_writer_t *w)
{
bool test_failed = test_state->error_cnt > 0;
@@ -427,7 +451,7 @@ static void dump_test_log(const struct prog_test_def *test,
if (verbose() && !par_exec_result)
return;
- if (test_state->log_cnt && print_test)
+ if (test_state->log_cnt && print_test && !quiet)
print_test_log(test_state->log_buf, test_state->log_cnt);
if (w && print_test) {
@@ -449,15 +473,16 @@ static void dump_test_log(const struct prog_test_def *test,
if ((skip_ok_subtests && !subtest_failed) || subtest_filtered)
continue;
- if (subtest_state->log_cnt && print_subtest) {
+ if (subtest_state->log_cnt && print_subtest && !quiet) {
print_test_log(subtest_state->log_buf,
subtest_state->log_cnt);
}
- print_subtest_name(test->test_num, i + 1,
- test->test_name, subtest_state->name,
- test_result(subtest_state->error_cnt,
- subtest_state->skipped));
+ if (!quiet)
+ print_subtest_name(test->test_num, i + 1,
+ test->test_name, subtest_state->name,
+ test_result(subtest_state->error_cnt,
+ subtest_state->skipped));
if (w && print_subtest) {
jsonw_start_object(w);
@@ -474,7 +499,8 @@ static void dump_test_log(const struct prog_test_def *test,
jsonw_end_object(w);
}
- print_test_result(test, test_state);
+ if (!quiet)
+ print_test_result(test, test_state);
}
/* A bunch of tests set custom affinity per-thread and/or per-process. Reset
@@ -544,24 +570,26 @@ void test__end_subtest(void)
env.subtest_state = NULL;
}
-bool test__start_subtest(const char *subtest_name)
+bool test__start_subtest_with_desc(const char *subtest_name, const char *subtest_desc)
{
struct prog_test_def *test = env.test;
struct test_state *state = env.test_state;
struct subtest_state *subtest_state;
+ const char *subtest_display_name;
size_t sub_state_size = sizeof(*subtest_state);
+ void *tmp;
if (env.subtest_state)
test__end_subtest();
state->subtest_num++;
- state->subtest_states =
- realloc(state->subtest_states,
- state->subtest_num * sub_state_size);
- if (!state->subtest_states) {
+ tmp = realloc(state->subtest_states, state->subtest_num * sub_state_size);
+ if (!tmp) {
+ state->subtest_num--;
fprintf(stderr, "Not enough memory to allocate subtest result\n");
return false;
}
+ state->subtest_states = tmp;
subtest_state = &state->subtest_states[state->subtest_num - 1];
@@ -574,7 +602,9 @@ bool test__start_subtest(const char *subtest_name)
return false;
}
- subtest_state->name = strdup(subtest_name);
+ subtest_display_name = subtest_desc ? subtest_desc : subtest_name;
+
+ subtest_state->name = strdup(subtest_display_name);
if (!subtest_state->name) {
fprintf(env.stderr_saved,
"Subtest #%d: failed to copy subtest name!\n",
@@ -586,14 +616,15 @@ bool test__start_subtest(const char *subtest_name)
&env.subtest_selector,
state->subtest_num,
test->test_name,
- subtest_name)) {
+ subtest_name,
+ subtest_desc)) {
subtest_state->filtered = true;
return false;
}
- subtest_state->should_tmon = match_subtest(&env.tmon_selector.whitelist,
- test->test_name,
- subtest_name);
+ subtest_state->should_tmon = match_subtest_desc(&env.tmon_selector.whitelist,
+ test->test_name, subtest_name,
+ subtest_desc);
env.subtest_state = subtest_state;
stdio_hijack_init(&subtest_state->log_buf, &subtest_state->log_cnt);
@@ -602,6 +633,11 @@ bool test__start_subtest(const char *subtest_name)
return true;
}
+bool test__start_subtest(const char *subtest_name)
+{
+ return test__start_subtest_with_desc(subtest_name, NULL);
+}
+
void test__force_log(void)
{
env.test_state->force_log = true;
@@ -699,11 +735,14 @@ int compare_map_keys(int map1_fd, int map2_fd)
int compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len)
{
__u32 key, next_key, *cur_key_p, *next_key_p;
- char *val_buf1, *val_buf2;
- int i, err = 0;
+ char *val_buf1 = NULL, *val_buf2 = NULL;
+ int i, err = -ENOMEM;
val_buf1 = malloc(stack_trace_len);
val_buf2 = malloc(stack_trace_len);
+ if (!val_buf1 || !val_buf2)
+ goto out;
+ err = 0;
cur_key_p = NULL;
next_key_p = &key;
while (bpf_map_get_next_key(smap_fd, cur_key_p, next_key_p) == 0) {
@@ -864,6 +903,7 @@ enum ARG_KEYS {
ARG_JSON_SUMMARY = 'J',
ARG_TRAFFIC_MONITOR = 'm',
ARG_WATCHDOG_TIMEOUT = 'w',
+ ARG_NO_ERROR_SUMMARY = -2,
};
static const struct argp_option opts[] = {
@@ -896,6 +936,8 @@ static const struct argp_option opts[] = {
#endif
{ "watchdog-timeout", ARG_WATCHDOG_TIMEOUT, "SECONDS", 0,
"Kill the process if tests are not making progress for specified number of seconds." },
+ { "no-error-summary", ARG_NO_ERROR_SUMMARY, NULL, 0,
+ "Do not re-print the aggregated error logs of failed tests at the end of the run." },
{},
};
@@ -1097,6 +1139,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
case ARG_DEBUG:
env->debug = true;
break;
+ case ARG_NO_ERROR_SUMMARY:
+ env->error_summary = false;
+ break;
case ARG_JSON_SUMMARY:
env->json = fopen(arg, "w");
if (env->json == NULL) {
@@ -1230,7 +1275,7 @@ int get_bpf_max_tramp_links_from(struct btf *btf)
const struct btf_type *t;
__u32 i, type_cnt;
const char *name;
- __u16 j, vlen;
+ __u32 j, vlen;
for (i = 1, type_cnt = btf__type_cnt(btf); i < type_cnt; i++) {
t = btf__type_by_id(btf, i);
@@ -1269,7 +1314,7 @@ static void dump_crash_log(void)
if (env.test) {
env.test_state->error_cnt++;
- dump_test_log(env.test, env.test_state, true, false, NULL);
+ dump_test_log(env.test, env.test_state, true, false, false, NULL);
}
}
@@ -1427,7 +1472,7 @@ static void run_one_test(int test_num)
free(stop_libbpf_log_capture());
- dump_test_log(test, state, false, false, NULL);
+ dump_test_log(test, state, false, false, false, NULL);
}
struct dispatch_data {
@@ -1482,13 +1527,15 @@ static int dispatch_thread_send_subtests(int sock_fd, struct test_state *state)
struct subtest_state *subtest_state;
int subtest_num = state->subtest_num;
- state->subtest_states = malloc(subtest_num * sizeof(*subtest_state));
+ state->subtest_states = calloc(subtest_num, sizeof(*subtest_state));
+ if (!state->subtest_states) {
+ state->subtest_num = 0;
+ return -ENOMEM;
+ }
for (int i = 0; i < subtest_num; i++) {
subtest_state = &state->subtest_states[i];
- memset(subtest_state, 0, sizeof(*subtest_state));
-
if (read_prog_test_msg(sock_fd, &msg, MSG_SUBTEST_DONE))
return 1;
@@ -1586,7 +1633,7 @@ static void *dispatch_thread(void *ctx)
} while (false);
pthread_mutex_lock(&stdout_output_lock);
- dump_test_log(test, state, false, true, NULL);
+ dump_test_log(test, state, false, true, false, NULL);
pthread_mutex_unlock(&stdout_output_lock);
} /* while (true) */
error:
@@ -1609,11 +1656,12 @@ done:
static void calculate_summary_and_print_errors(struct test_env *env)
{
- int i;
- int succ_cnt = 0, fail_cnt = 0, sub_succ_cnt = 0, skip_cnt = 0;
+ int i, j;
+ int succ_cnt = 0, fail_cnt = 0, sub_succ_cnt = 0, sub_fail_cnt = 0, skip_cnt = 0;
json_writer_t *w = NULL;
for (i = 0; i < prog_test_cnt; i++) {
+ struct prog_test_def *test = &prog_test_defs[i];
struct test_state *state = &test_states[i];
if (!state->tested)
@@ -1622,10 +1670,14 @@ static void calculate_summary_and_print_errors(struct test_env *env)
sub_succ_cnt += state->sub_succ_cnt;
skip_cnt += state->skip_cnt;
- if (state->error_cnt)
+ if (state->error_cnt) {
fail_cnt++;
- else
+ for (j = 0; j < state->subtest_num; j++)
+ if (state->subtest_states[j].error_cnt)
+ sub_fail_cnt++;
+ } else if (!test->not_built) {
succ_cnt++;
+ }
}
if (env->json) {
@@ -1640,6 +1692,7 @@ static void calculate_summary_and_print_errors(struct test_env *env)
jsonw_uint_field(w, "success_subtest", sub_succ_cnt);
jsonw_uint_field(w, "skipped", skip_cnt);
jsonw_uint_field(w, "failed", fail_cnt);
+ jsonw_uint_field(w, "failed_subtest", sub_fail_cnt);
jsonw_name(w, "results");
jsonw_start_array(w);
}
@@ -1648,9 +1701,14 @@ static void calculate_summary_and_print_errors(struct test_env *env)
* We only print error logs summary when there are failed tests and
* verbose mode is not enabled. Otherwise, results may be inconsistent.
*
+ * --no-error-summary elides the human readable dump. The walk still
+ * happens when a JSON report was requested, so the JSON output keeps
+ * its per-test results; with no JSON report there is nothing left to
+ * do and the whole loop is skipped.
*/
- if (!verbose() && fail_cnt) {
- printf("\nAll error logs:\n");
+ if (!verbose() && fail_cnt && (env->error_summary || w)) {
+ if (env->error_summary)
+ printf("\nAll error logs:\n");
/* print error logs again */
for (i = 0; i < prog_test_cnt; i++) {
@@ -1660,7 +1718,8 @@ static void calculate_summary_and_print_errors(struct test_env *env)
if (!state->tested || !state->error_cnt)
continue;
- dump_test_log(test, state, true, true, w);
+ dump_test_log(test, state, true, true,
+ !env->error_summary, w);
}
}
@@ -1673,8 +1732,13 @@ static void calculate_summary_and_print_errors(struct test_env *env)
if (env->json)
fclose(env->json);
- printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n",
- succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt);
+ if (env->not_built_cnt)
+ printf("Summary: %d/%d PASSED, %d SKIPPED (%d not built), %d/%d FAILED\n",
+ succ_cnt, sub_succ_cnt, skip_cnt, env->not_built_cnt,
+ fail_cnt, sub_fail_cnt);
+ else
+ printf("Summary: %d/%d PASSED, %d SKIPPED, %d/%d FAILED\n",
+ succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt, sub_fail_cnt);
env->succ_cnt = succ_cnt;
env->sub_succ_cnt = sub_succ_cnt;
@@ -1704,7 +1768,7 @@ static void server_main(void)
data[i].worker_id = i;
data[i].sock_fd = env.worker_socks[i];
rc = pthread_create(&dispatcher_threads[i], NULL, dispatch_thread, &data[i]);
- if (rc < 0) {
+ if (rc) {
perror("Failed to launch dispatcher thread");
exit(EXIT_ERR_SETUP_INFRA);
}
@@ -1745,6 +1809,19 @@ static void server_main(void)
run_one_test(i);
}
+ /* mark not-built tests as skipped */
+ for (int i = 0; i < prog_test_cnt; i++) {
+ struct prog_test_def *test = &prog_test_defs[i];
+ struct test_state *state = &test_states[i];
+
+ if (test->not_built && test->selected) {
+ state->tested = true;
+ state->skip_cnt = 1;
+ env.not_built_cnt++;
+ print_test_result(test, state);
+ }
+ }
+
/* generate summary */
fflush(stderr);
fflush(stdout);
@@ -1836,7 +1913,6 @@ static int worker_main_send_subtests(int sock, struct test_state *state)
worker_main_send_log(sock, subtest_state->log_buf, subtest_state->log_cnt);
free_subtest_state(subtest_state);
- free(subtest_state->name);
}
out:
@@ -1973,6 +2049,7 @@ int main(int argc, char **argv)
env.secs_till_notify = 10;
env.secs_till_kill = 120;
+ env.error_summary = true;
err = argp_parse(&argp, argc, argv, 0, NULL, &env);
if (err)
return err;
@@ -2019,15 +2096,20 @@ int main(int argc, char **argv)
struct prog_test_def *test = &prog_test_defs[i];
test->test_num = i + 1;
- test->should_run = should_run(&env.test_selector,
- test->test_num, test->test_name);
+ test->selected = should_run(&env.test_selector,
+ test->test_num, test->test_name);
+ test->should_run = test->selected;
- if ((test->run_test == NULL && test->run_serial_test == NULL) ||
- (test->run_test != NULL && test->run_serial_test != NULL)) {
+ if (test->run_test && test->run_serial_test) {
fprintf(stderr, "Test %d:%s must have either test_%s() or serial_test_%sl() defined.\n",
test->test_num, test->test_name, test->test_name, test->test_name);
exit(EXIT_ERR_SETUP_INFRA);
}
+ if (!test->run_test && !test->run_serial_test) {
+ test->not_built = true;
+ test->should_run = false;
+ continue;
+ }
if (test->should_run)
test->should_tmon = should_tmon(&env.tmon_selector, test->test_name);
}
@@ -2079,9 +2161,18 @@ int main(int argc, char **argv)
for (i = 0; i < prog_test_cnt; i++) {
struct prog_test_def *test = &prog_test_defs[i];
+ struct test_state *state = &test_states[i];
- if (!test->should_run)
+ if (!test->should_run) {
+ if (test->not_built && test->selected &&
+ !env.get_test_cnt && !env.list_test_names) {
+ state->tested = true;
+ state->skip_cnt = 1;
+ env.not_built_cnt++;
+ print_test_result(test, state);
+ }
continue;
+ }
if (env.get_test_cnt) {
env.succ_cnt++;