3 # Control script for QA
5 # Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved.
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License as
9 # published by the Free Software Foundation.
11 # This program is distributed in the hope that it would be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write the Free Software Foundation,
18 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
40 brief_test_summary=false
45 # start the initialisation work now
48 export MSGVERB="text:action"
49 export QA_CHECK_FS=${QA_CHECK_FS:=true}
51 # number of diff lines from a failed test, 0 for whole output
52 export DIFF_LENGTH=${DIFF_LENGTH:=10}
54 # by default don't output timestamps
55 timestamp=${TIMESTAMP:=false}
57 rm -f $tmp.list $tmp.tmp $tmp.grep $here/$iam.out $tmp.xlist $tmp.report.*
59 SRC_GROUPS="generic shared"
60 export SRC_DIR="tests"
64 echo "Usage: $0 [options] [testlist]"'
68 -glusterfs test GlusterFS
76 -udiff show unified diff (default)
77 -n show me, do not run tests
79 -r randomize test order
80 -d dump test output to stdout
82 -R fmt[,fmt] generate report in formats specified. Supported format: [xunit]
83 --large-fs optimise scratch device for large filesystems
84 -s section run only specified section from config file
85 -S section exclude the specified section from the config file
88 -g group[,group...] include tests from these groups
89 -x group[,group...] exclude tests from these groups
90 -X exclude_file exclude individual tests
91 -E external_file exclude individual tests
92 [testlist] include tests matching names in testlist
94 testlist argument is a list of tests in the form of <test dir>/<test name>.
96 <test dir> is a directory under tests that contains a group file,
97 with a list of the names of the tests in that directory.
99 <test name> may be either a specific test file name (e.g. xfs/001) or
100 a test file name match pattern (e.g. xfs/*).
102 group argument is either a name of a tests group to collect from all
103 the test dirs (e.g. quick) or a name of a tests group to collect from
104 a specific tests dir in the form of <test dir>/<group name> (e.g. xfs/quick).
106 exclude_file argument refers to a name of a file inside each test directory.
107 for every test dir where this file is found, the listed test names are
108 excluded from the list of tests to run from that test dir.
110 external_file argument is a path to a single file containing a list of tests
111 to exclude in the form of <test dir>/<test name>.
117 check -x stress xfs/*
118 check -X .exclude -g auto
119 check -E ~/.xfstests.exclude
129 test -s "$SRC_DIR/$d/group" || return 1
131 local grpl=$(sed -n < $SRC_DIR/$d/group \
134 -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p")
142 local sub=$(dirname $grp)
144 if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then
145 # group is given as <subdir>/<group> (e.g. xfs/quick)
147 get_sub_group_list $sub $grp
151 for d in $SRC_GROUPS $FSTYP; do
152 if ! test -d "$SRC_DIR/$d" ; then
155 grpl="$grpl $(get_sub_group_list $d $grp)"
160 # Find all tests, excluding files that are test metadata such as group files.
161 # It matches test names against $VALID_TEST_NAME defined in common/rc
165 for d in $SRC_GROUPS $FSTYP; do
166 if ! test -d "$SRC_DIR/$d" ; then
171 grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \
172 grep -v "group\|Makefile" >> $tmp.list 2>/dev/null
176 # takes the list of tests to run in $tmp.list, and removes the tests passed to
177 # the function from that list.
186 if [ $numsed -gt 100 ]; then
187 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
188 mv $tmp.tmp $tmp.list
192 echo "^$t\$" >>$tmp.grep
193 numsed=`expr $numsed + 1`
195 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
196 mv $tmp.tmp $tmp.list
215 # Tests specified on the command line
216 if [ -s $tmp.arglist ]; then
217 cat $tmp.arglist > $tmp.list
222 # Specified groups to include
223 for group in $GROUP_LIST; do
224 list=$(get_group_list $group)
225 if [ -z "$list" ]; then
226 echo "Group \"$group\" is empty or not defined?"
231 grep -s "^$t\$" $tmp.list >/dev/null || \
232 echo "$t" >>$tmp.list
236 if ! $have_test_arg && [ -z "$GROUP_LIST" ]; then
237 # no test numbers, do everything
241 # Specified groups to exclude
242 for xgroup in $XGROUP_LIST; do
243 list=$(get_group_list $xgroup)
244 if [ -z "$list" ]; then
245 echo "Group \"$xgroup\" is empty or not defined?"
252 # sort the list of tests into numeric order
253 list=`sort -n $tmp.list | uniq`
258 list=`echo $list | awk -f randomize.awk`
262 # Process command arguments first.
263 while [ $# -gt 0 ]; do
265 -\? | -h | --help) usage ;;
268 -glusterfs) FSTYP=glusterfs ;;
271 -overlay) FSTYP=overlay; export OVERLAY=true ;;
272 -pvfs2) FSTYP=pvfs2 ;;
273 -tmpfs) FSTYP=tmpfs ;;
274 -ubifs) FSTYP=ubifs ;;
276 -g) group=$2 ; shift ;
277 GROUP_LIST="$GROUP_LIST ${group//,/ }"
280 -x) xgroup=$2 ; shift ;
281 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
284 -X) xfile=$2; shift ;
285 for d in $SRC_GROUPS $FSTYP; do
286 [ -f $SRC_DIR/$d/$xfile ] || continue
287 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
288 echo $d/$f >> $tmp.xlist
292 -E) xfile=$2; shift ;
293 if [ -f $xfile ]; then
294 sed "s/#.*$//" "$xfile" >> $tmp.xlist
297 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
298 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
300 -udiff) diff="$diff -u" ;;
303 -r) randomize=true ;;
305 -T) timestamp=true ;;
306 -d) DUMP_OUTPUT=true ;;
307 -b) brief_test_summary=true;;
308 -R) report_fmt=$2 ; shift ;
309 REPORT_LIST="$REPORT_LIST ${report_fmt//,/ }"
312 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
313 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
316 *) # not an argument, we've got tests now.
317 have_test_arg=true ;;
320 # if we've found a test specification, the break out of the processing
321 # loop before we shift the arguments so that this is the first argument
322 # that we process in the test arg loop below.
323 if $have_test_arg; then
330 # we need common/config, source it after processing args, overlay needs FSTYP
331 # set before sourcing common/config
332 if ! . ./common/config; then
333 echo "$iam: failed to source common/config"
337 # Process tests from command line now.
338 if $have_test_arg; then
339 while [ $# -gt 0 ]; do
341 -*) echo "Arguments before tests, please!"
345 *) # Expand test pattern (e.g. xfs/???, *fs/001)
346 list=$(cd $SRC_DIR; echo $1)
348 test_dir=`dirname $t`
349 test_dir=${test_dir#$SRC_DIR/*}
350 test_name=`basename $t`
351 group_file=$SRC_DIR/$test_dir/group
353 if egrep -q "^$test_name" $group_file; then
354 # in group file ... OK
355 echo $SRC_DIR/$test_dir/$test_name \
359 echo "$t - unknown test, ignored"
372 echo "check: failed to source common/rc"
378 echo "check: QA must be run as root"
393 check="$RESULT_BASE/check"
403 if [ -f $check.time -a -f $tmp.time ]; then
404 cat $check.time $tmp.time \
409 for (i in t) print i " " t[i]
413 mv $tmp.out $check.time
419 echo "SECTION -- $section" >>$tmp.summary
420 echo "=========================" >>$tmp.summary
421 if [ ! -z "$n_try" -a $n_try != 0 ]; then
422 if [ $brief_test_summary == "false" ]; then
424 echo "Ran:$try" >>$tmp.summary
426 echo "Ran:$try" >>$check.log
429 $interrupt && echo "Interrupted!" | tee -a $check.log
431 if [ ! -z "$notrun" ]; then
432 if [ $brief_test_summary == "false" ]; then
433 echo "Not run:$notrun"
434 echo "Not run:$notrun" >>$tmp.summary
436 echo "Not run:$notrun" >>$check.log
439 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
441 echo "Failed $n_bad of $n_try tests"
442 echo "Failures:$bad" >>$check.log
443 echo "Failed $n_bad of $n_try tests" >>$check.log
444 echo "Failures:$bad" >>$tmp.summary
445 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
447 echo "Passed all $n_try tests"
448 echo "Passed all $n_try tests" >>$check.log
449 echo "Passed all $n_try tests" >>$tmp.summary
451 echo "" >>$tmp.summary
458 sum_bad=`expr $sum_bad + $n_bad`
460 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
461 if ! $OPTIONS_HAVE_SECTIONS; then
472 count=`wc -L $tmp.summary | cut -f1 -d" "`
481 if [ -f ${RESULT_DIR}/require_test ]; then
482 _check_test_fs || err=true
483 rm -f ${RESULT_DIR}/require_test*
485 if [ -f ${RESULT_DIR}/require_scratch ]; then
486 _check_scratch_fs || err=true
487 rm -f ${RESULT_DIR}/require_scratch*
494 if [ -s $tmp.xlist ]; then
495 if grep -q $TEST_ID $tmp.xlist; then
506 if $OPTIONS_HAVE_SECTIONS; then
507 trap "_summary; exit \$status" 0 1 2 3 15
509 trap "_wrapup; exit \$status" 0 1 2 3 15
512 for section in $HOST_OPTIONS_SECTIONS; do
514 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
515 get_next_config $section
517 # Do we need to run only some sections ?
518 if [ ! -z "$RUN_SECTION" ]; then
520 for s in $RUN_SECTION; do
521 if [ $section == $s ]; then
531 # Did this section get excluded?
532 if [ ! -z "$EXCLUDE_SECTION" ]; then
534 for s in $EXCLUDE_SECTION; do
535 if [ $section == $s ]; then
545 mkdir -p $RESULT_BASE
546 if [ ! -d $RESULT_BASE ]; then
547 echo "failed to create results directory $RESULT_BASE"
552 if $OPTIONS_HAVE_SECTIONS; then
553 echo "SECTION -- $section"
556 sect_start=`_wallclock`
557 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
558 echo "RECREATING -- $FSTYP on $TEST_DEV"
559 _test_unmount 2> /dev/null
560 if ! _test_mkfs >$tmp.err 2>&1
562 echo "our local _test_mkfs routine ..."
564 echo "check: failed to mkfs \$TEST_DEV using specified options"
570 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
575 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
576 _test_unmount 2> /dev/null
579 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
588 check="$RESULT_BASE/check"
590 # don't leave old full output behind on a clean run
593 [ -f $check.time ] || touch $check.time
595 # print out our test configuration
596 echo "FSTYP -- `_full_fstyp_details`"
597 echo "PLATFORM -- `_full_platform_details`"
598 if [ ! -z "$SCRATCH_DEV" ]; then
599 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
600 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
605 if [ ! -z "$SCRATCH_DEV" ]; then
606 _scratch_unmount 2> /dev/null
607 # call the overridden mkfs - make sure the FS is built
608 # the same as we'll create it later.
610 if ! _scratch_mkfs >$tmp.err 2>&1
612 echo "our local _scratch_mkfs routine ..."
614 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
619 # call the overridden mount - make sure the FS mounts with
620 # the same options that we'll mount with later.
621 if ! _scratch_mount >$tmp.err 2>&1
623 echo "our local mount routine ..."
625 echo "check: failed to mount \$SCRATCH_DEV using specified options"
638 if [ ! -f $seq ]; then
639 # Try to get full name in case the user supplied only seq id
640 # and the test has a name. A bit of hassle to find really
641 # the test and not its sample output or helping files.
642 bname=$(basename $seq)
643 full_seq=$(find $(dirname $seq) -name $bname* -executable |
644 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
645 END { print shortest }')
646 if [ -f $full_seq ] \
647 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
652 # the filename for the test and the name output are different.
653 # we don't include the tests/ directory in the name output.
654 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
656 # Similarly, the result directory needs to replace the tests/
657 # part of the test location.
659 if $OPTIONS_HAVE_SECTIONS; then
660 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
661 REPORT_DIR="$RESULT_BASE/$section"
663 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
664 REPORT_DIR="$RESULT_BASE"
666 seqres="$REPORT_DIR/$seqnum"
673 _expunge_test $seqnum
674 if [ $? -eq 1 ]; then
680 n_notrun=`expr $n_notrun + 1`
682 _make_testcase_report "list"
687 if [ ! -f $seq ]; then
688 echo " - no such test?"
690 # really going to try and run this one
692 rm -f $seqres.out.bad
694 # check if we really should run it
695 _expunge_test $seqnum
696 if [ $? -eq 1 ]; then
700 # slashes now in names, sed barfs on them so use grep
701 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
702 if [ "X$lasttime" != X ]; then
703 echo -n " ${lasttime}s ..."
705 echo -n " " # prettier output with timestamps.
707 rm -f core $seqres.notrun
710 $timestamp && echo -n " ["`date "+%T"`"]"
711 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
712 $LOGGER_PROG "run xfstest $seqnum"
713 if [ -w /dev/kmsg ]; then
714 export date_time=`date +"%F %T"`
715 echo "run fstests $seqnum at $date_time" > /dev/kmsg
716 # _check_dmesg depends on this log in dmesg
717 touch ${RESULT_DIR}/check_dmesg
719 if [ "$DUMP_OUTPUT" = true ]; then
720 ./$seq 2>&1 | tee $tmp.rawout
721 # Because $? would get tee's return code
724 ./$seq >$tmp.rawout 2>&1
727 $timestamp && _timestamp
730 _fix_malloc <$tmp.rawout >$tmp.out
735 err_msg="[dumped core]"
737 mv core $RESULT_BASE/$seqnum.core
741 if [ -f $seqres.notrun ]
743 $timestamp || echo -n " [not run] "
744 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
746 notrun="$notrun $seqnum"
747 n_notrun=`expr $n_notrun + 1`
752 err_msg="[failed, exit status $sts]"
758 _dump_err "no qualified output"
762 # coreutils 8.16+ changed quote formats in error messages from
763 # `foo' to 'foo'. Filter old versions to match the new version.
764 sed -i "s/\`/\'/g" $tmp.out
765 if diff $seq.out $tmp.out >/dev/null 2>&1
771 echo "$seqnum `expr $stop - $start`" >>$tmp.time
772 echo -n " `expr $stop - $start`s"
776 echo " - output mismatch (see $seqres.out.bad)"
777 mv $tmp.out $seqres.out.bad
778 $diff $seq.out $seqres.out.bad | {
779 if test "$DIFF_LENGTH" -le 0; then
782 head -n "$DIFF_LENGTH"
784 echo "(Run '$diff $seq.out $seqres.out.bad'" \
785 " to see the entire diff)"
787 sed -e 's/^\(.\)/ \1/'
788 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
793 n_try=`expr $n_try + 1`
795 _check_dmesg || err=true
796 _check_kmemleak || err=true
801 # come here for each test, except when $showme is true
806 n_bad=`expr $n_bad + 1`
810 _make_testcase_report "$tc_status"
814 sect_stop=`_wallclock`
820 _test_unmount 2> /dev/null
821 _scratch_unmount 2> /dev/null
825 status=`expr $sum_bad != 0`