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
504 if $OPTIONS_HAVE_SECTIONS; then
505 trap "_summary; exit \$status" 0 1 2 3 15
507 trap "_wrapup; exit \$status" 0 1 2 3 15
510 for section in $HOST_OPTIONS_SECTIONS; do
512 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
513 get_next_config $section
515 # Do we need to run only some sections ?
516 if [ ! -z "$RUN_SECTION" ]; then
518 for s in $RUN_SECTION; do
519 if [ $section == $s ]; then
529 # Did this section get excluded?
530 if [ ! -z "$EXCLUDE_SECTION" ]; then
532 for s in $EXCLUDE_SECTION; do
533 if [ $section == $s ]; then
543 mkdir -p $RESULT_BASE
544 if [ ! -d $RESULT_BASE ]; then
545 echo "failed to create results directory $RESULT_BASE"
550 if $OPTIONS_HAVE_SECTIONS; then
551 echo "SECTION -- $section"
554 sect_start=`_wallclock`
555 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
556 echo "RECREATING -- $FSTYP on $TEST_DEV"
557 _test_unmount 2> /dev/null
558 if ! _test_mkfs >$tmp.err 2>&1
560 echo "our local _test_mkfs routine ..."
562 echo "check: failed to mkfs \$TEST_DEV using specified options"
568 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
573 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
574 _test_unmount 2> /dev/null
577 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
586 check="$RESULT_BASE/check"
588 # don't leave old full output behind on a clean run
591 [ -f $check.time ] || touch $check.time
593 # print out our test configuration
594 echo "FSTYP -- `_full_fstyp_details`"
595 echo "PLATFORM -- `_full_platform_details`"
596 if [ ! -z "$SCRATCH_DEV" ]; then
597 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
598 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
603 if [ ! -z "$SCRATCH_DEV" ]; then
604 _scratch_unmount 2> /dev/null
605 # call the overridden mkfs - make sure the FS is built
606 # the same as we'll create it later.
608 if ! _scratch_mkfs >$tmp.err 2>&1
610 echo "our local _scratch_mkfs routine ..."
612 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
617 # call the overridden mount - make sure the FS mounts with
618 # the same options that we'll mount with later.
619 if ! _scratch_mount >$tmp.err 2>&1
621 echo "our local mount routine ..."
623 echo "check: failed to mount \$SCRATCH_DEV using specified options"
636 if [ ! -f $seq ]; then
637 # Try to get full name in case the user supplied only seq id
638 # and the test has a name. A bit of hassle to find really
639 # the test and not its sample output or helping files.
640 bname=$(basename $seq)
641 full_seq=$(find $(dirname $seq) -name $bname* -executable |
642 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
643 END { print shortest }')
644 if [ -f $full_seq ] \
645 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
650 # the filename for the test and the name output are different.
651 # we don't include the tests/ directory in the name output.
652 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
654 # Similarly, the result directory needs to replace the tests/
655 # part of the test location.
657 if $OPTIONS_HAVE_SECTIONS; then
658 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
659 REPORT_DIR="$RESULT_BASE/$section"
661 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
662 REPORT_DIR="$RESULT_BASE"
664 seqres="$REPORT_DIR/$seqnum"
674 n_notrun=`expr $n_notrun + 1`
676 _make_testcase_report "list"
681 if [ ! -f $seq ]; then
682 echo " - no such test?"
684 # really going to try and run this one
686 rm -f $seqres.out.bad
688 # check if we really should run it
689 _expunge_test $seqnum
690 if [ $? -eq 1 ]; then
694 # slashes now in names, sed barfs on them so use grep
695 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
696 if [ "X$lasttime" != X ]; then
697 echo -n " ${lasttime}s ..."
699 echo -n " " # prettier output with timestamps.
701 rm -f core $seqres.notrun
704 $timestamp && echo -n " ["`date "+%T"`"]"
705 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
706 $LOGGER_PROG "run xfstest $seqnum"
707 if [ -w /dev/kmsg ]; then
708 export date_time=`date +"%F %T"`
709 echo "run fstests $seqnum at $date_time" > /dev/kmsg
710 # _check_dmesg depends on this log in dmesg
711 touch ${RESULT_DIR}/check_dmesg
713 if [ "$DUMP_OUTPUT" = true ]; then
714 ./$seq 2>&1 | tee $tmp.rawout
715 # Because $? would get tee's return code
718 ./$seq >$tmp.rawout 2>&1
721 $timestamp && _timestamp
724 _fix_malloc <$tmp.rawout >$tmp.out
729 err_msg="[dumped core]"
731 mv core $RESULT_BASE/$seqnum.core
735 if [ -f $seqres.notrun ]
737 $timestamp || echo -n " [not run] "
738 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
740 notrun="$notrun $seqnum"
741 n_notrun=`expr $n_notrun + 1`
746 err_msg="[failed, exit status $sts]"
752 _dump_err "no qualified output"
756 # coreutils 8.16+ changed quote formats in error messages from
757 # `foo' to 'foo'. Filter old versions to match the new version.
758 sed -i "s/\`/\'/g" $tmp.out
759 if diff $seq.out $tmp.out >/dev/null 2>&1
765 echo "$seqnum `expr $stop - $start`" >>$tmp.time
766 echo -n " `expr $stop - $start`s"
770 echo " - output mismatch (see $seqres.out.bad)"
771 mv $tmp.out $seqres.out.bad
772 $diff $seq.out $seqres.out.bad | {
773 if test "$DIFF_LENGTH" -le 0; then
776 head -n "$DIFF_LENGTH"
778 echo "(Run '$diff $seq.out $seqres.out.bad'" \
779 " to see the entire diff)"
781 sed -e 's/^\(.\)/ \1/'
782 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
787 n_try=`expr $n_try + 1`
789 _check_dmesg || err=true
794 # come here for each test, except when $showme is true
799 n_bad=`expr $n_bad + 1`
804 _make_testcase_report "$tc_status"
808 sect_stop=`_wallclock`
814 _test_unmount 2> /dev/null
815 _scratch_unmount 2> /dev/null
819 status=`expr $sum_bad`