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).
105 If you want to run all the tests in the test suite, use "-g all" to specify all
108 exclude_file argument refers to a name of a file inside each test directory.
109 for every test dir where this file is found, the listed test names are
110 excluded from the list of tests to run from that test dir.
112 external_file argument is a path to a single file containing a list of tests
113 to exclude in the form of <test dir>/<test name>.
119 check -x stress xfs/*
120 check -X .exclude -g auto
121 check -E ~/.xfstests.exclude
131 test -s "$SRC_DIR/$d/group" || return 1
133 local grpl=$(sed -n < $SRC_DIR/$d/group \
136 -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p")
144 local sub=$(dirname $grp)
146 if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then
147 # group is given as <subdir>/<group> (e.g. xfs/quick)
149 get_sub_group_list $sub $grp
153 for d in $SRC_GROUPS $FSTYP; do
154 if ! test -d "$SRC_DIR/$d" ; then
157 grpl="$grpl $(get_sub_group_list $d $grp)"
162 # Find all tests, excluding files that are test metadata such as group files.
163 # It matches test names against $VALID_TEST_NAME defined in common/rc
167 for d in $SRC_GROUPS $FSTYP; do
168 if ! test -d "$SRC_DIR/$d" ; then
173 grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \
174 grep -v "group\|Makefile" >> $tmp.list 2>/dev/null
178 # takes the list of tests to run in $tmp.list, and removes the tests passed to
179 # the function from that list.
188 if [ $numsed -gt 100 ]; then
189 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
190 mv $tmp.tmp $tmp.list
194 echo "^$t\$" >>$tmp.grep
195 numsed=`expr $numsed + 1`
197 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
198 mv $tmp.tmp $tmp.list
217 # Tests specified on the command line
218 if [ -s $tmp.arglist ]; then
219 cat $tmp.arglist > $tmp.list
224 # Specified groups to include
225 # Note that the CLI processing adds a leading space to the first group
226 # parameter, so we have to catch that here checking for "all"
227 if ! $have_test_arg && [ "$GROUP_LIST" == " all" ]; then
228 # no test numbers, do everything
231 for group in $GROUP_LIST; do
232 list=$(get_group_list $group)
233 if [ -z "$list" ]; then
234 echo "Group \"$group\" is empty or not defined?"
239 grep -s "^$t\$" $tmp.list >/dev/null || \
240 echo "$t" >>$tmp.list
245 # Specified groups to exclude
246 for xgroup in $XGROUP_LIST; do
247 list=$(get_group_list $xgroup)
248 if [ -z "$list" ]; then
249 echo "Group \"$xgroup\" is empty or not defined?"
256 # sort the list of tests into numeric order
257 list=`sort -n $tmp.list | uniq`
262 list=`echo $list | awk -f randomize.awk`
266 # Process command arguments first.
267 while [ $# -gt 0 ]; do
269 -\? | -h | --help) usage ;;
272 -glusterfs) FSTYP=glusterfs ;;
275 -overlay) FSTYP=overlay; export OVERLAY=true ;;
276 -pvfs2) FSTYP=pvfs2 ;;
277 -tmpfs) FSTYP=tmpfs ;;
278 -ubifs) FSTYP=ubifs ;;
280 -g) group=$2 ; shift ;
281 GROUP_LIST="$GROUP_LIST ${group//,/ }"
284 -x) xgroup=$2 ; shift ;
285 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
288 -X) xfile=$2; shift ;
289 for d in $SRC_GROUPS $FSTYP; do
290 [ -f $SRC_DIR/$d/$xfile ] || continue
291 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
292 echo $d/$f >> $tmp.xlist
296 -E) xfile=$2; shift ;
297 if [ -f $xfile ]; then
298 sed "s/#.*$//" "$xfile" >> $tmp.xlist
301 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
302 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
304 -udiff) diff="$diff -u" ;;
307 -r) randomize=true ;;
309 -T) timestamp=true ;;
310 -d) DUMP_OUTPUT=true ;;
311 -b) brief_test_summary=true;;
312 -R) report_fmt=$2 ; shift ;
313 REPORT_LIST="$REPORT_LIST ${report_fmt//,/ }"
316 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
317 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
320 *) # not an argument, we've got tests now.
321 have_test_arg=true ;;
324 # if we've found a test specification, the break out of the processing
325 # loop before we shift the arguments so that this is the first argument
326 # that we process in the test arg loop below.
327 if $have_test_arg; then
334 # we need common/rc, that also sources common/config. We need to source it
335 # after processing args, overlay needs FSTYP set before sourcing common/config
336 if ! . ./common/rc; then
337 echo "check: failed to source common/rc"
341 # Process tests from command line now.
342 if $have_test_arg; then
343 while [ $# -gt 0 ]; do
345 -*) echo "Arguments before tests, please!"
349 *) # Expand test pattern (e.g. xfs/???, *fs/001)
350 list=$(cd $SRC_DIR; echo $1)
352 test_dir=`dirname $t`
353 test_dir=${test_dir#$SRC_DIR/*}
354 test_name=`basename $t`
355 group_file=$SRC_DIR/$test_dir/group
357 if egrep -q "^$test_name" $group_file; then
358 # in group file ... OK
359 echo $SRC_DIR/$test_dir/$test_name \
363 echo "$t - unknown test, ignored"
371 elif [ -z "$GROUP_LIST" ]; then
372 # default group list is the auto group. If any other group or test is
373 # specified, we use that instead.
379 echo "check: QA must be run as root"
394 check="$RESULT_BASE/check"
404 if [ -f $check.time -a -f $tmp.time ]; then
405 cat $check.time $tmp.time \
410 for (i in t) print i " " t[i]
414 mv $tmp.out $check.time
420 echo "SECTION -- $section" >>$tmp.summary
421 echo "=========================" >>$tmp.summary
422 if [ ! -z "$n_try" -a $n_try != 0 ]; then
423 if [ $brief_test_summary == "false" ]; then
425 echo "Ran:$try" >>$tmp.summary
427 echo "Ran:$try" >>$check.log
430 $interrupt && echo "Interrupted!" | tee -a $check.log
432 if [ ! -z "$notrun" ]; then
433 if [ $brief_test_summary == "false" ]; then
434 echo "Not run:$notrun"
435 echo "Not run:$notrun" >>$tmp.summary
437 echo "Not run:$notrun" >>$check.log
440 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
442 echo "Failed $n_bad of $n_try tests"
443 echo "Failures:$bad" >>$check.log
444 echo "Failed $n_bad of $n_try tests" >>$check.log
445 echo "Failures:$bad" >>$tmp.summary
446 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
448 echo "Passed all $n_try tests"
449 echo "Passed all $n_try tests" >>$check.log
450 echo "Passed all $n_try tests" >>$tmp.summary
452 echo "" >>$tmp.summary
459 sum_bad=`expr $sum_bad + $n_bad`
461 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
462 if ! $OPTIONS_HAVE_SECTIONS; then
473 count=`wc -L $tmp.summary | cut -f1 -d" "`
482 if [ -f ${RESULT_DIR}/require_test ]; then
483 _check_test_fs || err=true
484 rm -f ${RESULT_DIR}/require_test*
486 _test_unmount 2> /dev/null
488 if [ -f ${RESULT_DIR}/require_scratch ]; then
489 _check_scratch_fs || err=true
490 rm -f ${RESULT_DIR}/require_scratch*
492 _scratch_unmount 2> /dev/null
499 if [ -s $tmp.xlist ]; then
500 if grep -q $TEST_ID $tmp.xlist; then
511 if $OPTIONS_HAVE_SECTIONS; then
512 trap "_summary; exit \$status" 0 1 2 3 15
514 trap "_wrapup; exit \$status" 0 1 2 3 15
517 for section in $HOST_OPTIONS_SECTIONS; do
519 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
520 get_next_config $section
522 # Do we need to run only some sections ?
523 if [ ! -z "$RUN_SECTION" ]; then
525 for s in $RUN_SECTION; do
526 if [ $section == $s ]; then
536 # Did this section get excluded?
537 if [ ! -z "$EXCLUDE_SECTION" ]; then
539 for s in $EXCLUDE_SECTION; do
540 if [ $section == $s ]; then
550 mkdir -p $RESULT_BASE
551 if [ ! -d $RESULT_BASE ]; then
552 echo "failed to create results directory $RESULT_BASE"
557 if $OPTIONS_HAVE_SECTIONS; then
558 echo "SECTION -- $section"
561 sect_start=`_wallclock`
562 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
563 echo "RECREATING -- $FSTYP on $TEST_DEV"
564 _test_unmount 2> /dev/null
565 if ! _test_mkfs >$tmp.err 2>&1
567 echo "our local _test_mkfs routine ..."
569 echo "check: failed to mkfs \$TEST_DEV using specified options"
575 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
580 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
581 _test_unmount 2> /dev/null
584 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
593 check="$RESULT_BASE/check"
595 # don't leave old full output behind on a clean run
598 [ -f $check.time ] || touch $check.time
600 # print out our test configuration
601 echo "FSTYP -- `_full_fstyp_details`"
602 echo "PLATFORM -- `_full_platform_details`"
603 if [ ! -z "$SCRATCH_DEV" ]; then
604 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
605 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
610 if [ ! -z "$SCRATCH_DEV" ]; then
611 _scratch_unmount 2> /dev/null
612 # call the overridden mkfs - make sure the FS is built
613 # the same as we'll create it later.
615 if ! _scratch_mkfs >$tmp.err 2>&1
617 echo "our local _scratch_mkfs routine ..."
619 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
624 # call the overridden mount - make sure the FS mounts with
625 # the same options that we'll mount with later.
626 if ! _scratch_mount >$tmp.err 2>&1
628 echo "our local mount routine ..."
630 echo "check: failed to mount \$SCRATCH_DEV using specified options"
643 if [ ! -f $seq ]; then
644 # Try to get full name in case the user supplied only seq id
645 # and the test has a name. A bit of hassle to find really
646 # the test and not its sample output or helping files.
647 bname=$(basename $seq)
648 full_seq=$(find $(dirname $seq) -name $bname* -executable |
649 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
650 END { print shortest }')
651 if [ -f $full_seq ] \
652 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
657 # the filename for the test and the name output are different.
658 # we don't include the tests/ directory in the name output.
659 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
661 # Similarly, the result directory needs to replace the tests/
662 # part of the test location.
664 if $OPTIONS_HAVE_SECTIONS; then
665 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
666 REPORT_DIR="$RESULT_BASE/$section"
668 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
669 REPORT_DIR="$RESULT_BASE"
671 seqres="$REPORT_DIR/$seqnum"
678 _expunge_test $seqnum
679 if [ $? -eq 1 ]; then
685 n_notrun=`expr $n_notrun + 1`
687 _make_testcase_report "list"
692 if [ ! -f $seq ]; then
693 echo " - no such test?"
695 # really going to try and run this one
697 rm -f $seqres.out.bad
699 # check if we really should run it
700 _expunge_test $seqnum
701 if [ $? -eq 1 ]; then
705 # slashes now in names, sed barfs on them so use grep
706 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
707 if [ "X$lasttime" != X ]; then
708 echo -n " ${lasttime}s ..."
710 echo -n " " # prettier output with timestamps.
712 rm -f core $seqres.notrun
715 $timestamp && echo -n " ["`date "+%T"`"]"
716 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
717 $LOGGER_PROG "run xfstest $seqnum"
718 if [ -w /dev/kmsg ]; then
719 export date_time=`date +"%F %T"`
720 echo "run fstests $seqnum at $date_time" > /dev/kmsg
721 # _check_dmesg depends on this log in dmesg
722 touch ${RESULT_DIR}/check_dmesg
724 if [ "$DUMP_OUTPUT" = true ]; then
725 ./$seq 2>&1 | tee $tmp.out
726 # Because $? would get tee's return code
729 ./$seq >$tmp.out 2>&1
732 $timestamp && _timestamp
737 _err_msg="[dumped core]"
739 mv core $RESULT_BASE/$seqnum.core
743 if [ -f $seqres.notrun ]
745 $timestamp || echo -n " [not run] "
746 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
748 notrun="$notrun $seqnum"
749 n_notrun=`expr $n_notrun + 1`
754 _err_msg="[failed, exit status $sts]"
760 _dump_err "no qualified output"
764 # coreutils 8.16+ changed quote formats in error messages from
765 # `foo' to 'foo'. Filter old versions to match the new version.
766 sed -i "s/\`/\'/g" $tmp.out
767 if diff $seq.out $tmp.out >/dev/null 2>&1
773 echo "$seqnum `expr $stop - $start`" >>$tmp.time
774 echo -n " `expr $stop - $start`s"
778 echo " - output mismatch (see $seqres.out.bad)"
779 mv $tmp.out $seqres.out.bad
780 $diff $seq.out $seqres.out.bad | {
781 if test "$DIFF_LENGTH" -le 0; then
784 head -n "$DIFF_LENGTH"
786 echo "(Run '$diff $seq.out $seqres.out.bad'" \
787 " to see the entire diff)"
789 sed -e 's/^\(.\)/ \1/'
790 _err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
795 n_try=`expr $n_try + 1`
797 _check_dmesg || err=true
798 _check_kmemleak || err=true
803 # come here for each test, except when $showme is true
808 n_bad=`expr $n_bad + 1`
812 _make_testcase_report "$tc_status"
816 sect_stop=`_wallclock`
822 _test_unmount 2> /dev/null
823 _scratch_unmount 2> /dev/null
827 status=`expr $sum_bad != 0`