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*
492 if $OPTIONS_HAVE_SECTIONS; then
493 trap "_summary; exit \$status" 0 1 2 3 15
495 trap "_wrapup; exit \$status" 0 1 2 3 15
498 for section in $HOST_OPTIONS_SECTIONS; do
500 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
501 get_next_config $section
503 # Do we need to run only some sections ?
504 if [ ! -z "$RUN_SECTION" ]; then
506 for s in $RUN_SECTION; do
507 if [ $section == $s ]; then
517 # Did this section get excluded?
518 if [ ! -z "$EXCLUDE_SECTION" ]; then
520 for s in $EXCLUDE_SECTION; do
521 if [ $section == $s ]; then
531 mkdir -p $RESULT_BASE
532 if [ ! -d $RESULT_BASE ]; then
533 echo "failed to create results directory $RESULT_BASE"
538 if $OPTIONS_HAVE_SECTIONS; then
539 echo "SECTION -- $section"
542 sect_start=`_wallclock`
543 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
544 echo "RECREATING -- $FSTYP on $TEST_DEV"
545 _test_unmount 2> /dev/null
546 if ! _test_mkfs >$tmp.err 2>&1
548 echo "our local _test_mkfs routine ..."
550 echo "check: failed to mkfs \$TEST_DEV using specified options"
556 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
561 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
562 _test_unmount 2> /dev/null
565 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
574 check="$RESULT_BASE/check"
576 # don't leave old full output behind on a clean run
579 [ -f $check.time ] || touch $check.time
581 # print out our test configuration
582 echo "FSTYP -- `_full_fstyp_details`"
583 echo "PLATFORM -- `_full_platform_details`"
584 if [ ! -z "$SCRATCH_DEV" ]; then
585 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
586 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
591 if [ ! -z "$SCRATCH_DEV" ]; then
592 _scratch_unmount 2> /dev/null
593 # call the overridden mkfs - make sure the FS is built
594 # the same as we'll create it later.
596 if ! _scratch_mkfs >$tmp.err 2>&1
598 echo "our local _scratch_mkfs routine ..."
600 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
605 # call the overridden mount - make sure the FS mounts with
606 # the same options that we'll mount with later.
607 if ! _scratch_mount >$tmp.err 2>&1
609 echo "our local mount routine ..."
611 echo "check: failed to mount \$SCRATCH_DEV using specified options"
624 if [ ! -f $seq ]; then
625 # Try to get full name in case the user supplied only seq id
626 # and the test has a name. A bit of hassle to find really
627 # the test and not its sample output or helping files.
628 bname=$(basename $seq)
629 full_seq=$(find $(dirname $seq) -name $bname* -executable |
630 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
631 END { print shortest }')
632 if [ -f $full_seq ] \
633 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
638 # the filename for the test and the name output are different.
639 # we don't include the tests/ directory in the name output.
640 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
642 # Similarly, the result directory needs to replace the tests/
643 # part of the test location.
645 if $OPTIONS_HAVE_SECTIONS; then
646 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
647 REPORT_DIR="$RESULT_BASE/$section"
649 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
650 REPORT_DIR="$RESULT_BASE"
652 seqres="$REPORT_DIR/$seqnum"
662 n_notrun=`expr $n_notrun + 1`
664 _make_testcase_report "list"
669 if [ ! -f $seq ]; then
670 echo " - no such test?"
672 # really going to try and run this one
674 rm -f $seqres.out.bad
676 # check if we really should run it
677 if [ -s $tmp.xlist ]; then
678 if grep $seqnum $tmp.xlist > /dev/null 2>&1 ; then
684 # slashes now in names, sed barfs on them so use grep
685 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
686 if [ "X$lasttime" != X ]; then
687 echo -n " ${lasttime}s ..."
689 echo -n " " # prettier output with timestamps.
691 rm -f core $seqres.notrun
694 $timestamp && echo -n " ["`date "+%T"`"]"
695 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
696 $LOGGER_PROG "run xfstest $seqnum"
697 if [ -w /dev/kmsg ]; then
698 export date_time=`date +"%F %T"`
699 echo "run fstests $seqnum at $date_time" > /dev/kmsg
700 # _check_dmesg depends on this log in dmesg
701 touch ${RESULT_DIR}/check_dmesg
703 if [ "$DUMP_OUTPUT" = true ]; then
704 ./$seq 2>&1 | tee $tmp.rawout
705 # Because $? would get tee's return code
708 ./$seq >$tmp.rawout 2>&1
711 $timestamp && _timestamp
714 _fix_malloc <$tmp.rawout >$tmp.out
719 err_msg="[dumped core]"
721 mv core $RESULT_BASE/$seqnum.core
725 if [ -f $seqres.notrun ]
727 $timestamp || echo -n " [not run] "
728 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
730 notrun="$notrun $seqnum"
731 n_notrun=`expr $n_notrun + 1`
736 err_msg="[failed, exit status $sts]"
742 _dump_err "no qualified output"
746 # coreutils 8.16+ changed quote formats in error messages from
747 # `foo' to 'foo'. Filter old versions to match the new version.
748 sed -i "s/\`/\'/g" $tmp.out
749 if diff $seq.out $tmp.out >/dev/null 2>&1
755 echo "$seqnum `expr $stop - $start`" >>$tmp.time
756 echo -n " `expr $stop - $start`s"
760 echo " - output mismatch (see $seqres.out.bad)"
761 mv $tmp.out $seqres.out.bad
762 $diff $seq.out $seqres.out.bad | {
763 if test "$DIFF_LENGTH" -le 0; then
766 head -n "$DIFF_LENGTH"
768 echo "(Run '$diff $seq.out $seqres.out.bad'" \
769 " to see the entire diff)"
771 sed -e 's/^\(.\)/ \1/'
772 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
777 n_try=`expr $n_try + 1`
779 _check_dmesg || err=true
784 # come here for each test, except when $showme is true
789 n_bad=`expr $n_bad + 1`
794 _make_testcase_report "$tc_status"
798 sect_stop=`_wallclock`
804 _test_unmount 2> /dev/null
805 _scratch_unmount 2> /dev/null
809 status=`expr $sum_bad`