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
39 brief_test_summary=false
43 # start the initialisation work now
46 export MSGVERB="text:action"
47 export QA_CHECK_FS=${QA_CHECK_FS:=true}
49 # number of diff lines from a failed test, 0 for whole output
50 export DIFF_LENGTH=${DIFF_LENGTH:=10}
52 # by default don't output timestamps
53 timestamp=${TIMESTAMP:=false}
55 rm -f $tmp.list $tmp.tmp $tmp.grep $here/$iam.out $tmp.xlist
57 SRC_GROUPS="generic shared"
58 export SRC_DIR="tests"
62 echo "Usage: $0 [options] [testlist]"'
70 -udiff show unified diff (default)
71 -n show me, do not run tests
73 -r randomize test order
74 -d dump test output to stdout
76 --large-fs optimise scratch device for large filesystems
77 -s section run only specified section from config file
78 -S section exclude the specified section from the config file
81 -g group[,group...] include tests from these groups
82 -x group[,group...] exclude tests from these groups
83 -X exclude_file exclude individual tests
84 -E external_file exclude individual tests
85 [testlist] include tests matching names in testlist
87 testlist argument is a list of tests in the form of <test dir>/<test name>.
89 <test dir> is a directory under tests that contains a group file,
90 with a list of the names of the tests in that directory.
92 <test name> may be either a specific test file name (e.g. xfs/001) or
93 a test file name match pattern (e.g. xfs/*).
95 group argument is either a name of a tests group to collect from all
96 the test dirs (e.g. quick) or a name of a tests group to collect from
97 a specific tests dir in the form of <test dir>/<group name> (e.g. xfs/quick).
99 exclude_file argument refers to a name of a file inside each test directory.
100 for every test dir where this file is found, the listed test names are
101 excluded from the list of tests to run from that test dir.
103 external_file argument is a path to a single file containing a list of tests
104 to exclude in the form of <test dir>/<test name>.
110 check -x stress xfs/*
111 check -X .exclude -g auto
112 check -E ~/.xfstests.exclude
122 test -s "$SRC_DIR/$d/group" || return 1
124 local grpl=$(sed -n < $SRC_DIR/$d/group \
127 -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p")
135 local sub=$(dirname $grp)
137 if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then
138 # group is given as <subdir>/<group> (e.g. xfs/quick)
140 get_sub_group_list $sub $grp
144 for d in $SRC_GROUPS $FSTYP; do
145 if ! test -d "$SRC_DIR/$d" ; then
148 grpl="$grpl $(get_sub_group_list $d $grp)"
153 # Find all tests, excluding files that are test metadata such as group files.
154 # It matches test names against $VALID_TEST_NAME defined in common/rc
158 for d in $SRC_GROUPS $FSTYP; do
159 if ! test -d "$SRC_DIR/$d" ; then
164 grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \
165 grep -v "group\|Makefile" >> $tmp.list 2>/dev/null
169 # takes the list of tests to run in $tmp.list, and removes the tests passed to
170 # the function from that list.
179 if [ $numsed -gt 100 ]; then
180 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
181 mv $tmp.tmp $tmp.list
185 echo "^$t\$" >>$tmp.grep
186 numsed=`expr $numsed + 1`
188 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
189 mv $tmp.tmp $tmp.list
207 # Tests specified on the command line
208 if [ -s $tmp.arglist ]; then
209 cat $tmp.arglist > $tmp.list
214 # Specified groups to include
215 for group in $GROUP_LIST; do
216 list=$(get_group_list $group)
217 if [ -z "$list" ]; then
218 echo "Group \"$group\" is empty or not defined?"
223 grep -s "^$t\$" $tmp.list >/dev/null || \
224 echo "$t" >>$tmp.list
228 if ! $have_test_arg && [ -z "$GROUP_LIST" ]; then
229 # no test numbers, do everything
233 # Specified groups to exclude
234 for xgroup in $XGROUP_LIST; do
235 list=$(get_group_list $xgroup)
236 if [ -z "$list" ]; then
237 echo "Group \"$xgroup\" is empty or not defined?"
244 # sort the list of tests into numeric order
245 list=`sort -n $tmp.list | uniq`
246 rm -f $tmp.list $tmp.tmp $tmp.grep
250 list=`echo $list | awk -f randomize.awk`
254 # Process command arguments first.
255 while [ $# -gt 0 ]; do
257 -\? | -h | --help) usage ;;
261 -overlay) FSTYP=overlay ;;
262 -tmpfs) FSTYP=tmpfs ;;
264 -g) group=$2 ; shift ;
265 GROUP_LIST="$GROUP_LIST ${group//,/ }"
268 -x) xgroup=$2 ; shift ;
269 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
272 -X) xfile=$2; shift ;
273 for d in $SRC_GROUPS $FSTYP; do
274 [ -f $SRC_DIR/$d/$xfile ] || continue
275 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
276 echo $d/$f >> $tmp.xlist
280 -E) xfile=$2; shift ;
281 if [ -f $xfile ]; then
282 sed "s/#.*$//" "$xfile" >> $tmp.xlist
285 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
286 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
288 -udiff) diff="$diff -u" ;;
291 -r) randomize=true ;;
293 -T) timestamp=true ;;
294 -d) DUMP_OUTPUT=true ;;
295 -b) brief_test_summary=true;;
297 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
298 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
301 *) # not an argument, we've got tests now.
302 have_test_arg=true ;;
305 # if we've found a test specification, the break out of the processing
306 # loop before we shift the arguments so that this is the first argument
307 # that we process in the test arg loop below.
308 if $have_test_arg; then
315 # we need common/config, source it after processing args, overlay needs FSTYP
316 # set before sourcing common/config
317 if ! . ./common/config; then
318 echo "$iam: failed to source common/config"
322 # Process tests from command line now.
323 if $have_test_arg; then
324 while [ $# -gt 0 ]; do
326 -*) echo "Arguments before tests, please!"
330 *) # Expand test pattern (e.g. xfs/???, *fs/001)
331 list=$(cd $SRC_DIR; echo $1)
333 test_dir=`dirname $t`
334 test_dir=${test_dir#$SRC_DIR/*}
335 test_name=`basename $t`
336 group_file=$SRC_DIR/$test_dir/group
338 if egrep -q "^$test_name" $group_file; then
339 # in group file ... OK
340 echo $SRC_DIR/$test_dir/$test_name \
344 echo "$t - unknown test, ignored"
357 echo "check: failed to source common/rc"
363 echo "check: QA must be run as root"
377 check="$RESULT_BASE/check"
382 if [ -f $check.time -a -f $tmp.time ]; then
383 cat $check.time $tmp.time \
388 for (i in t) print i " " t[i]
392 mv $tmp.out $check.time
398 echo "SECTION -- $section" >>$tmp.summary
399 echo "=========================" >>$tmp.summary
400 if [ ! -z "$n_try" -a $n_try != 0 ]; then
401 if [ $brief_test_summary == "false" ]; then
403 echo "Ran:$try" >>$tmp.summary
405 echo "Ran:$try" >>$check.log
408 $interrupt && echo "Interrupted!" | tee -a $check.log
410 if [ ! -z "$notrun" ]; then
411 if [ $brief_test_summary == "false" ]; then
412 echo "Not run:$notrun"
413 echo "Not run:$notrun" >>$tmp.summary
415 echo "Not run:$notrun" >>$check.log
418 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
420 echo "Failed $n_bad of $n_try tests"
421 echo "Failures:$bad" >>$check.log
422 echo "Failed $n_bad of $n_try tests" >>$check.log
423 echo "Failures:$bad" >>$tmp.summary
424 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
426 echo "Passed all $n_try tests"
427 echo "Passed all $n_try tests" >>$check.log
428 echo "Passed all $n_try tests" >>$tmp.summary
430 echo "" >>$tmp.summary
434 sum_bad=`expr $sum_bad + $n_bad`
436 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
437 if ! $OPTIONS_HAVE_SECTIONS; then
448 count=`wc -L $tmp.summary | cut -f1 -d" "`
457 if [ -f ${RESULT_DIR}/require_test ]; then
458 _check_test_fs || err=true
459 rm -f ${RESULT_DIR}/require_test*
461 if [ -f ${RESULT_DIR}/require_scratch ]; then
462 _check_scratch_fs || err=true
463 rm -f ${RESULT_DIR}/require_scratch*
469 if $OPTIONS_HAVE_SECTIONS; then
470 trap "_summary; exit \$status" 0 1 2 3 15
472 trap "_wrapup; exit \$status" 0 1 2 3 15
475 for section in $HOST_OPTIONS_SECTIONS; do
477 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
478 get_next_config $section
480 # Do we need to run only some sections ?
481 if [ ! -z "$RUN_SECTION" ]; then
483 for s in $RUN_SECTION; do
484 if [ $section == $s ]; then
494 # Did this section get excluded?
495 if [ ! -z "$EXCLUDE_SECTION" ]; then
497 for s in $EXCLUDE_SECTION; do
498 if [ $section == $s ]; then
508 mkdir -p $RESULT_BASE
509 if [ ! -d $RESULT_BASE ]; then
510 echo "failed to create results directory $RESULT_BASE"
515 if $OPTIONS_HAVE_SECTIONS; then
516 echo "SECTION -- $section"
519 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
520 echo "RECREATING -- $FSTYP on $TEST_DEV"
521 _test_unmount 2> /dev/null
522 if ! _test_mkfs >$tmp.err 2>&1
524 echo "our local _test_mkfs routine ..."
526 echo "check: failed to mkfs \$TEST_DEV using specified options"
532 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
537 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
538 _test_unmount 2> /dev/null
541 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
550 check="$RESULT_BASE/check"
552 # don't leave old full output behind on a clean run
555 [ -f $check.time ] || touch $check.time
557 # print out our test configuration
558 echo "FSTYP -- `_full_fstyp_details`"
559 echo "PLATFORM -- `_full_platform_details`"
560 if [ ! -z "$SCRATCH_DEV" ]; then
561 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
562 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
567 if [ ! -z "$SCRATCH_DEV" ]; then
568 _scratch_unmount 2> /dev/null
569 # call the overridden mkfs - make sure the FS is built
570 # the same as we'll create it later.
572 if ! _scratch_mkfs >$tmp.err 2>&1
574 echo "our local _scratch_mkfs routine ..."
576 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
581 # call the overridden mount - make sure the FS mounts with
582 # the same options that we'll mount with later.
583 if ! _scratch_mount >$tmp.err 2>&1
585 echo "our local mount routine ..."
587 echo "check: failed to mount \$SCRATCH_DEV using specified options"
599 if [ ! -f $seq ]; then
600 # Try to get full name in case the user supplied only seq id
601 # and the test has a name. A bit of hassle to find really
602 # the test and not its sample output or helping files.
603 bname=$(basename $seq)
604 full_seq=$(find $(dirname $seq) -name $bname* -executable |
605 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
606 END { print shortest }')
607 if [ -f $full_seq ] \
608 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
613 # the filename for the test and the name output are different.
614 # we don't include the tests/ directory in the name output.
615 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
617 # Similarly, the result directory needs to replace the tests/
618 # part of the test location.
620 if $OPTIONS_HAVE_SECTIONS; then
621 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
622 seqres="$RESULT_BASE/$section/$seqnum"
624 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
625 seqres="$RESULT_BASE/$seqnum"
637 if [ ! -f $seq ]; then
638 echo " - no such test?"
640 # really going to try and run this one
642 rm -f $seqres.out.bad
644 # check if we really should run it
645 if [ -s $tmp.xlist ]; then
646 if grep $seqnum $tmp.xlist > /dev/null 2>&1 ; then
652 # slashes now in names, sed barfs on them so use grep
653 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
654 if [ "X$lasttime" != X ]; then
655 echo -n " ${lasttime}s ..."
657 echo -n " " # prettier output with timestamps.
659 rm -f core $seqres.notrun
662 $timestamp && echo -n " ["`date "+%T"`"]"
663 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
664 $LOGGER_PROG "run xfstest $seqnum"
665 if [ -w /dev/kmsg ]; then
666 export date_time=`date +"%F %T"`
667 echo "run fstests $seqnum at $date_time" > /dev/kmsg
668 # _check_dmesg depends on this log in dmesg
669 touch ${RESULT_DIR}/check_dmesg
671 if [ "$DUMP_OUTPUT" = true ]; then
672 ./$seq 2>&1 | tee $tmp.rawout
673 # Because $? would get tee's return code
676 ./$seq >$tmp.rawout 2>&1
679 $timestamp && _timestamp
682 _fix_malloc <$tmp.rawout >$tmp.out
687 echo -n " [dumped core]"
688 mv core $RESULT_BASE/$seqnum.core
692 if [ -f $seqres.notrun ]
694 $timestamp || echo -n " [not run] "
695 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
697 notrun="$notrun $seqnum"
701 echo -n " [failed, exit status $sts]"
706 echo " - no qualified output"
710 # coreutils 8.16+ changed quote formats in error messages from
711 # `foo' to 'foo'. Filter old versions to match the new version.
712 sed -i "s/\`/\'/g" $tmp.out
713 if diff $seq.out $tmp.out >/dev/null 2>&1
719 echo "$seqnum `expr $stop - $start`" >>$tmp.time
720 echo -n " `expr $stop - $start`s"
724 echo " - output mismatch (see $seqres.out.bad)"
725 mv $tmp.out $seqres.out.bad
726 $diff $seq.out $seqres.out.bad | {
727 if test "$DIFF_LENGTH" -le 0; then
730 head -n "$DIFF_LENGTH"
732 echo "(Run '$diff $seq.out $seqres.out.bad'" \
733 " to see the entire diff)"
735 sed -e 's/^\(.\)/ \1/'
740 n_try=`expr $n_try + 1`
742 _check_dmesg || err=true
747 # come here for each test, except when $showme is true
752 n_bad=`expr $n_bad + 1`
763 _test_unmount 2> /dev/null
764 _scratch_unmount 2> /dev/null
768 status=`expr $sum_bad`