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
214 # Tests specified on the command line
215 if [ -s $tmp.arglist ]; then
216 cat $tmp.arglist > $tmp.list
221 # Specified groups to include
222 for group in $GROUP_LIST; do
223 list=$(get_group_list $group)
224 if [ -z "$list" ]; then
225 echo "Group \"$group\" is empty or not defined?"
230 grep -s "^$t\$" $tmp.list >/dev/null || \
231 echo "$t" >>$tmp.list
235 if ! $have_test_arg && [ -z "$GROUP_LIST" ]; then
236 # no test numbers, do everything
240 # Specified groups to exclude
241 for xgroup in $XGROUP_LIST; do
242 list=$(get_group_list $xgroup)
243 if [ -z "$list" ]; then
244 echo "Group \"$xgroup\" is empty or not defined?"
251 # sort the list of tests into numeric order
252 list=`sort -n $tmp.list | uniq`
253 rm -f $tmp.list $tmp.tmp $tmp.grep
257 list=`echo $list | awk -f randomize.awk`
261 # Process command arguments first.
262 while [ $# -gt 0 ]; do
264 -\? | -h | --help) usage ;;
267 -glusterfs) FSTYP=glusterfs ;;
270 -overlay) FSTYP=overlay; export OVERLAY=true ;;
271 -pvfs2) FSTYP=pvfs2 ;;
272 -tmpfs) FSTYP=tmpfs ;;
273 -ubifs) FSTYP=ubifs ;;
275 -g) group=$2 ; shift ;
276 GROUP_LIST="$GROUP_LIST ${group//,/ }"
279 -x) xgroup=$2 ; shift ;
280 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
283 -X) xfile=$2; shift ;
284 for d in $SRC_GROUPS $FSTYP; do
285 [ -f $SRC_DIR/$d/$xfile ] || continue
286 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
287 echo $d/$f >> $tmp.xlist
291 -E) xfile=$2; shift ;
292 if [ -f $xfile ]; then
293 sed "s/#.*$//" "$xfile" >> $tmp.xlist
296 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
297 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
299 -udiff) diff="$diff -u" ;;
302 -r) randomize=true ;;
304 -T) timestamp=true ;;
305 -d) DUMP_OUTPUT=true ;;
306 -b) brief_test_summary=true;;
307 -R) report_fmt=$2 ; shift ;
308 REPORT_LIST="$REPORT_LIST ${report_fmt//,/ }"
311 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
312 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
315 *) # not an argument, we've got tests now.
316 have_test_arg=true ;;
319 # if we've found a test specification, the break out of the processing
320 # loop before we shift the arguments so that this is the first argument
321 # that we process in the test arg loop below.
322 if $have_test_arg; then
329 # we need common/config, source it after processing args, overlay needs FSTYP
330 # set before sourcing common/config
331 if ! . ./common/config; then
332 echo "$iam: failed to source common/config"
336 # Process tests from command line now.
337 if $have_test_arg; then
338 while [ $# -gt 0 ]; do
340 -*) echo "Arguments before tests, please!"
344 *) # Expand test pattern (e.g. xfs/???, *fs/001)
345 list=$(cd $SRC_DIR; echo $1)
347 test_dir=`dirname $t`
348 test_dir=${test_dir#$SRC_DIR/*}
349 test_name=`basename $t`
350 group_file=$SRC_DIR/$test_dir/group
352 if egrep -q "^$test_name" $group_file; then
353 # in group file ... OK
354 echo $SRC_DIR/$test_dir/$test_name \
358 echo "$t - unknown test, ignored"
371 echo "check: failed to source common/rc"
377 echo "check: QA must be run as root"
392 check="$RESULT_BASE/check"
402 if [ -f $check.time -a -f $tmp.time ]; then
403 cat $check.time $tmp.time \
408 for (i in t) print i " " t[i]
412 mv $tmp.out $check.time
418 echo "SECTION -- $section" >>$tmp.summary
419 echo "=========================" >>$tmp.summary
420 if [ ! -z "$n_try" -a $n_try != 0 ]; then
421 if [ $brief_test_summary == "false" ]; then
423 echo "Ran:$try" >>$tmp.summary
425 echo "Ran:$try" >>$check.log
428 $interrupt && echo "Interrupted!" | tee -a $check.log
430 if [ ! -z "$notrun" ]; then
431 if [ $brief_test_summary == "false" ]; then
432 echo "Not run:$notrun"
433 echo "Not run:$notrun" >>$tmp.summary
435 echo "Not run:$notrun" >>$check.log
438 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
440 echo "Failed $n_bad of $n_try tests"
441 echo "Failures:$bad" >>$check.log
442 echo "Failed $n_bad of $n_try tests" >>$check.log
443 echo "Failures:$bad" >>$tmp.summary
444 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
446 echo "Passed all $n_try tests"
447 echo "Passed all $n_try tests" >>$check.log
448 echo "Passed all $n_try tests" >>$tmp.summary
450 echo "" >>$tmp.summary
457 sum_bad=`expr $sum_bad + $n_bad`
459 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
460 if ! $OPTIONS_HAVE_SECTIONS; then
471 count=`wc -L $tmp.summary | cut -f1 -d" "`
480 if [ -f ${RESULT_DIR}/require_test ]; then
481 _check_test_fs || err=true
482 rm -f ${RESULT_DIR}/require_test*
484 if [ -f ${RESULT_DIR}/require_scratch ]; then
485 _check_scratch_fs || err=true
486 rm -f ${RESULT_DIR}/require_scratch*
493 if [ -s $tmp.xlist ]; then
494 if grep -q $TEST_ID $tmp.xlist; then
504 if $OPTIONS_HAVE_SECTIONS; then
505 trap "_summary; exit \$status" 0 1 2 3 15
507 trap "_wrapup; exit \$status" 0 1 2 3 15
510 for section in $HOST_OPTIONS_SECTIONS; do
512 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
513 get_next_config $section
515 # Do we need to run only some sections ?
516 if [ ! -z "$RUN_SECTION" ]; then
518 for s in $RUN_SECTION; do
519 if [ $section == $s ]; then
529 # Did this section get excluded?
530 if [ ! -z "$EXCLUDE_SECTION" ]; then
532 for s in $EXCLUDE_SECTION; do
533 if [ $section == $s ]; then
543 mkdir -p $RESULT_BASE
544 if [ ! -d $RESULT_BASE ]; then
545 echo "failed to create results directory $RESULT_BASE"
550 if $OPTIONS_HAVE_SECTIONS; then
551 echo "SECTION -- $section"
554 sect_start=`_wallclock`
555 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
556 echo "RECREATING -- $FSTYP on $TEST_DEV"
557 _test_unmount 2> /dev/null
558 if ! _test_mkfs >$tmp.err 2>&1
560 echo "our local _test_mkfs routine ..."
562 echo "check: failed to mkfs \$TEST_DEV using specified options"
568 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
573 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
574 _test_unmount 2> /dev/null
577 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
586 check="$RESULT_BASE/check"
588 # don't leave old full output behind on a clean run
591 [ -f $check.time ] || touch $check.time
593 # print out our test configuration
594 echo "FSTYP -- `_full_fstyp_details`"
595 echo "PLATFORM -- `_full_platform_details`"
596 if [ ! -z "$SCRATCH_DEV" ]; then
597 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
598 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
603 if [ ! -z "$SCRATCH_DEV" ]; then
604 _scratch_unmount 2> /dev/null
605 # call the overridden mkfs - make sure the FS is built
606 # the same as we'll create it later.
608 if ! _scratch_mkfs >$tmp.err 2>&1
610 echo "our local _scratch_mkfs routine ..."
612 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
617 # call the overridden mount - make sure the FS mounts with
618 # the same options that we'll mount with later.
619 if ! _scratch_mount >$tmp.err 2>&1
621 echo "our local mount routine ..."
623 echo "check: failed to mount \$SCRATCH_DEV using specified options"
636 if [ ! -f $seq ]; then
637 # Try to get full name in case the user supplied only seq id
638 # and the test has a name. A bit of hassle to find really
639 # the test and not its sample output or helping files.
640 bname=$(basename $seq)
641 full_seq=$(find $(dirname $seq) -name $bname* -executable |
642 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
643 END { print shortest }')
644 if [ -f $full_seq ] \
645 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
650 # the filename for the test and the name output are different.
651 # we don't include the tests/ directory in the name output.
652 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
654 # Similarly, the result directory needs to replace the tests/
655 # part of the test location.
657 if $OPTIONS_HAVE_SECTIONS; then
658 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
659 REPORT_DIR="$RESULT_BASE/$section"
661 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
662 REPORT_DIR="$RESULT_BASE"
664 seqres="$REPORT_DIR/$seqnum"
671 _expunge_test $seqnum
672 if [ $? -eq 1 ]; then
678 n_notrun=`expr $n_notrun + 1`
680 _make_testcase_report "list"
685 if [ ! -f $seq ]; then
686 echo " - no such test?"
688 # really going to try and run this one
690 rm -f $seqres.out.bad
692 # check if we really should run it
693 _expunge_test $seqnum
694 if [ $? -eq 1 ]; then
698 # slashes now in names, sed barfs on them so use grep
699 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
700 if [ "X$lasttime" != X ]; then
701 echo -n " ${lasttime}s ..."
703 echo -n " " # prettier output with timestamps.
705 rm -f core $seqres.notrun
708 $timestamp && echo -n " ["`date "+%T"`"]"
709 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
710 $LOGGER_PROG "run xfstest $seqnum"
711 if [ -w /dev/kmsg ]; then
712 export date_time=`date +"%F %T"`
713 echo "run fstests $seqnum at $date_time" > /dev/kmsg
714 # _check_dmesg depends on this log in dmesg
715 touch ${RESULT_DIR}/check_dmesg
717 if [ "$DUMP_OUTPUT" = true ]; then
718 ./$seq 2>&1 | tee $tmp.rawout
719 # Because $? would get tee's return code
722 ./$seq >$tmp.rawout 2>&1
725 $timestamp && _timestamp
728 _fix_malloc <$tmp.rawout >$tmp.out
733 err_msg="[dumped core]"
735 mv core $RESULT_BASE/$seqnum.core
739 if [ -f $seqres.notrun ]
741 $timestamp || echo -n " [not run] "
742 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
744 notrun="$notrun $seqnum"
745 n_notrun=`expr $n_notrun + 1`
750 err_msg="[failed, exit status $sts]"
756 _dump_err "no qualified output"
760 # coreutils 8.16+ changed quote formats in error messages from
761 # `foo' to 'foo'. Filter old versions to match the new version.
762 sed -i "s/\`/\'/g" $tmp.out
763 if diff $seq.out $tmp.out >/dev/null 2>&1
769 echo "$seqnum `expr $stop - $start`" >>$tmp.time
770 echo -n " `expr $stop - $start`s"
774 echo " - output mismatch (see $seqres.out.bad)"
775 mv $tmp.out $seqres.out.bad
776 $diff $seq.out $seqres.out.bad | {
777 if test "$DIFF_LENGTH" -le 0; then
780 head -n "$DIFF_LENGTH"
782 echo "(Run '$diff $seq.out $seqres.out.bad'" \
783 " to see the entire diff)"
785 sed -e 's/^\(.\)/ \1/'
786 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
791 n_try=`expr $n_try + 1`
793 _check_dmesg || err=true
798 # come here for each test, except when $showme is true
803 n_bad=`expr $n_bad + 1`
808 _make_testcase_report "$tc_status"
812 sect_stop=`_wallclock`
818 _test_unmount 2> /dev/null
819 _scratch_unmount 2> /dev/null
823 status=`expr $sum_bad`