2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved.
5 # Control script for QA
25 brief_test_summary=false
29 # This is a global variable used to pass test failure text to reporting gunk
32 # start the initialisation work now
35 export MSGVERB="text:action"
36 export QA_CHECK_FS=${QA_CHECK_FS:=true}
38 # number of diff lines from a failed test, 0 for whole output
39 export DIFF_LENGTH=${DIFF_LENGTH:=10}
41 # by default don't output timestamps
42 timestamp=${TIMESTAMP:=false}
44 rm -f $tmp.list $tmp.tmp $tmp.grep $here/$iam.out $tmp.xlist $tmp.report.*
46 SRC_GROUPS="generic shared"
47 export SRC_DIR="tests"
51 echo "Usage: $0 [options] [testlist]"'
55 -glusterfs test GlusterFS
63 -udiff show unified diff (default)
64 -n show me, do not run tests
66 -r randomize test order
67 -d dump test output to stdout
69 -R fmt[,fmt] generate report in formats specified. Supported format: [xunit]
70 --large-fs optimise scratch device for large filesystems
71 -s section run only specified section from config file
72 -S section exclude the specified section from the config file
75 -g group[,group...] include tests from these groups
76 -x group[,group...] exclude tests from these groups
77 -X exclude_file exclude individual tests
78 -E external_file exclude individual tests
79 [testlist] include tests matching names in testlist
81 testlist argument is a list of tests in the form of <test dir>/<test name>.
83 <test dir> is a directory under tests that contains a group file,
84 with a list of the names of the tests in that directory.
86 <test name> may be either a specific test file name (e.g. xfs/001) or
87 a test file name match pattern (e.g. xfs/*).
89 group argument is either a name of a tests group to collect from all
90 the test dirs (e.g. quick) or a name of a tests group to collect from
91 a specific tests dir in the form of <test dir>/<group name> (e.g. xfs/quick).
92 If you want to run all the tests in the test suite, use "-g all" to specify all
95 exclude_file argument refers to a name of a file inside each test directory.
96 for every test dir where this file is found, the listed test names are
97 excluded from the list of tests to run from that test dir.
99 external_file argument is a path to a single file containing a list of tests
100 to exclude in the form of <test dir>/<test name>.
106 check -x stress xfs/*
107 check -X .exclude -g auto
108 check -E ~/.xfstests.exclude
118 test -s "$SRC_DIR/$d/group" || return 1
120 local grpl=$(sed -n < $SRC_DIR/$d/group \
123 -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p")
131 local sub=$(dirname $grp)
133 if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then
134 # group is given as <subdir>/<group> (e.g. xfs/quick)
136 get_sub_group_list $sub $grp
140 for d in $SRC_GROUPS $FSTYP; do
141 if ! test -d "$SRC_DIR/$d" ; then
144 grpl="$grpl $(get_sub_group_list $d $grp)"
149 # Find all tests, excluding files that are test metadata such as group files.
150 # It matches test names against $VALID_TEST_NAME defined in common/rc
154 for d in $SRC_GROUPS $FSTYP; do
155 if ! test -d "$SRC_DIR/$d" ; then
160 grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \
161 grep -v "group\|Makefile" >> $tmp.list 2>/dev/null
165 # takes the list of tests to run in $tmp.list, and removes the tests passed to
166 # the function from that list.
175 if [ $numsed -gt 100 ]; then
176 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
177 mv $tmp.tmp $tmp.list
181 echo "^$t\$" >>$tmp.grep
182 numsed=`expr $numsed + 1`
184 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
185 mv $tmp.tmp $tmp.list
204 # Tests specified on the command line
205 if [ -s $tmp.arglist ]; then
206 cat $tmp.arglist > $tmp.list
211 # Specified groups to include
212 # Note that the CLI processing adds a leading space to the first group
213 # parameter, so we have to catch that here checking for "all"
214 if ! $have_test_arg && [ "$GROUP_LIST" == " all" ]; then
215 # no test numbers, do everything
218 for group in $GROUP_LIST; do
219 list=$(get_group_list $group)
220 if [ -z "$list" ]; then
221 echo "Group \"$group\" is empty or not defined?"
226 grep -s "^$t\$" $tmp.list >/dev/null || \
227 echo "$t" >>$tmp.list
232 # Specified groups to exclude
233 for xgroup in $XGROUP_LIST; do
234 list=$(get_group_list $xgroup)
235 if [ -z "$list" ]; then
236 echo "Group \"$xgroup\" is empty or not defined?"
243 # sort the list of tests into numeric order
244 list=`sort -n $tmp.list | uniq`
249 list=`echo $list | awk -f randomize.awk`
253 # Process command arguments first.
254 while [ $# -gt 0 ]; do
256 -\? | -h | --help) usage ;;
259 -glusterfs) FSTYP=glusterfs ;;
262 -overlay) FSTYP=overlay; export OVERLAY=true ;;
263 -pvfs2) FSTYP=pvfs2 ;;
264 -tmpfs) FSTYP=tmpfs ;;
265 -ubifs) FSTYP=ubifs ;;
267 -g) group=$2 ; shift ;
268 GROUP_LIST="$GROUP_LIST ${group//,/ }"
271 -x) xgroup=$2 ; shift ;
272 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
275 -X) xfile=$2; shift ;
276 for d in $SRC_GROUPS $FSTYP; do
277 [ -f $SRC_DIR/$d/$xfile ] || continue
278 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
279 echo $d/$f >> $tmp.xlist
283 -E) xfile=$2; shift ;
284 if [ -f $xfile ]; then
285 sed "s/#.*$//" "$xfile" >> $tmp.xlist
288 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
289 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
291 -udiff) diff="$diff -u" ;;
294 -r) randomize=true ;;
296 -T) timestamp=true ;;
297 -d) DUMP_OUTPUT=true ;;
298 -b) brief_test_summary=true;;
299 -R) report_fmt=$2 ; shift ;
300 REPORT_LIST="$REPORT_LIST ${report_fmt//,/ }"
303 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
304 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
307 *) # not an argument, we've got tests now.
308 have_test_arg=true ;;
311 # if we've found a test specification, the break out of the processing
312 # loop before we shift the arguments so that this is the first argument
313 # that we process in the test arg loop below.
314 if $have_test_arg; then
321 # we need common/rc, that also sources common/config. We need to source it
322 # after processing args, overlay needs FSTYP set before sourcing common/config
323 if ! . ./common/rc; then
324 echo "check: failed to source common/rc"
328 # Process tests from command line now.
329 if $have_test_arg; then
330 while [ $# -gt 0 ]; do
332 -*) echo "Arguments before tests, please!"
336 *) # Expand test pattern (e.g. xfs/???, *fs/001)
337 list=$(cd $SRC_DIR; echo $1)
339 test_dir=`dirname $t`
340 test_dir=${test_dir#$SRC_DIR/*}
341 test_name=`basename $t`
342 group_file=$SRC_DIR/$test_dir/group
344 if egrep -q "^$test_name" $group_file; then
345 # in group file ... OK
346 echo $SRC_DIR/$test_dir/$test_name \
350 echo "$t - unknown test, ignored"
358 elif [ -z "$GROUP_LIST" ]; then
359 # default group list is the auto group. If any other group or test is
360 # specified, we use that instead.
366 echo "check: QA must be run as root"
381 check="$RESULT_BASE/check"
391 if [ -f $check.time -a -f $tmp.time ]; then
392 cat $check.time $tmp.time \
397 for (i in t) print i " " t[i]
401 mv $tmp.out $check.time
407 echo "SECTION -- $section" >>$tmp.summary
408 echo "=========================" >>$tmp.summary
409 if [ ! -z "$n_try" -a $n_try != 0 ]; then
410 if [ $brief_test_summary == "false" ]; then
412 echo "Ran:$try" >>$tmp.summary
414 echo "Ran:$try" >>$check.log
417 $interrupt && echo "Interrupted!" | tee -a $check.log
419 if [ ! -z "$notrun" ]; then
420 if [ $brief_test_summary == "false" ]; then
421 echo "Not run:$notrun"
422 echo "Not run:$notrun" >>$tmp.summary
424 echo "Not run:$notrun" >>$check.log
427 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
429 echo "Failed $n_bad of $n_try tests"
430 echo "Failures:$bad" >>$check.log
431 echo "Failed $n_bad of $n_try tests" >>$check.log
432 echo "Failures:$bad" >>$tmp.summary
433 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
435 echo "Passed all $n_try tests"
436 echo "Passed all $n_try tests" >>$check.log
437 echo "Passed all $n_try tests" >>$tmp.summary
439 echo "" >>$tmp.summary
446 sum_bad=`expr $sum_bad + $n_bad`
448 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
449 if ! $OPTIONS_HAVE_SECTIONS; then
460 count=`wc -L $tmp.summary | cut -f1 -d" "`
469 if [ -f ${RESULT_DIR}/require_test ]; then
470 _check_test_fs || err=true
471 rm -f ${RESULT_DIR}/require_test*
473 _test_unmount 2> /dev/null
475 if [ -f ${RESULT_DIR}/require_scratch ]; then
476 _check_scratch_fs || err=true
477 rm -f ${RESULT_DIR}/require_scratch*
479 _scratch_unmount 2> /dev/null
486 if [ -s $tmp.xlist ]; then
487 if grep -q $TEST_ID $tmp.xlist; then
498 if $OPTIONS_HAVE_SECTIONS; then
499 trap "_summary; exit \$status" 0 1 2 3 15
501 trap "_wrapup; exit \$status" 0 1 2 3 15
504 for section in $HOST_OPTIONS_SECTIONS; do
506 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
507 get_next_config $section
509 # Do we need to run only some sections ?
510 if [ ! -z "$RUN_SECTION" ]; then
512 for s in $RUN_SECTION; do
513 if [ $section == $s ]; then
523 # Did this section get excluded?
524 if [ ! -z "$EXCLUDE_SECTION" ]; then
526 for s in $EXCLUDE_SECTION; do
527 if [ $section == $s ]; then
537 if $OPTIONS_HAVE_SECTIONS; then
538 echo "SECTION -- $section"
541 sect_start=`_wallclock`
542 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
543 echo "RECREATING -- $FSTYP on $TEST_DEV"
544 _test_unmount 2> /dev/null
545 if ! _test_mkfs >$tmp.err 2>&1
547 echo "our local _test_mkfs routine ..."
549 echo "check: failed to mkfs \$TEST_DEV using specified options"
555 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
560 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
561 _test_unmount 2> /dev/null
564 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
573 check="$RESULT_BASE/check"
575 # don't leave old full output behind on a clean run
578 [ -f $check.time ] || touch $check.time
580 # print out our test configuration
581 echo "FSTYP -- `_full_fstyp_details`"
582 echo "PLATFORM -- `_full_platform_details`"
583 if [ ! -z "$SCRATCH_DEV" ]; then
584 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
585 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
590 if [ ! -z "$SCRATCH_DEV" ]; then
591 _scratch_unmount 2> /dev/null
592 # call the overridden mkfs - make sure the FS is built
593 # the same as we'll create it later.
595 if ! _scratch_mkfs >$tmp.err 2>&1
597 echo "our local _scratch_mkfs routine ..."
599 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
604 # call the overridden mount - make sure the FS mounts with
605 # the same options that we'll mount with later.
606 if ! _scratch_mount >$tmp.err 2>&1
608 echo "our local mount routine ..."
610 echo "check: failed to mount \$SCRATCH_DEV using specified options"
622 for seq in $list ; do
623 # Run report for previous test!
626 n_bad=`expr $n_bad + 1`
629 if $do_report && ! $first_test ; then
630 if [ $tc_status != "expunge" ] ; then
631 _make_testcase_report "$prev_seq" "$tc_status"
638 if [ ! -f $seq ]; then
639 # Try to get full name in case the user supplied only
640 # seq id and the test has a name. A bit of hassle to
641 # find really the test and not its sample output or
643 bname=$(basename $seq)
644 full_seq=$(find $(dirname $seq) -name $bname* -executable |
645 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
646 END { print shortest }')
647 if [ -f $full_seq ] && \
648 [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
653 # the filename for the test and the name output are different.
654 # we don't include the tests/ directory in the name output.
655 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
657 # Similarly, the result directory needs to replace the tests/
658 # part of the test location.
660 if $OPTIONS_HAVE_SECTIONS; then
661 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
662 REPORT_DIR="$RESULT_BASE/$section"
664 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
665 REPORT_DIR="$RESULT_BASE"
667 seqres="$REPORT_DIR/$seqnum"
673 _expunge_test $seqnum
674 if [ $? -eq 1 ]; then
682 n_notrun=`expr $n_notrun + 1`
687 if [ ! -f $seq ]; then
688 echo " - no such test?"
692 # really going to try and run this one
693 rm -f $seqres.out.bad
695 # check if we really should run it
696 _expunge_test $seqnum
697 if [ $? -eq 1 ]; then
702 # record that we really tried to run this test.
704 n_try=`expr $n_try + 1`
706 # slashes now in names, sed barfs on them so use grep
707 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
708 if [ "X$lasttime" != X ]; then
709 echo -n " ${lasttime}s ... "
711 echo -n " " # prettier output with timestamps.
713 rm -f core $seqres.notrun
716 $timestamp && echo -n " ["`date "+%T"`"]"
717 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
718 $LOGGER_PROG "run xfstest $seqnum"
719 if [ -w /dev/kmsg ]; then
720 export date_time=`date +"%F %T"`
721 echo "run fstests $seqnum at $date_time" > /dev/kmsg
722 # _check_dmesg depends on this log in dmesg
723 touch ${RESULT_DIR}/check_dmesg
725 if [ "$DUMP_OUTPUT" = true ]; then
726 ./$seq 2>&1 | tee $tmp.out
727 # Because $? would get tee's return code
730 ./$seq >$tmp.out 2>&1
735 _dump_err_cont "[dumped core]"
736 mv core $RESULT_BASE/$seqnum.core
740 if [ -f $seqres.notrun ]; then
741 $timestamp && _timestamp
743 $timestamp || echo -n "[not run] "
744 $timestamp && echo " [not run]" && \
745 echo -n " $seqnum -- "
747 notrun="$notrun $seqnum"
748 n_notrun=`expr $n_notrun + 1`
753 if [ $sts -ne 0 ]; then
754 _dump_err_cont "[failed, exit status $sts]"
755 _test_unmount 2> /dev/null
756 _scratch_unmount 2> /dev/null
759 # the test apparently passed, so check for corruption
760 # and log messages that shouldn't be there.
762 _check_dmesg || err=true
763 _check_kmemleak || err=true
766 # test ends after all checks are done.
767 $timestamp && _timestamp
770 if [ ! -f $seq.out ]; then
771 _dump_err "no qualified output"
776 # coreutils 8.16+ changed quote formats in error messages
777 # from `foo' to 'foo'. Filter old versions to match the new
779 sed -i "s/\`/\'/g" $tmp.out
780 if diff $seq.out $tmp.out >/dev/null 2>&1 ; then
782 echo "$seqnum `expr $stop - $start`" >>$tmp.time
783 echo -n " `expr $stop - $start`s"
787 _dump_err "- output mismatch (see $seqres.out.bad)"
788 mv $tmp.out $seqres.out.bad
789 $diff $seq.out $seqres.out.bad | {
790 if test "$DIFF_LENGTH" -le 0; then
793 head -n "$DIFF_LENGTH"
795 echo "(Run '$diff $here/$seq.out $seqres.out.bad'" \
796 " to see the entire diff)"
797 fi; } | sed -e 's/^\(.\)/ \1/'
802 # make sure we record the status of the last test we ran.
805 n_bad=`expr $n_bad + 1`
808 if $do_report && ! $first_test ; then
809 if [ $tc_status != "expunge" ] ; then
810 _make_testcase_report "$prev_seq" "$tc_status"
814 sect_stop=`_wallclock`
820 _test_unmount 2> /dev/null
821 _scratch_unmount 2> /dev/null
825 status=`expr $sum_bad != 0`