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
59 SRC_GROUPS="generic shared"
60 export SRC_DIR="tests"
64 echo "Usage: $0 [options] [testlist]"'
72 -udiff show unified diff (default)
73 -n show me, do not run tests
75 -r randomize test order
76 -d dump test output to stdout
78 --large-fs optimise scratch device for large filesystems
79 -s section run only specified section from config file
80 -S section exclude the specified section from the config file
83 -g group[,group...] include tests from these groups
84 -x group[,group...] exclude tests from these groups
85 -X exclude_file exclude individual tests
86 -E external_file exclude individual tests
87 [testlist] include tests matching names in testlist
89 testlist argument is a list of tests in the form of <test dir>/<test name>.
91 <test dir> is a directory under tests that contains a group file,
92 with a list of the names of the tests in that directory.
94 <test name> may be either a specific test file name (e.g. xfs/001) or
95 a test file name match pattern (e.g. xfs/*).
97 group argument is either a name of a tests group to collect from all
98 the test dirs (e.g. quick) or a name of a tests group to collect from
99 a specific tests dir in the form of <test dir>/<group name> (e.g. xfs/quick).
101 exclude_file argument refers to a name of a file inside each test directory.
102 for every test dir where this file is found, the listed test names are
103 excluded from the list of tests to run from that test dir.
105 external_file argument is a path to a single file containing a list of tests
106 to exclude in the form of <test dir>/<test name>.
112 check -x stress xfs/*
113 check -X .exclude -g auto
114 check -E ~/.xfstests.exclude
124 test -s "$SRC_DIR/$d/group" || return 1
126 local grpl=$(sed -n < $SRC_DIR/$d/group \
129 -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p")
137 local sub=$(dirname $grp)
139 if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then
140 # group is given as <subdir>/<group> (e.g. xfs/quick)
142 get_sub_group_list $sub $grp
146 for d in $SRC_GROUPS $FSTYP; do
147 if ! test -d "$SRC_DIR/$d" ; then
150 grpl="$grpl $(get_sub_group_list $d $grp)"
155 # Find all tests, excluding files that are test metadata such as group files.
156 # It matches test names against $VALID_TEST_NAME defined in common/rc
160 for d in $SRC_GROUPS $FSTYP; do
161 if ! test -d "$SRC_DIR/$d" ; then
166 grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \
167 grep -v "group\|Makefile" >> $tmp.list 2>/dev/null
171 # takes the list of tests to run in $tmp.list, and removes the tests passed to
172 # the function from that list.
181 if [ $numsed -gt 100 ]; then
182 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
183 mv $tmp.tmp $tmp.list
187 echo "^$t\$" >>$tmp.grep
188 numsed=`expr $numsed + 1`
190 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
191 mv $tmp.tmp $tmp.list
209 # Tests specified on the command line
210 if [ -s $tmp.arglist ]; then
211 cat $tmp.arglist > $tmp.list
216 # Specified groups to include
217 for group in $GROUP_LIST; do
218 list=$(get_group_list $group)
219 if [ -z "$list" ]; then
220 echo "Group \"$group\" is empty or not defined?"
225 grep -s "^$t\$" $tmp.list >/dev/null || \
226 echo "$t" >>$tmp.list
230 if ! $have_test_arg && [ -z "$GROUP_LIST" ]; then
231 # no test numbers, do everything
235 # Specified groups to exclude
236 for xgroup in $XGROUP_LIST; do
237 list=$(get_group_list $xgroup)
238 if [ -z "$list" ]; then
239 echo "Group \"$xgroup\" is empty or not defined?"
246 # sort the list of tests into numeric order
247 list=`sort -n $tmp.list | uniq`
248 rm -f $tmp.list $tmp.tmp $tmp.grep
252 list=`echo $list | awk -f randomize.awk`
256 # Process command arguments first.
257 while [ $# -gt 0 ]; do
259 -\? | -h | --help) usage ;;
263 -overlay) FSTYP=overlay; export OVERLAY=true ;;
264 -tmpfs) FSTYP=tmpfs ;;
266 -g) group=$2 ; shift ;
267 GROUP_LIST="$GROUP_LIST ${group//,/ }"
270 -x) xgroup=$2 ; shift ;
271 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
274 -X) xfile=$2; shift ;
275 for d in $SRC_GROUPS $FSTYP; do
276 [ -f $SRC_DIR/$d/$xfile ] || continue
277 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
278 echo $d/$f >> $tmp.xlist
282 -E) xfile=$2; shift ;
283 if [ -f $xfile ]; then
284 sed "s/#.*$//" "$xfile" >> $tmp.xlist
287 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
288 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
290 -udiff) diff="$diff -u" ;;
293 -r) randomize=true ;;
295 -T) timestamp=true ;;
296 -d) DUMP_OUTPUT=true ;;
297 -b) brief_test_summary=true;;
299 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
300 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
303 *) # not an argument, we've got tests now.
304 have_test_arg=true ;;
307 # if we've found a test specification, the break out of the processing
308 # loop before we shift the arguments so that this is the first argument
309 # that we process in the test arg loop below.
310 if $have_test_arg; then
317 # we need common/config, source it after processing args, overlay needs FSTYP
318 # set before sourcing common/config
319 if ! . ./common/config; then
320 echo "$iam: failed to source common/config"
324 # Process tests from command line now.
325 if $have_test_arg; then
326 while [ $# -gt 0 ]; do
328 -*) echo "Arguments before tests, please!"
332 *) # Expand test pattern (e.g. xfs/???, *fs/001)
333 list=$(cd $SRC_DIR; echo $1)
335 test_dir=`dirname $t`
336 test_dir=${test_dir#$SRC_DIR/*}
337 test_name=`basename $t`
338 group_file=$SRC_DIR/$test_dir/group
340 if egrep -q "^$test_name" $group_file; then
341 # in group file ... OK
342 echo $SRC_DIR/$test_dir/$test_name \
346 echo "$t - unknown test, ignored"
359 echo "check: failed to source common/rc"
365 echo "check: QA must be run as root"
380 check="$RESULT_BASE/check"
385 if [ -f $check.time -a -f $tmp.time ]; then
386 cat $check.time $tmp.time \
391 for (i in t) print i " " t[i]
395 mv $tmp.out $check.time
401 echo "SECTION -- $section" >>$tmp.summary
402 echo "=========================" >>$tmp.summary
403 if [ ! -z "$n_try" -a $n_try != 0 ]; then
404 if [ $brief_test_summary == "false" ]; then
406 echo "Ran:$try" >>$tmp.summary
408 echo "Ran:$try" >>$check.log
411 $interrupt && echo "Interrupted!" | tee -a $check.log
413 if [ ! -z "$notrun" ]; then
414 if [ $brief_test_summary == "false" ]; then
415 echo "Not run:$notrun"
416 echo "Not run:$notrun" >>$tmp.summary
418 echo "Not run:$notrun" >>$check.log
421 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
423 echo "Failed $n_bad of $n_try tests"
424 echo "Failures:$bad" >>$check.log
425 echo "Failed $n_bad of $n_try tests" >>$check.log
426 echo "Failures:$bad" >>$tmp.summary
427 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
429 echo "Passed all $n_try tests"
430 echo "Passed all $n_try tests" >>$check.log
431 echo "Passed all $n_try tests" >>$tmp.summary
433 echo "" >>$tmp.summary
437 sum_bad=`expr $sum_bad + $n_bad`
439 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
440 if ! $OPTIONS_HAVE_SECTIONS; then
451 count=`wc -L $tmp.summary | cut -f1 -d" "`
460 if [ -f ${RESULT_DIR}/require_test ]; then
461 _check_test_fs || err=true
462 rm -f ${RESULT_DIR}/require_test*
464 if [ -f ${RESULT_DIR}/require_scratch ]; then
465 _check_scratch_fs || err=true
466 rm -f ${RESULT_DIR}/require_scratch*
472 if $OPTIONS_HAVE_SECTIONS; then
473 trap "_summary; exit \$status" 0 1 2 3 15
475 trap "_wrapup; exit \$status" 0 1 2 3 15
478 for section in $HOST_OPTIONS_SECTIONS; do
480 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
481 get_next_config $section
483 # Do we need to run only some sections ?
484 if [ ! -z "$RUN_SECTION" ]; then
486 for s in $RUN_SECTION; do
487 if [ $section == $s ]; then
497 # Did this section get excluded?
498 if [ ! -z "$EXCLUDE_SECTION" ]; then
500 for s in $EXCLUDE_SECTION; do
501 if [ $section == $s ]; then
511 mkdir -p $RESULT_BASE
512 if [ ! -d $RESULT_BASE ]; then
513 echo "failed to create results directory $RESULT_BASE"
518 if $OPTIONS_HAVE_SECTIONS; then
519 echo "SECTION -- $section"
522 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
523 echo "RECREATING -- $FSTYP on $TEST_DEV"
524 _test_unmount 2> /dev/null
525 if ! _test_mkfs >$tmp.err 2>&1
527 echo "our local _test_mkfs routine ..."
529 echo "check: failed to mkfs \$TEST_DEV using specified options"
535 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
540 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
541 _test_unmount 2> /dev/null
544 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
553 check="$RESULT_BASE/check"
555 # don't leave old full output behind on a clean run
558 [ -f $check.time ] || touch $check.time
560 # print out our test configuration
561 echo "FSTYP -- `_full_fstyp_details`"
562 echo "PLATFORM -- `_full_platform_details`"
563 if [ ! -z "$SCRATCH_DEV" ]; then
564 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
565 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
570 if [ ! -z "$SCRATCH_DEV" ]; then
571 _scratch_unmount 2> /dev/null
572 # call the overridden mkfs - make sure the FS is built
573 # the same as we'll create it later.
575 if ! _scratch_mkfs >$tmp.err 2>&1
577 echo "our local _scratch_mkfs routine ..."
579 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
584 # call the overridden mount - make sure the FS mounts with
585 # the same options that we'll mount with later.
586 if ! _scratch_mount >$tmp.err 2>&1
588 echo "our local mount routine ..."
590 echo "check: failed to mount \$SCRATCH_DEV using specified options"
603 if [ ! -f $seq ]; then
604 # Try to get full name in case the user supplied only seq id
605 # and the test has a name. A bit of hassle to find really
606 # the test and not its sample output or helping files.
607 bname=$(basename $seq)
608 full_seq=$(find $(dirname $seq) -name $bname* -executable |
609 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
610 END { print shortest }')
611 if [ -f $full_seq ] \
612 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
617 # the filename for the test and the name output are different.
618 # we don't include the tests/ directory in the name output.
619 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
621 # Similarly, the result directory needs to replace the tests/
622 # part of the test location.
624 if $OPTIONS_HAVE_SECTIONS; then
625 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
626 seqres="$RESULT_BASE/$section/$seqnum"
628 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
629 seqres="$RESULT_BASE/$seqnum"
640 n_notrun=`expr $n_notrun + 1`
644 if [ ! -f $seq ]; then
645 echo " - no such test?"
647 # really going to try and run this one
649 rm -f $seqres.out.bad
651 # check if we really should run it
652 if [ -s $tmp.xlist ]; then
653 if grep $seqnum $tmp.xlist > /dev/null 2>&1 ; then
659 # slashes now in names, sed barfs on them so use grep
660 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
661 if [ "X$lasttime" != X ]; then
662 echo -n " ${lasttime}s ..."
664 echo -n " " # prettier output with timestamps.
666 rm -f core $seqres.notrun
669 $timestamp && echo -n " ["`date "+%T"`"]"
670 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
671 $LOGGER_PROG "run xfstest $seqnum"
672 if [ -w /dev/kmsg ]; then
673 export date_time=`date +"%F %T"`
674 echo "run fstests $seqnum at $date_time" > /dev/kmsg
675 # _check_dmesg depends on this log in dmesg
676 touch ${RESULT_DIR}/check_dmesg
678 if [ "$DUMP_OUTPUT" = true ]; then
679 ./$seq 2>&1 | tee $tmp.rawout
680 # Because $? would get tee's return code
683 ./$seq >$tmp.rawout 2>&1
686 $timestamp && _timestamp
689 _fix_malloc <$tmp.rawout >$tmp.out
694 err_msg="[dumped core]"
696 mv core $RESULT_BASE/$seqnum.core
700 if [ -f $seqres.notrun ]
702 $timestamp || echo -n " [not run] "
703 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
705 notrun="$notrun $seqnum"
706 n_notrun=`expr $n_notrun + 1`
710 err_msg="[failed, exit status $sts]"
716 _dump_err "no qualified output"
720 # coreutils 8.16+ changed quote formats in error messages from
721 # `foo' to 'foo'. Filter old versions to match the new version.
722 sed -i "s/\`/\'/g" $tmp.out
723 if diff $seq.out $tmp.out >/dev/null 2>&1
729 echo "$seqnum `expr $stop - $start`" >>$tmp.time
730 echo -n " `expr $stop - $start`s"
734 echo " - output mismatch (see $seqres.out.bad)"
735 mv $tmp.out $seqres.out.bad
736 $diff $seq.out $seqres.out.bad | {
737 if test "$DIFF_LENGTH" -le 0; then
740 head -n "$DIFF_LENGTH"
742 echo "(Run '$diff $seq.out $seqres.out.bad'" \
743 " to see the entire diff)"
745 sed -e 's/^\(.\)/ \1/'
746 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
751 n_try=`expr $n_try + 1`
753 _check_dmesg || err=true
758 # come here for each test, except when $showme is true
763 n_bad=`expr $n_bad + 1`
774 _test_unmount 2> /dev/null
775 _scratch_unmount 2> /dev/null
779 status=`expr $sum_bad`