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
73 -udiff show unified diff (default)
74 -n show me, do not run tests
76 -r randomize test order
77 -d dump test output to stdout
79 -R fmt[,fmt] generate report in formats specified. Supported format: [xunit]
80 --large-fs optimise scratch device for large filesystems
81 -s section run only specified section from config file
82 -S section exclude the specified section from the config file
85 -g group[,group...] include tests from these groups
86 -x group[,group...] exclude tests from these groups
87 -X exclude_file exclude individual tests
88 -E external_file exclude individual tests
89 [testlist] include tests matching names in testlist
91 testlist argument is a list of tests in the form of <test dir>/<test name>.
93 <test dir> is a directory under tests that contains a group file,
94 with a list of the names of the tests in that directory.
96 <test name> may be either a specific test file name (e.g. xfs/001) or
97 a test file name match pattern (e.g. xfs/*).
99 group argument is either a name of a tests group to collect from all
100 the test dirs (e.g. quick) or a name of a tests group to collect from
101 a specific tests dir in the form of <test dir>/<group name> (e.g. xfs/quick).
103 exclude_file argument refers to a name of a file inside each test directory.
104 for every test dir where this file is found, the listed test names are
105 excluded from the list of tests to run from that test dir.
107 external_file argument is a path to a single file containing a list of tests
108 to exclude in the form of <test dir>/<test name>.
114 check -x stress xfs/*
115 check -X .exclude -g auto
116 check -E ~/.xfstests.exclude
126 test -s "$SRC_DIR/$d/group" || return 1
128 local grpl=$(sed -n < $SRC_DIR/$d/group \
131 -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p")
139 local sub=$(dirname $grp)
141 if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then
142 # group is given as <subdir>/<group> (e.g. xfs/quick)
144 get_sub_group_list $sub $grp
148 for d in $SRC_GROUPS $FSTYP; do
149 if ! test -d "$SRC_DIR/$d" ; then
152 grpl="$grpl $(get_sub_group_list $d $grp)"
157 # Find all tests, excluding files that are test metadata such as group files.
158 # It matches test names against $VALID_TEST_NAME defined in common/rc
162 for d in $SRC_GROUPS $FSTYP; do
163 if ! test -d "$SRC_DIR/$d" ; then
168 grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \
169 grep -v "group\|Makefile" >> $tmp.list 2>/dev/null
173 # takes the list of tests to run in $tmp.list, and removes the tests passed to
174 # the function from that list.
183 if [ $numsed -gt 100 ]; then
184 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
185 mv $tmp.tmp $tmp.list
189 echo "^$t\$" >>$tmp.grep
190 numsed=`expr $numsed + 1`
192 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
193 mv $tmp.tmp $tmp.list
211 # Tests specified on the command line
212 if [ -s $tmp.arglist ]; then
213 cat $tmp.arglist > $tmp.list
218 # Specified groups to include
219 for group in $GROUP_LIST; do
220 list=$(get_group_list $group)
221 if [ -z "$list" ]; then
222 echo "Group \"$group\" is empty or not defined?"
227 grep -s "^$t\$" $tmp.list >/dev/null || \
228 echo "$t" >>$tmp.list
232 if ! $have_test_arg && [ -z "$GROUP_LIST" ]; then
233 # no test numbers, do everything
237 # Specified groups to exclude
238 for xgroup in $XGROUP_LIST; do
239 list=$(get_group_list $xgroup)
240 if [ -z "$list" ]; then
241 echo "Group \"$xgroup\" is empty or not defined?"
248 # sort the list of tests into numeric order
249 list=`sort -n $tmp.list | uniq`
250 rm -f $tmp.list $tmp.tmp $tmp.grep
254 list=`echo $list | awk -f randomize.awk`
258 # Process command arguments first.
259 while [ $# -gt 0 ]; do
261 -\? | -h | --help) usage ;;
264 -glusterfs) FSTYP=glusterfs ;;
266 -overlay) FSTYP=overlay; export OVERLAY=true ;;
267 -tmpfs) FSTYP=tmpfs ;;
269 -g) group=$2 ; shift ;
270 GROUP_LIST="$GROUP_LIST ${group//,/ }"
273 -x) xgroup=$2 ; shift ;
274 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
277 -X) xfile=$2; shift ;
278 for d in $SRC_GROUPS $FSTYP; do
279 [ -f $SRC_DIR/$d/$xfile ] || continue
280 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
281 echo $d/$f >> $tmp.xlist
285 -E) xfile=$2; shift ;
286 if [ -f $xfile ]; then
287 sed "s/#.*$//" "$xfile" >> $tmp.xlist
290 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
291 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
293 -udiff) diff="$diff -u" ;;
296 -r) randomize=true ;;
298 -T) timestamp=true ;;
299 -d) DUMP_OUTPUT=true ;;
300 -b) brief_test_summary=true;;
301 -R) report_fmt=$2 ; shift ;
302 REPORT_LIST="$REPORT_LIST ${report_fmt//,/ }"
305 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
306 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
309 *) # not an argument, we've got tests now.
310 have_test_arg=true ;;
313 # if we've found a test specification, the break out of the processing
314 # loop before we shift the arguments so that this is the first argument
315 # that we process in the test arg loop below.
316 if $have_test_arg; then
323 # we need common/config, source it after processing args, overlay needs FSTYP
324 # set before sourcing common/config
325 if ! . ./common/config; then
326 echo "$iam: failed to source common/config"
330 # Process tests from command line now.
331 if $have_test_arg; then
332 while [ $# -gt 0 ]; do
334 -*) echo "Arguments before tests, please!"
338 *) # Expand test pattern (e.g. xfs/???, *fs/001)
339 list=$(cd $SRC_DIR; echo $1)
341 test_dir=`dirname $t`
342 test_dir=${test_dir#$SRC_DIR/*}
343 test_name=`basename $t`
344 group_file=$SRC_DIR/$test_dir/group
346 if egrep -q "^$test_name" $group_file; then
347 # in group file ... OK
348 echo $SRC_DIR/$test_dir/$test_name \
352 echo "$t - unknown test, ignored"
365 echo "check: failed to source common/rc"
371 echo "check: QA must be run as root"
386 check="$RESULT_BASE/check"
396 if [ -f $check.time -a -f $tmp.time ]; then
397 cat $check.time $tmp.time \
402 for (i in t) print i " " t[i]
406 mv $tmp.out $check.time
412 echo "SECTION -- $section" >>$tmp.summary
413 echo "=========================" >>$tmp.summary
414 if [ ! -z "$n_try" -a $n_try != 0 ]; then
415 if [ $brief_test_summary == "false" ]; then
417 echo "Ran:$try" >>$tmp.summary
419 echo "Ran:$try" >>$check.log
422 $interrupt && echo "Interrupted!" | tee -a $check.log
424 if [ ! -z "$notrun" ]; then
425 if [ $brief_test_summary == "false" ]; then
426 echo "Not run:$notrun"
427 echo "Not run:$notrun" >>$tmp.summary
429 echo "Not run:$notrun" >>$check.log
432 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
434 echo "Failed $n_bad of $n_try tests"
435 echo "Failures:$bad" >>$check.log
436 echo "Failed $n_bad of $n_try tests" >>$check.log
437 echo "Failures:$bad" >>$tmp.summary
438 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
440 echo "Passed all $n_try tests"
441 echo "Passed all $n_try tests" >>$check.log
442 echo "Passed all $n_try tests" >>$tmp.summary
444 echo "" >>$tmp.summary
451 sum_bad=`expr $sum_bad + $n_bad`
453 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
454 if ! $OPTIONS_HAVE_SECTIONS; then
465 count=`wc -L $tmp.summary | cut -f1 -d" "`
474 if [ -f ${RESULT_DIR}/require_test ]; then
475 _check_test_fs || err=true
476 rm -f ${RESULT_DIR}/require_test*
478 if [ -f ${RESULT_DIR}/require_scratch ]; then
479 _check_scratch_fs || err=true
480 rm -f ${RESULT_DIR}/require_scratch*
486 if $OPTIONS_HAVE_SECTIONS; then
487 trap "_summary; exit \$status" 0 1 2 3 15
489 trap "_wrapup; exit \$status" 0 1 2 3 15
492 for section in $HOST_OPTIONS_SECTIONS; do
494 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
495 get_next_config $section
497 # Do we need to run only some sections ?
498 if [ ! -z "$RUN_SECTION" ]; then
500 for s in $RUN_SECTION; do
501 if [ $section == $s ]; then
511 # Did this section get excluded?
512 if [ ! -z "$EXCLUDE_SECTION" ]; then
514 for s in $EXCLUDE_SECTION; do
515 if [ $section == $s ]; then
525 mkdir -p $RESULT_BASE
526 if [ ! -d $RESULT_BASE ]; then
527 echo "failed to create results directory $RESULT_BASE"
532 if $OPTIONS_HAVE_SECTIONS; then
533 echo "SECTION -- $section"
536 sect_start=`_wallclock`
537 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
538 echo "RECREATING -- $FSTYP on $TEST_DEV"
539 _test_unmount 2> /dev/null
540 if ! _test_mkfs >$tmp.err 2>&1
542 echo "our local _test_mkfs routine ..."
544 echo "check: failed to mkfs \$TEST_DEV using specified options"
550 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
555 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
556 _test_unmount 2> /dev/null
559 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
568 check="$RESULT_BASE/check"
570 # don't leave old full output behind on a clean run
573 [ -f $check.time ] || touch $check.time
575 # print out our test configuration
576 echo "FSTYP -- `_full_fstyp_details`"
577 echo "PLATFORM -- `_full_platform_details`"
578 if [ ! -z "$SCRATCH_DEV" ]; then
579 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
580 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
585 if [ ! -z "$SCRATCH_DEV" ]; then
586 _scratch_unmount 2> /dev/null
587 # call the overridden mkfs - make sure the FS is built
588 # the same as we'll create it later.
590 if ! _scratch_mkfs >$tmp.err 2>&1
592 echo "our local _scratch_mkfs routine ..."
594 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
599 # call the overridden mount - make sure the FS mounts with
600 # the same options that we'll mount with later.
601 if ! _scratch_mount >$tmp.err 2>&1
603 echo "our local mount routine ..."
605 echo "check: failed to mount \$SCRATCH_DEV using specified options"
618 if [ ! -f $seq ]; then
619 # Try to get full name in case the user supplied only seq id
620 # and the test has a name. A bit of hassle to find really
621 # the test and not its sample output or helping files.
622 bname=$(basename $seq)
623 full_seq=$(find $(dirname $seq) -name $bname* -executable |
624 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
625 END { print shortest }')
626 if [ -f $full_seq ] \
627 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
632 # the filename for the test and the name output are different.
633 # we don't include the tests/ directory in the name output.
634 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
636 # Similarly, the result directory needs to replace the tests/
637 # part of the test location.
639 if $OPTIONS_HAVE_SECTIONS; then
640 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
641 REPORT_DIR="$RESULT_BASE/$section"
643 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
644 REPORT_DIR="$RESULT_BASE"
646 seqres="$REPORT_DIR/$seqnum"
656 n_notrun=`expr $n_notrun + 1`
658 _make_testcase_report "list"
663 if [ ! -f $seq ]; then
664 echo " - no such test?"
666 # really going to try and run this one
668 rm -f $seqres.out.bad
670 # check if we really should run it
671 if [ -s $tmp.xlist ]; then
672 if grep $seqnum $tmp.xlist > /dev/null 2>&1 ; then
678 # slashes now in names, sed barfs on them so use grep
679 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
680 if [ "X$lasttime" != X ]; then
681 echo -n " ${lasttime}s ..."
683 echo -n " " # prettier output with timestamps.
685 rm -f core $seqres.notrun
688 $timestamp && echo -n " ["`date "+%T"`"]"
689 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
690 $LOGGER_PROG "run xfstest $seqnum"
691 if [ -w /dev/kmsg ]; then
692 export date_time=`date +"%F %T"`
693 echo "run fstests $seqnum at $date_time" > /dev/kmsg
694 # _check_dmesg depends on this log in dmesg
695 touch ${RESULT_DIR}/check_dmesg
697 if [ "$DUMP_OUTPUT" = true ]; then
698 ./$seq 2>&1 | tee $tmp.rawout
699 # Because $? would get tee's return code
702 ./$seq >$tmp.rawout 2>&1
705 $timestamp && _timestamp
708 _fix_malloc <$tmp.rawout >$tmp.out
713 err_msg="[dumped core]"
715 mv core $RESULT_BASE/$seqnum.core
719 if [ -f $seqres.notrun ]
721 $timestamp || echo -n " [not run] "
722 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
724 notrun="$notrun $seqnum"
725 n_notrun=`expr $n_notrun + 1`
730 err_msg="[failed, exit status $sts]"
736 _dump_err "no qualified output"
740 # coreutils 8.16+ changed quote formats in error messages from
741 # `foo' to 'foo'. Filter old versions to match the new version.
742 sed -i "s/\`/\'/g" $tmp.out
743 if diff $seq.out $tmp.out >/dev/null 2>&1
749 echo "$seqnum `expr $stop - $start`" >>$tmp.time
750 echo -n " `expr $stop - $start`s"
754 echo " - output mismatch (see $seqres.out.bad)"
755 mv $tmp.out $seqres.out.bad
756 $diff $seq.out $seqres.out.bad | {
757 if test "$DIFF_LENGTH" -le 0; then
760 head -n "$DIFF_LENGTH"
762 echo "(Run '$diff $seq.out $seqres.out.bad'" \
763 " to see the entire diff)"
765 sed -e 's/^\(.\)/ \1/'
766 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
771 n_try=`expr $n_try + 1`
773 _check_dmesg || err=true
778 # come here for each test, except when $showme is true
783 n_bad=`expr $n_bad + 1`
788 _make_testcase_report "$tc_status"
792 sect_stop=`_wallclock`
798 _test_unmount 2> /dev/null
799 _scratch_unmount 2> /dev/null
803 status=`expr $sum_bad`