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
505 if $OPTIONS_HAVE_SECTIONS; then
506 trap "_summary; exit \$status" 0 1 2 3 15
508 trap "_wrapup; exit \$status" 0 1 2 3 15
511 for section in $HOST_OPTIONS_SECTIONS; do
513 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
514 get_next_config $section
516 # Do we need to run only some sections ?
517 if [ ! -z "$RUN_SECTION" ]; then
519 for s in $RUN_SECTION; do
520 if [ $section == $s ]; then
530 # Did this section get excluded?
531 if [ ! -z "$EXCLUDE_SECTION" ]; then
533 for s in $EXCLUDE_SECTION; do
534 if [ $section == $s ]; then
544 mkdir -p $RESULT_BASE
545 if [ ! -d $RESULT_BASE ]; then
546 echo "failed to create results directory $RESULT_BASE"
551 if $OPTIONS_HAVE_SECTIONS; then
552 echo "SECTION -- $section"
555 sect_start=`_wallclock`
556 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
557 echo "RECREATING -- $FSTYP on $TEST_DEV"
558 _test_unmount 2> /dev/null
559 if ! _test_mkfs >$tmp.err 2>&1
561 echo "our local _test_mkfs routine ..."
563 echo "check: failed to mkfs \$TEST_DEV using specified options"
569 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
574 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
575 _test_unmount 2> /dev/null
578 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
587 check="$RESULT_BASE/check"
589 # don't leave old full output behind on a clean run
592 [ -f $check.time ] || touch $check.time
594 # print out our test configuration
595 echo "FSTYP -- `_full_fstyp_details`"
596 echo "PLATFORM -- `_full_platform_details`"
597 if [ ! -z "$SCRATCH_DEV" ]; then
598 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
599 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
604 if [ ! -z "$SCRATCH_DEV" ]; then
605 _scratch_unmount 2> /dev/null
606 # call the overridden mkfs - make sure the FS is built
607 # the same as we'll create it later.
609 if ! _scratch_mkfs >$tmp.err 2>&1
611 echo "our local _scratch_mkfs routine ..."
613 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
618 # call the overridden mount - make sure the FS mounts with
619 # the same options that we'll mount with later.
620 if ! _scratch_mount >$tmp.err 2>&1
622 echo "our local mount routine ..."
624 echo "check: failed to mount \$SCRATCH_DEV using specified options"
637 if [ ! -f $seq ]; then
638 # Try to get full name in case the user supplied only seq id
639 # and the test has a name. A bit of hassle to find really
640 # the test and not its sample output or helping files.
641 bname=$(basename $seq)
642 full_seq=$(find $(dirname $seq) -name $bname* -executable |
643 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
644 END { print shortest }')
645 if [ -f $full_seq ] \
646 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
651 # the filename for the test and the name output are different.
652 # we don't include the tests/ directory in the name output.
653 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
655 # Similarly, the result directory needs to replace the tests/
656 # part of the test location.
658 if $OPTIONS_HAVE_SECTIONS; then
659 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
660 REPORT_DIR="$RESULT_BASE/$section"
662 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
663 REPORT_DIR="$RESULT_BASE"
665 seqres="$REPORT_DIR/$seqnum"
672 _expunge_test $seqnum
673 if [ $? -eq 1 ]; then
679 n_notrun=`expr $n_notrun + 1`
681 _make_testcase_report "list"
686 if [ ! -f $seq ]; then
687 echo " - no such test?"
689 # really going to try and run this one
691 rm -f $seqres.out.bad
693 # check if we really should run it
694 _expunge_test $seqnum
695 if [ $? -eq 1 ]; then
699 # slashes now in names, sed barfs on them so use grep
700 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
701 if [ "X$lasttime" != X ]; then
702 echo -n " ${lasttime}s ..."
704 echo -n " " # prettier output with timestamps.
706 rm -f core $seqres.notrun
709 $timestamp && echo -n " ["`date "+%T"`"]"
710 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
711 $LOGGER_PROG "run xfstest $seqnum"
712 if [ -w /dev/kmsg ]; then
713 export date_time=`date +"%F %T"`
714 echo "run fstests $seqnum at $date_time" > /dev/kmsg
715 # _check_dmesg depends on this log in dmesg
716 touch ${RESULT_DIR}/check_dmesg
718 if [ "$DUMP_OUTPUT" = true ]; then
719 ./$seq 2>&1 | tee $tmp.rawout
720 # Because $? would get tee's return code
723 ./$seq >$tmp.rawout 2>&1
726 $timestamp && _timestamp
729 _fix_malloc <$tmp.rawout >$tmp.out
734 err_msg="[dumped core]"
736 mv core $RESULT_BASE/$seqnum.core
740 if [ -f $seqres.notrun ]
742 $timestamp || echo -n " [not run] "
743 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
745 notrun="$notrun $seqnum"
746 n_notrun=`expr $n_notrun + 1`
751 err_msg="[failed, exit status $sts]"
757 _dump_err "no qualified output"
761 # coreutils 8.16+ changed quote formats in error messages from
762 # `foo' to 'foo'. Filter old versions to match the new version.
763 sed -i "s/\`/\'/g" $tmp.out
764 if diff $seq.out $tmp.out >/dev/null 2>&1
770 echo "$seqnum `expr $stop - $start`" >>$tmp.time
771 echo -n " `expr $stop - $start`s"
775 echo " - output mismatch (see $seqres.out.bad)"
776 mv $tmp.out $seqres.out.bad
777 $diff $seq.out $seqres.out.bad | {
778 if test "$DIFF_LENGTH" -le 0; then
781 head -n "$DIFF_LENGTH"
783 echo "(Run '$diff $seq.out $seqres.out.bad'" \
784 " to see the entire diff)"
786 sed -e 's/^\(.\)/ \1/'
787 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
792 n_try=`expr $n_try + 1`
794 _check_dmesg || err=true
795 _check_kmemleak || err=true
800 # come here for each test, except when $showme is true
805 n_bad=`expr $n_bad + 1`
810 _make_testcase_report "$tc_status"
814 sect_stop=`_wallclock`
820 _test_unmount 2> /dev/null
821 _scratch_unmount 2> /dev/null
825 status=`expr $sum_bad`