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 mkdir -p $RESULT_BASE
538 if [ ! -d $RESULT_BASE ]; then
539 echo "failed to create results directory $RESULT_BASE"
544 if $OPTIONS_HAVE_SECTIONS; then
545 echo "SECTION -- $section"
548 sect_start=`_wallclock`
549 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
550 echo "RECREATING -- $FSTYP on $TEST_DEV"
551 _test_unmount 2> /dev/null
552 if ! _test_mkfs >$tmp.err 2>&1
554 echo "our local _test_mkfs routine ..."
556 echo "check: failed to mkfs \$TEST_DEV using specified options"
562 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
567 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
568 _test_unmount 2> /dev/null
571 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
580 check="$RESULT_BASE/check"
582 # don't leave old full output behind on a clean run
585 [ -f $check.time ] || touch $check.time
587 # print out our test configuration
588 echo "FSTYP -- `_full_fstyp_details`"
589 echo "PLATFORM -- `_full_platform_details`"
590 if [ ! -z "$SCRATCH_DEV" ]; then
591 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
592 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
597 if [ ! -z "$SCRATCH_DEV" ]; then
598 _scratch_unmount 2> /dev/null
599 # call the overridden mkfs - make sure the FS is built
600 # the same as we'll create it later.
602 if ! _scratch_mkfs >$tmp.err 2>&1
604 echo "our local _scratch_mkfs routine ..."
606 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
611 # call the overridden mount - make sure the FS mounts with
612 # the same options that we'll mount with later.
613 if ! _scratch_mount >$tmp.err 2>&1
615 echo "our local mount routine ..."
617 echo "check: failed to mount \$SCRATCH_DEV using specified options"
629 for seq in $list ; do
630 # Run report for previous test!
633 n_bad=`expr $n_bad + 1`
636 if $do_report && ! $first_test ; then
637 if [ $tc_status != "expunge" ] ; then
638 _make_testcase_report "$prev_seq" "$tc_status"
645 if [ ! -f $seq ]; then
646 # Try to get full name in case the user supplied only
647 # seq id and the test has a name. A bit of hassle to
648 # find really the test and not its sample output or
650 bname=$(basename $seq)
651 full_seq=$(find $(dirname $seq) -name $bname* -executable |
652 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
653 END { print shortest }')
654 if [ -f $full_seq ] && \
655 [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
660 # the filename for the test and the name output are different.
661 # we don't include the tests/ directory in the name output.
662 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
664 # Similarly, the result directory needs to replace the tests/
665 # part of the test location.
667 if $OPTIONS_HAVE_SECTIONS; then
668 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
669 REPORT_DIR="$RESULT_BASE/$section"
671 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
672 REPORT_DIR="$RESULT_BASE"
674 seqres="$REPORT_DIR/$seqnum"
680 _expunge_test $seqnum
681 if [ $? -eq 1 ]; then
689 n_notrun=`expr $n_notrun + 1`
694 if [ ! -f $seq ]; then
695 echo " - no such test?"
699 # really going to try and run this one
700 rm -f $seqres.out.bad
702 # check if we really should run it
703 _expunge_test $seqnum
704 if [ $? -eq 1 ]; then
709 # record that we really tried to run this test.
711 n_try=`expr $n_try + 1`
713 # slashes now in names, sed barfs on them so use grep
714 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
715 if [ "X$lasttime" != X ]; then
716 echo -n " ${lasttime}s ... "
718 echo -n " " # prettier output with timestamps.
720 rm -f core $seqres.notrun
723 $timestamp && echo -n " ["`date "+%T"`"]"
724 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
725 $LOGGER_PROG "run xfstest $seqnum"
726 if [ -w /dev/kmsg ]; then
727 export date_time=`date +"%F %T"`
728 echo "run fstests $seqnum at $date_time" > /dev/kmsg
729 # _check_dmesg depends on this log in dmesg
730 touch ${RESULT_DIR}/check_dmesg
732 if [ "$DUMP_OUTPUT" = true ]; then
733 ./$seq 2>&1 | tee $tmp.out
734 # Because $? would get tee's return code
737 ./$seq >$tmp.out 2>&1
742 _dump_err_cont "[dumped core]"
743 mv core $RESULT_BASE/$seqnum.core
747 if [ -f $seqres.notrun ]; then
748 $timestamp && _timestamp
750 $timestamp || echo -n "[not run] "
751 $timestamp && echo " [not run]" && \
752 echo -n " $seqnum -- "
754 notrun="$notrun $seqnum"
755 n_notrun=`expr $n_notrun + 1`
760 if [ $sts -ne 0 ]; then
761 _dump_err_cont "[failed, exit status $sts]"
762 _test_unmount 2> /dev/null
763 _scratch_unmount 2> /dev/null
766 # the test apparently passed, so check for corruption
767 # and log messages that shouldn't be there.
769 _check_dmesg || err=true
770 _check_kmemleak || err=true
773 # test ends after all checks are done.
774 $timestamp && _timestamp
777 if [ ! -f $seq.out ]; then
778 _dump_err "no qualified output"
783 # coreutils 8.16+ changed quote formats in error messages
784 # from `foo' to 'foo'. Filter old versions to match the new
786 sed -i "s/\`/\'/g" $tmp.out
787 if diff $seq.out $tmp.out >/dev/null 2>&1 ; then
789 echo "$seqnum `expr $stop - $start`" >>$tmp.time
790 echo -n " `expr $stop - $start`s"
794 _dump_err "- output mismatch (see $seqres.out.bad)"
795 mv $tmp.out $seqres.out.bad
796 $diff $seq.out $seqres.out.bad | {
797 if test "$DIFF_LENGTH" -le 0; then
800 head -n "$DIFF_LENGTH"
802 echo "(Run '$diff $here/$seq.out $seqres.out.bad'" \
803 " to see the entire diff)"
804 fi; } | sed -e 's/^\(.\)/ \1/'
809 # make sure we record the status of the last test we ran.
812 n_bad=`expr $n_bad + 1`
815 if $do_report && ! $first_test ; then
816 if [ $tc_status != "expunge" ] ; then
817 _make_testcase_report "$prev_seq" "$tc_status"
821 sect_stop=`_wallclock`
827 _test_unmount 2> /dev/null
828 _scratch_unmount 2> /dev/null
832 status=`expr $sum_bad != 0`