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
74 -udiff show unified diff (default)
75 -n show me, do not run tests
77 -r randomize test order
78 -d dump test output to stdout
80 -R fmt[,fmt] generate report in formats specified. Supported format: [xunit]
81 --large-fs optimise scratch device for large filesystems
82 -s section run only specified section from config file
83 -S section exclude the specified section from the config file
86 -g group[,group...] include tests from these groups
87 -x group[,group...] exclude tests from these groups
88 -X exclude_file exclude individual tests
89 -E external_file exclude individual tests
90 [testlist] include tests matching names in testlist
92 testlist argument is a list of tests in the form of <test dir>/<test name>.
94 <test dir> is a directory under tests that contains a group file,
95 with a list of the names of the tests in that directory.
97 <test name> may be either a specific test file name (e.g. xfs/001) or
98 a test file name match pattern (e.g. xfs/*).
100 group argument is either a name of a tests group to collect from all
101 the test dirs (e.g. quick) or a name of a tests group to collect from
102 a specific tests dir in the form of <test dir>/<group name> (e.g. xfs/quick).
104 exclude_file argument refers to a name of a file inside each test directory.
105 for every test dir where this file is found, the listed test names are
106 excluded from the list of tests to run from that test dir.
108 external_file argument is a path to a single file containing a list of tests
109 to exclude in the form of <test dir>/<test name>.
115 check -x stress xfs/*
116 check -X .exclude -g auto
117 check -E ~/.xfstests.exclude
127 test -s "$SRC_DIR/$d/group" || return 1
129 local grpl=$(sed -n < $SRC_DIR/$d/group \
132 -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p")
140 local sub=$(dirname $grp)
142 if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then
143 # group is given as <subdir>/<group> (e.g. xfs/quick)
145 get_sub_group_list $sub $grp
149 for d in $SRC_GROUPS $FSTYP; do
150 if ! test -d "$SRC_DIR/$d" ; then
153 grpl="$grpl $(get_sub_group_list $d $grp)"
158 # Find all tests, excluding files that are test metadata such as group files.
159 # It matches test names against $VALID_TEST_NAME defined in common/rc
163 for d in $SRC_GROUPS $FSTYP; do
164 if ! test -d "$SRC_DIR/$d" ; then
169 grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \
170 grep -v "group\|Makefile" >> $tmp.list 2>/dev/null
174 # takes the list of tests to run in $tmp.list, and removes the tests passed to
175 # the function from that list.
184 if [ $numsed -gt 100 ]; then
185 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
186 mv $tmp.tmp $tmp.list
190 echo "^$t\$" >>$tmp.grep
191 numsed=`expr $numsed + 1`
193 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
194 mv $tmp.tmp $tmp.list
212 # Tests specified on the command line
213 if [ -s $tmp.arglist ]; then
214 cat $tmp.arglist > $tmp.list
219 # Specified groups to include
220 for group in $GROUP_LIST; do
221 list=$(get_group_list $group)
222 if [ -z "$list" ]; then
223 echo "Group \"$group\" is empty or not defined?"
228 grep -s "^$t\$" $tmp.list >/dev/null || \
229 echo "$t" >>$tmp.list
233 if ! $have_test_arg && [ -z "$GROUP_LIST" ]; then
234 # no test numbers, do everything
238 # Specified groups to exclude
239 for xgroup in $XGROUP_LIST; do
240 list=$(get_group_list $xgroup)
241 if [ -z "$list" ]; then
242 echo "Group \"$xgroup\" is empty or not defined?"
249 # sort the list of tests into numeric order
250 list=`sort -n $tmp.list | uniq`
251 rm -f $tmp.list $tmp.tmp $tmp.grep
255 list=`echo $list | awk -f randomize.awk`
259 # Process command arguments first.
260 while [ $# -gt 0 ]; do
262 -\? | -h | --help) usage ;;
265 -glusterfs) FSTYP=glusterfs ;;
267 -overlay) FSTYP=overlay; export OVERLAY=true ;;
268 -pvfs2) FSTYP=pvfs2 ;;
269 -tmpfs) FSTYP=tmpfs ;;
271 -g) group=$2 ; shift ;
272 GROUP_LIST="$GROUP_LIST ${group//,/ }"
275 -x) xgroup=$2 ; shift ;
276 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
279 -X) xfile=$2; shift ;
280 for d in $SRC_GROUPS $FSTYP; do
281 [ -f $SRC_DIR/$d/$xfile ] || continue
282 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
283 echo $d/$f >> $tmp.xlist
287 -E) xfile=$2; shift ;
288 if [ -f $xfile ]; then
289 sed "s/#.*$//" "$xfile" >> $tmp.xlist
292 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
293 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
295 -udiff) diff="$diff -u" ;;
298 -r) randomize=true ;;
300 -T) timestamp=true ;;
301 -d) DUMP_OUTPUT=true ;;
302 -b) brief_test_summary=true;;
303 -R) report_fmt=$2 ; shift ;
304 REPORT_LIST="$REPORT_LIST ${report_fmt//,/ }"
307 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
308 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
311 *) # not an argument, we've got tests now.
312 have_test_arg=true ;;
315 # if we've found a test specification, the break out of the processing
316 # loop before we shift the arguments so that this is the first argument
317 # that we process in the test arg loop below.
318 if $have_test_arg; then
325 # we need common/config, source it after processing args, overlay needs FSTYP
326 # set before sourcing common/config
327 if ! . ./common/config; then
328 echo "$iam: failed to source common/config"
332 # Process tests from command line now.
333 if $have_test_arg; then
334 while [ $# -gt 0 ]; do
336 -*) echo "Arguments before tests, please!"
340 *) # Expand test pattern (e.g. xfs/???, *fs/001)
341 list=$(cd $SRC_DIR; echo $1)
343 test_dir=`dirname $t`
344 test_dir=${test_dir#$SRC_DIR/*}
345 test_name=`basename $t`
346 group_file=$SRC_DIR/$test_dir/group
348 if egrep -q "^$test_name" $group_file; then
349 # in group file ... OK
350 echo $SRC_DIR/$test_dir/$test_name \
354 echo "$t - unknown test, ignored"
367 echo "check: failed to source common/rc"
373 echo "check: QA must be run as root"
388 check="$RESULT_BASE/check"
398 if [ -f $check.time -a -f $tmp.time ]; then
399 cat $check.time $tmp.time \
404 for (i in t) print i " " t[i]
408 mv $tmp.out $check.time
414 echo "SECTION -- $section" >>$tmp.summary
415 echo "=========================" >>$tmp.summary
416 if [ ! -z "$n_try" -a $n_try != 0 ]; then
417 if [ $brief_test_summary == "false" ]; then
419 echo "Ran:$try" >>$tmp.summary
421 echo "Ran:$try" >>$check.log
424 $interrupt && echo "Interrupted!" | tee -a $check.log
426 if [ ! -z "$notrun" ]; then
427 if [ $brief_test_summary == "false" ]; then
428 echo "Not run:$notrun"
429 echo "Not run:$notrun" >>$tmp.summary
431 echo "Not run:$notrun" >>$check.log
434 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
436 echo "Failed $n_bad of $n_try tests"
437 echo "Failures:$bad" >>$check.log
438 echo "Failed $n_bad of $n_try tests" >>$check.log
439 echo "Failures:$bad" >>$tmp.summary
440 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
442 echo "Passed all $n_try tests"
443 echo "Passed all $n_try tests" >>$check.log
444 echo "Passed all $n_try tests" >>$tmp.summary
446 echo "" >>$tmp.summary
453 sum_bad=`expr $sum_bad + $n_bad`
455 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
456 if ! $OPTIONS_HAVE_SECTIONS; then
467 count=`wc -L $tmp.summary | cut -f1 -d" "`
476 if [ -f ${RESULT_DIR}/require_test ]; then
477 _check_test_fs || err=true
478 rm -f ${RESULT_DIR}/require_test*
480 if [ -f ${RESULT_DIR}/require_scratch ]; then
481 _check_scratch_fs || err=true
482 rm -f ${RESULT_DIR}/require_scratch*
488 if $OPTIONS_HAVE_SECTIONS; then
489 trap "_summary; exit \$status" 0 1 2 3 15
491 trap "_wrapup; exit \$status" 0 1 2 3 15
494 for section in $HOST_OPTIONS_SECTIONS; do
496 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
497 get_next_config $section
499 # Do we need to run only some sections ?
500 if [ ! -z "$RUN_SECTION" ]; then
502 for s in $RUN_SECTION; do
503 if [ $section == $s ]; then
513 # Did this section get excluded?
514 if [ ! -z "$EXCLUDE_SECTION" ]; then
516 for s in $EXCLUDE_SECTION; do
517 if [ $section == $s ]; then
527 mkdir -p $RESULT_BASE
528 if [ ! -d $RESULT_BASE ]; then
529 echo "failed to create results directory $RESULT_BASE"
534 if $OPTIONS_HAVE_SECTIONS; then
535 echo "SECTION -- $section"
538 sect_start=`_wallclock`
539 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
540 echo "RECREATING -- $FSTYP on $TEST_DEV"
541 _test_unmount 2> /dev/null
542 if ! _test_mkfs >$tmp.err 2>&1
544 echo "our local _test_mkfs routine ..."
546 echo "check: failed to mkfs \$TEST_DEV using specified options"
552 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
557 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
558 _test_unmount 2> /dev/null
561 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
570 check="$RESULT_BASE/check"
572 # don't leave old full output behind on a clean run
575 [ -f $check.time ] || touch $check.time
577 # print out our test configuration
578 echo "FSTYP -- `_full_fstyp_details`"
579 echo "PLATFORM -- `_full_platform_details`"
580 if [ ! -z "$SCRATCH_DEV" ]; then
581 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
582 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
587 if [ ! -z "$SCRATCH_DEV" ]; then
588 _scratch_unmount 2> /dev/null
589 # call the overridden mkfs - make sure the FS is built
590 # the same as we'll create it later.
592 if ! _scratch_mkfs >$tmp.err 2>&1
594 echo "our local _scratch_mkfs routine ..."
596 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
601 # call the overridden mount - make sure the FS mounts with
602 # the same options that we'll mount with later.
603 if ! _scratch_mount >$tmp.err 2>&1
605 echo "our local mount routine ..."
607 echo "check: failed to mount \$SCRATCH_DEV using specified options"
620 if [ ! -f $seq ]; then
621 # Try to get full name in case the user supplied only seq id
622 # and the test has a name. A bit of hassle to find really
623 # the test and not its sample output or helping files.
624 bname=$(basename $seq)
625 full_seq=$(find $(dirname $seq) -name $bname* -executable |
626 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
627 END { print shortest }')
628 if [ -f $full_seq ] \
629 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
634 # the filename for the test and the name output are different.
635 # we don't include the tests/ directory in the name output.
636 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
638 # Similarly, the result directory needs to replace the tests/
639 # part of the test location.
641 if $OPTIONS_HAVE_SECTIONS; then
642 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
643 REPORT_DIR="$RESULT_BASE/$section"
645 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
646 REPORT_DIR="$RESULT_BASE"
648 seqres="$REPORT_DIR/$seqnum"
658 n_notrun=`expr $n_notrun + 1`
660 _make_testcase_report "list"
665 if [ ! -f $seq ]; then
666 echo " - no such test?"
668 # really going to try and run this one
670 rm -f $seqres.out.bad
672 # check if we really should run it
673 if [ -s $tmp.xlist ]; then
674 if grep $seqnum $tmp.xlist > /dev/null 2>&1 ; then
680 # slashes now in names, sed barfs on them so use grep
681 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
682 if [ "X$lasttime" != X ]; then
683 echo -n " ${lasttime}s ..."
685 echo -n " " # prettier output with timestamps.
687 rm -f core $seqres.notrun
690 $timestamp && echo -n " ["`date "+%T"`"]"
691 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
692 $LOGGER_PROG "run xfstest $seqnum"
693 if [ -w /dev/kmsg ]; then
694 export date_time=`date +"%F %T"`
695 echo "run fstests $seqnum at $date_time" > /dev/kmsg
696 # _check_dmesg depends on this log in dmesg
697 touch ${RESULT_DIR}/check_dmesg
699 if [ "$DUMP_OUTPUT" = true ]; then
700 ./$seq 2>&1 | tee $tmp.rawout
701 # Because $? would get tee's return code
704 ./$seq >$tmp.rawout 2>&1
707 $timestamp && _timestamp
710 _fix_malloc <$tmp.rawout >$tmp.out
715 err_msg="[dumped core]"
717 mv core $RESULT_BASE/$seqnum.core
721 if [ -f $seqres.notrun ]
723 $timestamp || echo -n " [not run] "
724 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
726 notrun="$notrun $seqnum"
727 n_notrun=`expr $n_notrun + 1`
732 err_msg="[failed, exit status $sts]"
738 _dump_err "no qualified output"
742 # coreutils 8.16+ changed quote formats in error messages from
743 # `foo' to 'foo'. Filter old versions to match the new version.
744 sed -i "s/\`/\'/g" $tmp.out
745 if diff $seq.out $tmp.out >/dev/null 2>&1
751 echo "$seqnum `expr $stop - $start`" >>$tmp.time
752 echo -n " `expr $stop - $start`s"
756 echo " - output mismatch (see $seqres.out.bad)"
757 mv $tmp.out $seqres.out.bad
758 $diff $seq.out $seqres.out.bad | {
759 if test "$DIFF_LENGTH" -le 0; then
762 head -n "$DIFF_LENGTH"
764 echo "(Run '$diff $seq.out $seqres.out.bad'" \
765 " to see the entire diff)"
767 sed -e 's/^\(.\)/ \1/'
768 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
773 n_try=`expr $n_try + 1`
775 _check_dmesg || err=true
780 # come here for each test, except when $showme is true
785 n_bad=`expr $n_bad + 1`
790 _make_testcase_report "$tc_status"
794 sect_stop=`_wallclock`
800 _test_unmount 2> /dev/null
801 _scratch_unmount 2> /dev/null
805 status=`expr $sum_bad`