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
75 -udiff show unified diff (default)
76 -n show me, do not run tests
78 -r randomize test order
79 -d dump test output to stdout
81 -R fmt[,fmt] generate report in formats specified. Supported format: [xunit]
82 --large-fs optimise scratch device for large filesystems
83 -s section run only specified section from config file
84 -S section exclude the specified section from the config file
87 -g group[,group...] include tests from these groups
88 -x group[,group...] exclude tests from these groups
89 -X exclude_file exclude individual tests
90 -E external_file exclude individual tests
91 [testlist] include tests matching names in testlist
93 testlist argument is a list of tests in the form of <test dir>/<test name>.
95 <test dir> is a directory under tests that contains a group file,
96 with a list of the names of the tests in that directory.
98 <test name> may be either a specific test file name (e.g. xfs/001) or
99 a test file name match pattern (e.g. xfs/*).
101 group argument is either a name of a tests group to collect from all
102 the test dirs (e.g. quick) or a name of a tests group to collect from
103 a specific tests dir in the form of <test dir>/<group name> (e.g. xfs/quick).
105 exclude_file argument refers to a name of a file inside each test directory.
106 for every test dir where this file is found, the listed test names are
107 excluded from the list of tests to run from that test dir.
109 external_file argument is a path to a single file containing a list of tests
110 to exclude in the form of <test dir>/<test name>.
116 check -x stress xfs/*
117 check -X .exclude -g auto
118 check -E ~/.xfstests.exclude
128 test -s "$SRC_DIR/$d/group" || return 1
130 local grpl=$(sed -n < $SRC_DIR/$d/group \
133 -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p")
141 local sub=$(dirname $grp)
143 if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then
144 # group is given as <subdir>/<group> (e.g. xfs/quick)
146 get_sub_group_list $sub $grp
150 for d in $SRC_GROUPS $FSTYP; do
151 if ! test -d "$SRC_DIR/$d" ; then
154 grpl="$grpl $(get_sub_group_list $d $grp)"
159 # Find all tests, excluding files that are test metadata such as group files.
160 # It matches test names against $VALID_TEST_NAME defined in common/rc
164 for d in $SRC_GROUPS $FSTYP; do
165 if ! test -d "$SRC_DIR/$d" ; then
170 grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \
171 grep -v "group\|Makefile" >> $tmp.list 2>/dev/null
175 # takes the list of tests to run in $tmp.list, and removes the tests passed to
176 # the function from that list.
185 if [ $numsed -gt 100 ]; then
186 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
187 mv $tmp.tmp $tmp.list
191 echo "^$t\$" >>$tmp.grep
192 numsed=`expr $numsed + 1`
194 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
195 mv $tmp.tmp $tmp.list
213 # Tests specified on the command line
214 if [ -s $tmp.arglist ]; then
215 cat $tmp.arglist > $tmp.list
220 # Specified groups to include
221 for group in $GROUP_LIST; do
222 list=$(get_group_list $group)
223 if [ -z "$list" ]; then
224 echo "Group \"$group\" is empty or not defined?"
229 grep -s "^$t\$" $tmp.list >/dev/null || \
230 echo "$t" >>$tmp.list
234 if ! $have_test_arg && [ -z "$GROUP_LIST" ]; then
235 # no test numbers, do everything
239 # Specified groups to exclude
240 for xgroup in $XGROUP_LIST; do
241 list=$(get_group_list $xgroup)
242 if [ -z "$list" ]; then
243 echo "Group \"$xgroup\" is empty or not defined?"
250 # sort the list of tests into numeric order
251 list=`sort -n $tmp.list | uniq`
252 rm -f $tmp.list $tmp.tmp $tmp.grep
256 list=`echo $list | awk -f randomize.awk`
260 # Process command arguments first.
261 while [ $# -gt 0 ]; do
263 -\? | -h | --help) usage ;;
266 -glusterfs) FSTYP=glusterfs ;;
268 -overlay) FSTYP=overlay; export OVERLAY=true ;;
269 -pvfs2) FSTYP=pvfs2 ;;
270 -tmpfs) FSTYP=tmpfs ;;
271 -ubifs) FSTYP=ubifs ;;
273 -g) group=$2 ; shift ;
274 GROUP_LIST="$GROUP_LIST ${group//,/ }"
277 -x) xgroup=$2 ; shift ;
278 XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }"
281 -X) xfile=$2; shift ;
282 for d in $SRC_GROUPS $FSTYP; do
283 [ -f $SRC_DIR/$d/$xfile ] || continue
284 for f in `sed "s/#.*$//" $SRC_DIR/$d/$xfile`; do
285 echo $d/$f >> $tmp.xlist
289 -E) xfile=$2; shift ;
290 if [ -f $xfile ]; then
291 sed "s/#.*$//" "$xfile" >> $tmp.xlist
294 -s) RUN_SECTION="$RUN_SECTION $2"; shift ;;
295 -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;;
297 -udiff) diff="$diff -u" ;;
300 -r) randomize=true ;;
302 -T) timestamp=true ;;
303 -d) DUMP_OUTPUT=true ;;
304 -b) brief_test_summary=true;;
305 -R) report_fmt=$2 ; shift ;
306 REPORT_LIST="$REPORT_LIST ${report_fmt//,/ }"
309 --large-fs) export LARGE_SCRATCH_DEV=yes ;;
310 --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
313 *) # not an argument, we've got tests now.
314 have_test_arg=true ;;
317 # if we've found a test specification, the break out of the processing
318 # loop before we shift the arguments so that this is the first argument
319 # that we process in the test arg loop below.
320 if $have_test_arg; then
327 # we need common/config, source it after processing args, overlay needs FSTYP
328 # set before sourcing common/config
329 if ! . ./common/config; then
330 echo "$iam: failed to source common/config"
334 # Process tests from command line now.
335 if $have_test_arg; then
336 while [ $# -gt 0 ]; do
338 -*) echo "Arguments before tests, please!"
342 *) # Expand test pattern (e.g. xfs/???, *fs/001)
343 list=$(cd $SRC_DIR; echo $1)
345 test_dir=`dirname $t`
346 test_dir=${test_dir#$SRC_DIR/*}
347 test_name=`basename $t`
348 group_file=$SRC_DIR/$test_dir/group
350 if egrep -q "^$test_name" $group_file; then
351 # in group file ... OK
352 echo $SRC_DIR/$test_dir/$test_name \
356 echo "$t - unknown test, ignored"
369 echo "check: failed to source common/rc"
375 echo "check: QA must be run as root"
390 check="$RESULT_BASE/check"
400 if [ -f $check.time -a -f $tmp.time ]; then
401 cat $check.time $tmp.time \
406 for (i in t) print i " " t[i]
410 mv $tmp.out $check.time
416 echo "SECTION -- $section" >>$tmp.summary
417 echo "=========================" >>$tmp.summary
418 if [ ! -z "$n_try" -a $n_try != 0 ]; then
419 if [ $brief_test_summary == "false" ]; then
421 echo "Ran:$try" >>$tmp.summary
423 echo "Ran:$try" >>$check.log
426 $interrupt && echo "Interrupted!" | tee -a $check.log
428 if [ ! -z "$notrun" ]; then
429 if [ $brief_test_summary == "false" ]; then
430 echo "Not run:$notrun"
431 echo "Not run:$notrun" >>$tmp.summary
433 echo "Not run:$notrun" >>$check.log
436 if [ ! -z "$n_bad" -a $n_bad != 0 ]; then
438 echo "Failed $n_bad of $n_try tests"
439 echo "Failures:$bad" >>$check.log
440 echo "Failed $n_bad of $n_try tests" >>$check.log
441 echo "Failures:$bad" >>$tmp.summary
442 echo "Failed $n_bad of $n_try tests" >>$tmp.summary
444 echo "Passed all $n_try tests"
445 echo "Passed all $n_try tests" >>$check.log
446 echo "Passed all $n_try tests" >>$tmp.summary
448 echo "" >>$tmp.summary
455 sum_bad=`expr $sum_bad + $n_bad`
457 rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
458 if ! $OPTIONS_HAVE_SECTIONS; then
469 count=`wc -L $tmp.summary | cut -f1 -d" "`
478 if [ -f ${RESULT_DIR}/require_test ]; then
479 _check_test_fs || err=true
480 rm -f ${RESULT_DIR}/require_test*
482 if [ -f ${RESULT_DIR}/require_scratch ]; then
483 _check_scratch_fs || err=true
484 rm -f ${RESULT_DIR}/require_scratch*
490 if $OPTIONS_HAVE_SECTIONS; then
491 trap "_summary; exit \$status" 0 1 2 3 15
493 trap "_wrapup; exit \$status" 0 1 2 3 15
496 for section in $HOST_OPTIONS_SECTIONS; do
498 OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
499 get_next_config $section
501 # Do we need to run only some sections ?
502 if [ ! -z "$RUN_SECTION" ]; then
504 for s in $RUN_SECTION; do
505 if [ $section == $s ]; then
515 # Did this section get excluded?
516 if [ ! -z "$EXCLUDE_SECTION" ]; then
518 for s in $EXCLUDE_SECTION; do
519 if [ $section == $s ]; then
529 mkdir -p $RESULT_BASE
530 if [ ! -d $RESULT_BASE ]; then
531 echo "failed to create results directory $RESULT_BASE"
536 if $OPTIONS_HAVE_SECTIONS; then
537 echo "SECTION -- $section"
540 sect_start=`_wallclock`
541 if $RECREATE_TEST_DEV || [ "$OLD_FSTYP" != "$FSTYP" ]; then
542 echo "RECREATING -- $FSTYP on $TEST_DEV"
543 _test_unmount 2> /dev/null
544 if ! _test_mkfs >$tmp.err 2>&1
546 echo "our local _test_mkfs routine ..."
548 echo "check: failed to mkfs \$TEST_DEV using specified options"
554 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
559 elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then
560 _test_unmount 2> /dev/null
563 echo "check: failed to mount $TEST_DEV on $TEST_DIR"
572 check="$RESULT_BASE/check"
574 # don't leave old full output behind on a clean run
577 [ -f $check.time ] || touch $check.time
579 # print out our test configuration
580 echo "FSTYP -- `_full_fstyp_details`"
581 echo "PLATFORM -- `_full_platform_details`"
582 if [ ! -z "$SCRATCH_DEV" ]; then
583 echo "MKFS_OPTIONS -- `_scratch_mkfs_options`"
584 echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
589 if [ ! -z "$SCRATCH_DEV" ]; then
590 _scratch_unmount 2> /dev/null
591 # call the overridden mkfs - make sure the FS is built
592 # the same as we'll create it later.
594 if ! _scratch_mkfs >$tmp.err 2>&1
596 echo "our local _scratch_mkfs routine ..."
598 echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
603 # call the overridden mount - make sure the FS mounts with
604 # the same options that we'll mount with later.
605 if ! _scratch_mount >$tmp.err 2>&1
607 echo "our local mount routine ..."
609 echo "check: failed to mount \$SCRATCH_DEV using specified options"
622 if [ ! -f $seq ]; then
623 # Try to get full name in case the user supplied only seq id
624 # and the test has a name. A bit of hassle to find really
625 # the test and not its sample output or helping files.
626 bname=$(basename $seq)
627 full_seq=$(find $(dirname $seq) -name $bname* -executable |
628 awk '(NR == 1 || length < length(shortest)) { shortest = $0 }\
629 END { print shortest }')
630 if [ -f $full_seq ] \
631 && [ x$(echo $bname | grep -o "^$VALID_TEST_ID") != x ]; then
636 # the filename for the test and the name output are different.
637 # we don't include the tests/ directory in the name output.
638 export seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
640 # Similarly, the result directory needs to replace the tests/
641 # part of the test location.
643 if $OPTIONS_HAVE_SECTIONS; then
644 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;${RESULT_BASE}/$section;"`
645 REPORT_DIR="$RESULT_BASE/$section"
647 export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
648 REPORT_DIR="$RESULT_BASE"
650 seqres="$REPORT_DIR/$seqnum"
660 n_notrun=`expr $n_notrun + 1`
662 _make_testcase_report "list"
667 if [ ! -f $seq ]; then
668 echo " - no such test?"
670 # really going to try and run this one
672 rm -f $seqres.out.bad
674 # check if we really should run it
675 if [ -s $tmp.xlist ]; then
676 if grep $seqnum $tmp.xlist > /dev/null 2>&1 ; then
682 # slashes now in names, sed barfs on them so use grep
683 lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
684 if [ "X$lasttime" != X ]; then
685 echo -n " ${lasttime}s ..."
687 echo -n " " # prettier output with timestamps.
689 rm -f core $seqres.notrun
692 $timestamp && echo -n " ["`date "+%T"`"]"
693 [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
694 $LOGGER_PROG "run xfstest $seqnum"
695 if [ -w /dev/kmsg ]; then
696 export date_time=`date +"%F %T"`
697 echo "run fstests $seqnum at $date_time" > /dev/kmsg
698 # _check_dmesg depends on this log in dmesg
699 touch ${RESULT_DIR}/check_dmesg
701 if [ "$DUMP_OUTPUT" = true ]; then
702 ./$seq 2>&1 | tee $tmp.rawout
703 # Because $? would get tee's return code
706 ./$seq >$tmp.rawout 2>&1
709 $timestamp && _timestamp
712 _fix_malloc <$tmp.rawout >$tmp.out
717 err_msg="[dumped core]"
719 mv core $RESULT_BASE/$seqnum.core
723 if [ -f $seqres.notrun ]
725 $timestamp || echo -n " [not run] "
726 $timestamp && echo " [not run]" && echo -n " $seqnum -- "
728 notrun="$notrun $seqnum"
729 n_notrun=`expr $n_notrun + 1`
734 err_msg="[failed, exit status $sts]"
740 _dump_err "no qualified output"
744 # coreutils 8.16+ changed quote formats in error messages from
745 # `foo' to 'foo'. Filter old versions to match the new version.
746 sed -i "s/\`/\'/g" $tmp.out
747 if diff $seq.out $tmp.out >/dev/null 2>&1
753 echo "$seqnum `expr $stop - $start`" >>$tmp.time
754 echo -n " `expr $stop - $start`s"
758 echo " - output mismatch (see $seqres.out.bad)"
759 mv $tmp.out $seqres.out.bad
760 $diff $seq.out $seqres.out.bad | {
761 if test "$DIFF_LENGTH" -le 0; then
764 head -n "$DIFF_LENGTH"
766 echo "(Run '$diff $seq.out $seqres.out.bad'" \
767 " to see the entire diff)"
769 sed -e 's/^\(.\)/ \1/'
770 err_msg="output mismatch (see $diff $seq.out $seqres.out.bad)"
775 n_try=`expr $n_try + 1`
777 _check_dmesg || err=true
782 # come here for each test, except when $showme is true
787 n_bad=`expr $n_bad + 1`
792 _make_testcase_report "$tc_status"
796 sect_stop=`_wallclock`
802 _test_unmount 2> /dev/null
803 _scratch_unmount 2> /dev/null
807 status=`expr $sum_bad`