From: Manu Bretelle <chantr4@gmail.com>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: bpf@vger.kernel.org, andrii@kernel.org, mykolal@fb.com,
ast@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev,
yhs@fb.com
Subject: Re: [PATCH bpf-next] selftests/bpf: add --json-summary option to test_progs
Date: Thu, 16 Mar 2023 17:40:03 -0700 [thread overview]
Message-ID: <ZBO24yyuynZCMqGO@worktop> (raw)
In-Reply-To: <CAEf4BzYiFYdqToBpnnYMCxi+eihMu1VJ1Njz9_3vHES9y3yYcw@mail.gmail.com>
On Thu, Mar 16, 2023 at 04:21:52PM -0700, Andrii Nakryiko wrote:
> On Wed, Mar 15, 2023 at 11:39 PM Manu Bretelle <chantr4@gmail.com> wrote:
> >
> > Currently, test_progs outputs all stdout/stderr as it runs, and when it
> > is done, prints a summary.
> >
> > It is non-trivial for tooling to parse that output and extract meaningful
> > information from it.
> >
> > This change adds a new option, `--json-summary`/`-J` that let the caller
> > specify a file where `test_progs{,-no_alu32}` can write a summary of the
> > run in a json format that can later be parsed by tooling.
> >
> > Currently, it creates a summary section with successes/skipped/failures
> > followed by a list of failed tests/subtests.
> >
> > A test contains the following fields:
> > - test_name: the name of the test
> > - test_number: the number of the test
> > - message: the log message that was printed by the test.
> > - failed: A boolean indicating whether the test failed or not. Currently
> > we only output failed tests, but in the future, successful tests could
> > be added.
> >
> > A subtest contains the following fields:
> > - test_name: same as above
> > - test_number: sanme as above
> > - subtest_name: the name of the subtest
> > - subtest_number: the number of the subtest.
> > - message: the log message that was printed by the subtest.
> > - is_subtest: a boolean indicating that the entry is a subtest.
>
> "is_" prefix stands out compared to other bool field ("failed"),
> should we call this just "subtest" for consistency?
>
yes, I will give a try to the nested representation and play a bit more
with jq. In any case, this will become `subtest[s]`.
> > - failed: same as above but for the subtest
> >
> > ```
> > $ sudo ./test_progs -a $(grep -v '^#' ./DENYLIST.aarch64 | awk '{print
> > $1","}' | tr -d '\n') -j -J /tmp/test_progs.json
> > $ jq . < /tmp/test_progs.json | head -n 30
> > $ head -n 30 /tmp/test_progs.json
> > {
> > "success": 29,
> > "success_subtest": 23,
> > "skipped": 3,
> > "failed": 27,
> > "results": [{
> > "test_name": "bpf_cookie",
> > "test_number": 10,
> > "message": "test_bpf_cookie:PASS:skel_open 0 nsec\n",
> > "failed": true
> > },{
> > "test_name": "bpf_cookie",
> > "subtest_name": "multi_kprobe_link_api",
> > "test_number": 10,
> > "subtest_number": 2,
> > "message": "kprobe_multi_link_api_subtest:PASS:load_kallsyms
> > 0 nsec\nlibbpf: extern 'bpf_testmod_fentry_test1' (strong): not
> > resolved\nlibbpf: failed to load object 'kprobe_multi'\nlibbpf: failed
> > to load BPF skeleton 'kprobe_multi':
> > -3\nkprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected
> > error: -3\n",
> > "is_subtest": true,
> > "failed": true
> > },{
> > "test_name": "bpf_cookie",
> > "subtest_name": "multi_kprobe_attach_api",
> > "test_number": 10,
> > "subtest_number": 3,
> > "message": "libbpf: extern 'bpf_testmod_fentry_test1'
> > (strong): not resolved\nlibbpf: failed to load object
> > 'kprobe_multi'\nlibbpf: failed to load BPF skeleton 'kprobe_multi':
> > -3\nkprobe_multi_attach_api_subtest:FAIL:fentry_raw_skel_load unexpected
> > error: -3\n",
> > "is_subtest": true,
> > "failed": true
> > },{
> > "test_name": "bpf_cookie",
> > "subtest_name": "lsm",
> > "test_number": 10,
> > ```
> >
> > The file can then be used to print a summary of the test run and list of
> > failing tests/subtests:
> >
> > ```
> > $ jq -r < /tmp/test_progs.json '"Success:
> > \(.success)/\(.success_subtest), Skipped: \(.skipped), Failed:
> > \(.failed)"'
> >
> > Success: 29/23, Skipped: 3, Failed: 27
> > $ jq -r <
> > /tmp/test_progs.json '.results[] | if .is_subtest then
> > "#\(.test_number)/\(.subtest_number) \(.test_name)/\(.subtest_name)"
> > else "#\(.test_number) \(.test_name)" end'
> > ```
> >
> > Signed-off-by: Manu Bretelle <chantr4@gmail.com>
> > ---
>
> Looks great, some nits below.
>
> > tools/testing/selftests/bpf/Makefile | 4 +-
> > tools/testing/selftests/bpf/json_writer.c | 1 +
> > tools/testing/selftests/bpf/json_writer.h | 1 +
> > tools/testing/selftests/bpf/test_progs.c | 83 +++++++++++++++++++++--
> > tools/testing/selftests/bpf/test_progs.h | 1 +
> > 5 files changed, 84 insertions(+), 6 deletions(-)
> > create mode 120000 tools/testing/selftests/bpf/json_writer.c
> > create mode 120000 tools/testing/selftests/bpf/json_writer.h
> >
>
> [...]
>
> > @@ -269,10 +270,22 @@ static void print_subtest_name(int test_num, int subtest_num,
> > fprintf(env.stdout, "\n");
> > }
> >
> > +static void jsonw_write_log_message(json_writer_t *w, char *log_buf, size_t log_cnt)
> > +{
> > + // open_memstream (from stdio_hijack_init) ensures that log_bug is terminated by a
> > + // null byte. Yet in parralel mode, log_buf will be NULL if there is no message.
>
> please don't use C++-style comments, let's use /* */ consistently
>
> also typo: parallel
>
ack
> > + if (log_cnt) {
> > + jsonw_string_field(w, "message", log_buf);
> > + } else {
> > + jsonw_string_field(w, "message", "");
> > + }
> > +}
> > +
>
> [...]
>
> > @@ -1283,7 +1327,7 @@ static void *dispatch_thread(void *ctx)
> > } while (false);
> >
> > pthread_mutex_lock(&stdout_output_lock);
> > - dump_test_log(test, state, false, true);
> > + dump_test_log(test, state, false, true, NULL);
> > pthread_mutex_unlock(&stdout_output_lock);
> > } /* while (true) */
> > error:
> > @@ -1322,8 +1366,28 @@ static void calculate_summary_and_print_errors(struct test_env *env)
> > fail_cnt++;
> > else
> > succ_cnt++;
> > +
> > + }
> > +
> > + json_writer_t *w = NULL;
>
> please declare variable at the top to follow C89 style
>
ack
> > +
> > + if (env->json) {
> > + w = jsonw_new(env->json);
> > + if (!w)
> > + fprintf(env->stderr, "Failed to create new JSON stream.");
> > }
> >
> > + if (w) {
> > + jsonw_pretty(w, 1);
>
> true, it's bool
>
actually, given that this is not printed to stdout, and jq is widely available...
probably no need to pretty the output.
> > + jsonw_start_object(w);
> > + jsonw_uint_field(w, "success", succ_cnt);
> > + jsonw_uint_field(w, "success_subtest", sub_succ_cnt);
> > + jsonw_uint_field(w, "skipped", skip_cnt);
> > + jsonw_uint_field(w, "failed", fail_cnt);
> > + jsonw_name(w, "results");
> > + jsonw_start_array(w);
> > +
> > + }
>
> [...]
prev parent reply other threads:[~2023-03-17 0:40 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-16 6:39 [PATCH bpf-next] selftests/bpf: add --json-summary option to test_progs Manu Bretelle
2023-03-16 15:03 ` Eduard Zingerman
2023-03-16 16:38 ` Manu Bretelle
2023-03-16 19:18 ` Eduard Zingerman
2023-03-16 23:23 ` Andrii Nakryiko
2023-03-16 23:33 ` Eduard Zingerman
2023-03-17 0:07 ` Andrii Nakryiko
2023-03-17 0:24 ` Manu Bretelle
2023-03-16 23:21 ` Andrii Nakryiko
2023-03-17 0:40 ` Manu Bretelle [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZBO24yyuynZCMqGO@worktop \
--to=chantr4@gmail.com \
--cc=andrii.nakryiko@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=martin.lau@linux.dev \
--cc=mykolal@fb.com \
--cc=yhs@fb.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox