All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Disseldorp <ddiss@suse.de>
To: "Darrick J. Wong" <djwong@kernel.org>
Cc: fstests@vger.kernel.org, tytso@mit.edu
Subject: Re: [RFC PATCH v2 5/6] check: add -L <n> parameter to rerun failed tests
Date: Wed, 29 Jun 2022 00:34:32 +0200	[thread overview]
Message-ID: <20220629003432.665c9872@suse.de> (raw)
In-Reply-To: <Yrsa+wO6vLcsvcJ3@magnolia>

Thanks for the review, Darrick...

On Tue, 28 Jun 2022 08:15:07 -0700, Darrick J. Wong wrote:

> On Tue, Jun 28, 2022 at 12:22:55AM +0200, David Disseldorp wrote:
> > If check is run with -L <n>, then a failed test will be rerun <n> times
> > before proceeding to the next test. Following completion of the rerun
> > loop, aggregate pass/fail statistics are printed.
> > 
> > Rerun tests will be tracked as a single failure in overall pass/fail
> > metrics (via @try and @bad), with .out.bad, .dmesg and .full saved using
> > a .rerun# suffix.
> > 
> > Suggested-by: Theodore Ts'o <tytso@mit.edu>
> > Link: https://lwn.net/Articles/897061/
> > Signed-off-by: David Disseldorp <ddiss@suse.de>
> > ---
> >  check         | 94 ++++++++++++++++++++++++++++++++++++++++++++-------
> >  common/report |  8 +++--
> >  2 files changed, 88 insertions(+), 14 deletions(-)
> > 
> > diff --git a/check b/check
> > index aa7dac2f..726c83d9 100755
> > --- a/check
> > +++ b/check
> > @@ -26,6 +26,7 @@ do_report=false
> >  DUMP_OUTPUT=false
> >  iterations=1
> >  istop=false
> > +loop_on_fail=0
> >  
> >  # This is a global variable used to pass test failure text to reporting gunk
> >  _err_msg=""
> > @@ -75,6 +76,7 @@ check options
> >      --large-fs		optimise scratch device for large filesystems
> >      -s section		run only specified section from config file
> >      -S section		exclude the specified section from the config file
> > +    -L <n>		loop tests <n> times following a failure, measuring aggregate pass/fail metrics
> >  
> >  testlist options
> >      -g group[,group...]	include tests from these groups
> > @@ -333,6 +335,9 @@ while [ $# -gt 0 ]; do
> >  		;;
> >  	--large-fs) export LARGE_SCRATCH_DEV=yes ;;
> >  	--extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
> > +	-L)	[[ $2 =~ ^[0-9]+$ ]] || usage
> > +		loop_on_fail=$2; shift
> > +		;;
> >  
> >  	-*)	usage ;;
> >  	*)	# not an argument, we've got tests now.
> > @@ -555,6 +560,18 @@ _expunge_test()
> >  _stash_test_status() {
> >  	local test_seq="$1"
> >  	local test_status="$2"
> > +	local test_time="$3"
> > +	local loop_num="$4"
> > +	local report_msg="$5"
> > +
> > +	if $do_report && [[ ! $test_status =~ ^(init|expunge)$ ]]; then
> > +		_make_testcase_report "$section" "$test_seq" \
> > +				      "$test_status" "$test_time" \
> > +				      "$report_msg"
> > +	fi
> > +
> > +	# only stash result for first failure (triggering loop)
> > +	((loop_num > 1)) && return
> >  
> >  	case "$test_status" in
> >  	fail)
> > @@ -610,6 +627,38 @@ _run_seq() {
> >  	fi
> >  }
> >  
> > +# Check whether the last test should be rerun according to loop-on-error state
> > +# and return "0" if so, otherwise return "1".  
> 
> Er... this echoes 0 and 1, and the return value of the function is
> neither checked nor set to anything other than zero, right?

Right. run_section() test list iteration uses this helper to
conditionally increment the test index, depending on whether or not a
rerun (following test failure) is required.

> I'm also not sure what 'ix' stands for?

Index... I figured 'i' would get stomped on and didn't come up with a
better name at the time :)

> > +_ix_inc() {
> > +	local test_status="$1"
> > +	local loop_len="$2"
> > +
> > +	if ((!loop_on_fail)); then
> > +		echo 1
> > +		return
> > +	fi
> > +
> > +	if [ "$test_status" == "fail" ] && ((!loop_len)); then
> > +		echo 0	# initial failure of this test, start loop-on-fail
> > +	elif ((loop_len > 0)) && ((loop_len < loop_on_fail)); then
> > +		echo 0	# continue loop following initial failure
> > +	else
> > +		echo 1	# completed or not currently in a failure loop
> > +	fi
> > +}
> > +
> > +_failure_loop_dump_stats() {
> > +	awk "BEGIN {
> > +		n=split(\"$*\", arr);"'
> > +		for (i = 1; i <= n; i++)
> > +			stats[arr[i]]++;
> > +		printf("aggregate results across %d runs: ", n);
> > +		for (x in stats)
> > +			printf("%s=%d (%.1f%%)", (i-- > n ? x : ", " x),
> > +			       stats[x], 100 * stats[x] / n);
> > +	     }'
> > +}
> > +
> >  _detect_kmemleak
> >  _prepare_test_list
> >  
> > @@ -750,14 +799,29 @@ function run_section()
> >  	seqres="$check"
> >  	_check_test_fs
> >  
> > -	local tc_status="init"
> > +	local tc_status="init" ix agg_msg
> >  	prev_seq=""
> > -	for seq in $list ; do
> > +	local -a _list=( $list ) loop_status=()
> > +	for ((ix = 0; ix < ${#_list[*]};
> > +	      ix += $(_ix_inc "$tc_status" "${#loop_status[*]}"))); do

Here is the _ix_inc caller ^^. It's a bit convoluted so I could probably
turn it into a while loop and put the increment logic here. Not sure how
much simpler it'd be though.

> > +		seq="${_list[$ix]}"
> > +
> > +		if [ "$seq" == "$prev_seq" ]; then
> > +			loop_status+=("$tc_status")
> > +		elif ((${#loop_status[*]})); then
> > +			# leaving rerun-on-failure loop
> > +			loop_status+=("$tc_status")
> > +			agg_msg=$(_failure_loop_dump_stats "${loop_status[@]}")
> > +			echo "$seqnum $agg_msg"
> > +		fi
> > +
> >  		# Run report for previous test!
> > -		_stash_test_status "$seqnum" "$tc_status"
> > -		if $do_report && [[ ! $tc_status =~ ^(init|expunge)$ ]]; then
> > -			_make_testcase_report "$section" "$seqnum" \
> > -					      "$tc_status" "$((stop - start))"
> > +		_stash_test_status "$seqnum" "$tc_status" "$((stop - start))" \
> > +				   "${#loop_status[*]}" "$agg_msg"
> > +
> > +		if [ -n "$agg_msg" ]; then
> > +			loop_status=()
> > +			agg_msg=""
> >  		fi
> >  
> >  		prev_seq="$seq"
> > @@ -827,7 +891,9 @@ function run_section()
> >  		fi
> >  
> >  		# record that we really tried to run this test.
> > -		try+=("$seqnum")
> > +		if ((!${#loop_status[*]})); then
> > +			try+=("$seqnum")
> > +		fi
> >  
> >  		awk 'BEGIN {lasttime="       "} \
> >  		     $1 == "'$seqnum'" {lasttime=" " $2 "s ... "; exit} \
> > @@ -954,13 +1020,17 @@ function run_section()
> >  		fi
> >  	done
> >  
> > -	# make sure we record the status of the last test we ran.
> > -	_stash_test_status "$seqnum" "$tc_status"
> > -	if $do_report && [[ ! $tc_status =~ ^(init|expunge)$ ]]; then
> > -		_make_testcase_report "$section" "$seqnum" "$tc_status" \
> > -				      "$((stop - start))"
> > +	if ((${#loop_status[*]})); then
> > +		# leaving rerun-on-failure loop
> > +		loop_status+=("$tc_status")
> > +		agg_msg=$(_failure_loop_dump_stats "${loop_status[@]}")
> > +		echo "$seqnum $agg_msg"
> >  	fi
> >  
> > +	# Run report for previous test!
> > +	_stash_test_status "$seqnum" "$tc_status" "$((stop - start))" \
> > +			   "${#loop_status[*]}" "$agg_msg"
> > +
> >  	sect_stop=`_wallclock`
> >  	interrupt=false
> >  	_wrapup
> > diff --git a/common/report b/common/report
> > index 5ca41bc4..cede4987 100644
> > --- a/common/report
> > +++ b/common/report
> > @@ -71,6 +71,7 @@ _xunit_make_testcase_report()
> >  	local test_name="$2"
> >  	local test_status="$3"
> >  	local test_time="$4"
> > +	local test_md="$5"  
> 
> ...or what "md" here means.

Test (result) metadata.

> >  	# TODO: other places may also win if no-section mode will be named like 'default/global'
> >  	if [ $sect_name == '-no-sections-' ]; then
> > @@ -79,7 +80,8 @@ _xunit_make_testcase_report()
> >  	fi
> >  	local report=$tmp.report.xunit.$sect_name.xml
> >  
> > -	echo -e "\t<testcase classname=\"xfstests.$sect_name\" name=\"$test_name\" time=\"$test_time\">" >> $report
> > +	[ -n "$test_md" ] && test_md=" status=\"$(echo "$test_md"|encode_xml)\""  
> 
> AFAICT the junit xml schema defines a @status attribute for <testcase>.
> 
> https://raw.githubusercontent.com/windyroad/JUnit-Schema/master/JUnit.xsd

^ hmm, I don't see a @status attribute under your link. I was using a
different reference...

> And yes, it's confusing that fstests namespaced all this code with
> 'xunit', since there's a separate xunit test reporting schema too!

It is absolutely confusing. I've been using
https://llg.cubic.org/docs/junit/ but only came across that by searching
for specific attribute names.

> That said -- I'm not sure what's supposed to end up in this attribute?
> It looks like it's supposed to capture the aggregation report?

Correct, it's just the aggregation report for now.

> But then I wonder, why not stick to adding a separate <testcase> element
> for each test run, even the repeated ones?  And let the xml consumer
> compute aggregation statistics from the elements?

This v2 patchset does add a <testcase> element for each rerun, with the
aggregation stats attached to the last rerun . The
aggregation stats are already calculated for non-xunit output, and
passing it through for xunit only costs a few lines of code. However, if
the @status attribute isn't an option then I suppose I could drop it -
Ted also mentioned that it's unnecessary.

Cheers, David

  reply	other threads:[~2022-06-28 22:34 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-27 22:22 [RFC PATCH v2 0/6] check: add option to rerun failed tests David Disseldorp
2022-06-27 22:22 ` [RFC PATCH v2 1/6] report: use array for REPORT_ENV_LIST David Disseldorp
2022-06-28 14:54   ` Darrick J. Wong
2022-06-27 22:22 ` [RFC PATCH v2 2/6] report: pass through most details as function parameters David Disseldorp
2022-06-28 14:55   ` Darrick J. Wong
2022-06-27 22:22 ` [RFC PATCH v2 3/6] check: make a few variables local David Disseldorp
2022-06-28 14:56   ` Darrick J. Wong
2022-06-27 22:22 ` [RFC PATCH v2 4/6] check: append bad / notrun arrays in helper function David Disseldorp
2022-06-28 15:00   ` Darrick J. Wong
2022-06-27 22:22 ` [RFC PATCH v2 5/6] check: add -L <n> parameter to rerun failed tests David Disseldorp
2022-06-28 15:15   ` Darrick J. Wong
2022-06-28 22:34     ` David Disseldorp [this message]
2022-06-27 22:22 ` [RFC PATCH v2 6/6] check: stash full/dmesg/out.bad files on rerun David Disseldorp
2022-06-28 15:16   ` Darrick J. Wong
2022-06-28 22:36     ` David Disseldorp

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=20220629003432.665c9872@suse.de \
    --to=ddiss@suse.de \
    --cc=djwong@kernel.org \
    --cc=fstests@vger.kernel.org \
    --cc=tytso@mit.edu \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.