xfstests: include test subdirectory support
[xfstests-dev.git] / check
1 #!/bin/bash
2 #
3 # Control script for QA
4 #
5 # Copyright (c) 2000-2002,2006 Silicon Graphics, Inc.  All Rights Reserved.
6 #
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.
10 #
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.
15 #
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
19 #
20 #
21
22 tmp=/tmp/$$
23 status=0
24 needwrap=true
25 n_try=0
26 try=""
27 n_bad=0
28 bad=""
29 notrun=""
30 interrupt=true
31 diff="diff -u"
32 showme=false
33 have_test_arg=false
34 randomize=false
35 here=`pwd`
36 FSTYP=xfs
37
38 SUPPORTED_TESTS="[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]"
39 TEST_GROUP_DIR="tests"
40 GENERIC_GROUP_DIR="$TEST_GROUP_DIR/generic"
41
42 # generic initialization
43 iam=check
44
45 export QA_CHECK_FS=${QA_CHECK_FS:=true}
46
47 # by default don't output timestamps
48 timestamp=${TIMESTAMP:=false}
49
50 # number of diff lines from a failed test, 0 for whole output
51 export DIFF_LENGTH=${DIFF_LENGTH:=10}
52
53 # by default don't output timestamps
54 timestamp=${TIMESTAMP:=false}
55
56 usage()
57 {
58     echo "Usage: $0 [options] [testlist]"'
59
60 check options
61     -xfs                test XFS (default)
62     -udf                test UDF
63     -nfs                test NFS
64     -l                  line mode diff
65     -udiff              show unified diff (default)
66     -n                  show me, do not run tests
67     -T                  output timestamps
68     -r                  randomize test order
69     --large-fs          optimise scratch device for large filesystems
70
71 testlist options
72     -g group[,group...] include tests from these groups
73     -x group[,group...] exclude tests from these groups
74     NNN                 include test NNN
75     NNN-NNN             include test range (eg. 012-021)
76 '
77             exit 0
78 }
79
80 _setenvironment()
81 {
82     MSGVERB="text:action"
83     export MSGVERB
84 }
85
86 get_group_list()
87 {
88         grp=$1
89         dirs=". $GENERIC_GROUP_DIR"
90
91         for d in $dirs; do
92                 l=$(sed -n < $d/group \
93                         -e 's/#.*//' \
94                         -e 's/$/ /' \
95                         -e "s;\(^[0-9][0-9][0-9]\).* $grp .*;$d/\1;p")
96                 grpl="$grpl $l"
97         done
98         echo $grpl
99 }
100
101 expand_test_numbers()
102 {
103         # strip leading zeros, could be considered octal.
104         start=`echo $1 | sed 's/^0*//'`
105         end=`echo $2 | sed 's/^0*//'`
106
107         $AWK_PROG </dev/null '
108 BEGIN   { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
109         | while read id
110         do
111                 if grep -s "^$id " group >/dev/null ; then
112                         # in group file ... OK
113                         echo $id >>$tmp.list
114                 else
115                         # oops
116                         echo "$id - unknown test, ignored"
117                 fi
118         done
119 }
120
121 _wallclock()
122 {
123     date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }'
124 }
125
126 _timestamp()
127 {
128     now=`date "+%T"`
129     echo -n " [$now]"
130 }
131
132 # start the initialisation work now
133 _setenvironment
134
135 rm -f $tmp.list $tmp.tmp $tmp.sed $here/$iam.out
136
137 # Autodetect fs type based on what's on $TEST_DEV
138 if [ "$HOSTOS" == "Linux" ]; then
139     FSTYP=`blkid -c /dev/null -s TYPE -o value $TEST_DEV`
140 fi
141 export FSTYP
142
143 # we need common.config
144 if ! . ./common.config
145 then
146     echo "$iam: failed to source common.config"
147     exit 1
148 fi
149
150 while [ $# -gt 0 ]; do
151         case "$1" in
152         -\? | -h | --help) usage ;;
153
154         -udf)   FSTYP=udf ;;
155         -xfs)   FSTYP=xfs ;;
156         -nfs)   FSTYP=nfs ;;
157
158         -g)     group=$2 ; shift ;
159                 group_list=$(get_group_list $group)
160                 if [ -z "$group_list" ]; then
161                     echo "Group \"$group\" is empty or not defined?"
162                     exit 1
163                 fi
164
165                 [ ! -s $tmp.list ] && touch $tmp.list
166                 for t in $group_list; do
167                         grep -s "^$t\$" $tmp.list >/dev/null || \
168                                                         echo "$t" >>$tmp.list
169                 done
170
171                 ;;
172
173         -x)     xgroup=$2 ; shift ;
174                 [ ! -s $tmp.list ] &&  ls $SUPPORTED_TESTS >$tmp.list 2>/dev/null
175                 group_list=$(get_group_list $xgroup)
176                 if [ -z "$group_list" ]; then
177                     echo "Group \"$xgroup\" is empty or not defined?"
178                     exit 1
179                 fi
180
181                 rm -f $tmp.sed
182                 numsed=0
183                 for t in $group_list
184                 do
185                     if [ $numsed -gt 100 ]; then
186                         sed -f $tmp.sed <$tmp.list >$tmp.tmp
187                         mv $tmp.tmp $tmp.list
188                         numsed=0
189                         rm -f $tmp.sed
190                     fi
191                     echo "/^$t\$/d" >>$tmp.sed
192                     numsed=`expr $numsed + 1`
193                 done
194                 sed -f $tmp.sed <$tmp.list >$tmp.tmp
195                 mv $tmp.tmp $tmp.list
196                 ;;
197
198         -l)     diff="diff" ;;
199         -udiff) diff="$diff -u" ;;
200
201         -n)     showme=true ;;
202         -r)     randomize=true ;;
203
204         -T)     timestamp=true ;;
205
206         "$SUPPORTED_TESTS")
207                 echo "No tests?"
208                 status=1
209                 exit $status
210                 ;;
211
212         [0-9]*-[0-9]*)
213                 eval `echo $1 | sed -e 's/^/start=/' -e 's/-/ end=/'`
214                 expand_test_numbers $start $end
215                 have_test_arg=true
216                 ;;
217
218         [0-9]*-)
219                 eval `echo $1 | sed -e 's/^/start=/' -e 's/-//'`
220                 end=`echo $SUPPORTED_TESTS | sed -e 's/\[0-9]//g' -e 's/  *$//' -e 's/.* //'`
221                 if [ -z "$end" ]; then
222                         echo "No tests in range \"$1\"?"
223                         status=1
224                         exit $status
225                 fi
226                 expand_test_numbers $start $end
227                 have_test_arg=true
228                 ;;
229
230         --large-fs) export LARGE_SCRATCH_DEV=yes ;;
231         --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
232
233         -*)     usage ;;
234         *)      expand_test_numbers $1 $1 ;
235                 have_test_arg=true
236                 ;;
237         esac
238
239         shift
240 done
241
242 if [ -s $tmp.list ]; then
243     # found some valid test numbers ... this is good
244     :
245 elif $have_test_arg; then
246         # had test numbers, but none in group file ... do nothing
247         touch $tmp.list
248 else
249         # no test numbers, do everything from group file
250         sed -n -e '/^[0-9][0-9][0-9]*/s/[       ].*//p' <group >$tmp.list
251 fi
252
253 # sort the list of tests into numeric order
254 list=`sort -n $tmp.list`
255 rm -f $tmp.list $tmp.tmp $tmp.sed
256
257 if $randomize
258 then
259     list=`echo $list | awk -f randomize.awk`
260 fi
261
262 # we need common.rc
263 if ! . ./common.rc
264 then
265     echo "check: failed to source common.rc"
266     exit 1
267 fi
268
269 if [ `id -u` -ne 0 ]
270 then
271     echo "check: QA must be run as root"
272     exit 1
273 fi
274
275 # Ok, time to start running...
276
277 _wrapup()
278 {
279     if $showme
280     then
281         :
282     elif $needwrap
283     then
284         if [ -f check.time -a -f $tmp.time ]
285         then
286             cat check.time $tmp.time \
287             | $AWK_PROG '
288         { t[$1] = $2 }
289 END     { if (NR > 0) {
290             for (i in t) print i " " t[i]
291           }
292         }' \
293             | sort -n >$tmp.out
294             mv $tmp.out check.time
295         fi
296
297         echo "" >>check.log
298         date >>check.log
299         echo $list | fmt | sed -e 's/^/    /' -e 's;tests/;;g' >>check.log
300         $interrupt && echo "Interrupted!" >>check.log
301         
302         if [ ! -z "$n_try" -a $n_try != 0 ]
303         then
304             echo "Ran:$try"
305         fi
306
307         if [ ! -z "$notrun" ]
308         then
309             echo "Not run:$notrun"
310             echo "Not run:$notrun" >>check.log
311         fi
312
313         if [ ! -z "$n_bad" -a $n_bad != 0 ]
314         then
315             echo "Failures:$bad"
316             echo "Failed $n_bad of $n_try tests"
317             echo "Failures:$bad" | fmt >>check.log
318             echo "Failed $n_bad of $n_try tests" >>check.log
319         else
320             echo "Passed all $n_try tests"
321             echo "Passed all $n_try tests" >>check.log
322         fi
323         needwrap=false
324     fi
325
326     rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
327     rm -f $tmp.*
328 }
329
330 trap "_wrapup; exit \$status" 0 1 2 3 15
331
332 # don't leave old full output behind on a clean run
333 rm -f check.full
334
335 [ -f check.time ] || touch check.time
336
337 # print out our test configuration
338 echo "FSTYP         -- `_full_fstyp_details`"
339 echo "PLATFORM      -- `_full_platform_details`"
340 if [ ! -z "$SCRATCH_DEV" ]; then
341   echo "MKFS_OPTIONS  -- `_scratch_mkfs_options`"
342   echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
343 fi
344 echo
345
346
347 if [ ! -z "$SCRATCH_DEV" ]; then
348   umount $SCRATCH_DEV 2>/dev/null
349   # call the overridden mkfs - make sure the FS is built
350   # the same as we'll create it later.
351
352   if ! _scratch_mkfs $flag >$tmp.err 2>&1
353   then
354       echo "our local _scratch_mkfs routine ..."
355       cat $tmp.err
356       echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
357       exit 1
358   fi
359
360   # call the overridden mount - make sure the FS mounts with
361   # the same options that we'll mount with later.
362   if ! _scratch_mount >$tmp.err 2>&1
363   then
364       echo "our local mount routine ..."
365       cat $tmp.err
366       echo "check: failed to mount \$SCRATCH_DEV using specified options"
367       exit 1
368   fi
369 fi
370
371 seq="check"
372 _check_test_fs
373
374 for seq in $list
375 do
376     err=false
377
378     # the filename for the test and the name output are different.
379     # we don't include the tests/ directory in the name output.
380     seqnum=`echo $seq | sed -e 's;tests/;;'`
381
382     echo -n "$seqnum"
383
384     if $showme
385     then
386         echo
387         continue
388     elif [ ! -f $seq ]
389     then
390         echo " - no such test?"
391     else
392         # really going to try and run this one
393         #
394         rm -f $seq.out.bad
395
396         # slashes now in names, sed barfs on them so use grep
397         lasttime=`grep -w ^$seq check.time | awk '// {print $2}'`
398         if [ "X$lasttime" != X ]; then
399                 echo -n " ${lasttime}s ..."
400         else
401                 echo -n "       "       # prettier output with timestamps.
402         fi
403         rm -f core $seq.notrun
404
405         start=`_wallclock`
406         $timestamp && echo -n " ["`date "+%T"`"]"
407         [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
408         $LOGGER_PROG "run xfstest $seqnum"
409         ./$seq >$tmp.rawout 2>&1
410         sts=$?
411         $timestamp && _timestamp
412         stop=`_wallclock`
413
414         _fix_malloc <$tmp.rawout >$tmp.out
415         rm -f $tmp.rawout
416
417         if [ -f core ]
418         then
419             echo -n " [dumped core]"
420             mv core $seq.core
421             err=true
422         fi
423
424         if [ -f $seq.notrun ]
425         then
426             $timestamp || echo -n " [not run] "
427             $timestamp && echo " [not run]" && echo -n "        $seqnum -- "
428             cat $seq.notrun
429             notrun="$notrun $seqnum"
430         else
431             if [ $sts -ne 0 ]
432             then
433                 echo -n " [failed, exit status $sts]"
434                 err=true
435             fi
436             if [ ! -f $seq.out ]
437             then
438                 echo " - no qualified output"
439                 err=true
440             else
441                 if diff $seq.out $tmp.out >/dev/null 2>&1
442                 then
443                     if $err
444                     then
445                         :
446                     else
447                         echo "$seqnum `expr $stop - $start`" >>$tmp.time
448                         echo -n " `expr $stop - $start`s"
449                     fi
450                     echo ""
451                 else
452                     echo " - output mismatch (see $seq.out.bad)"
453                     mv $tmp.out $seq.out.bad
454                     $diff $seq.out $seq.out.bad | {
455                         if test "$DIFF_LENGTH" -le 0; then
456                                 cat
457                         else
458                                 head -n "$DIFF_LENGTH"
459                         fi; } | \
460                         sed -e 's/^\(.\)/    \1/'
461                     echo "     ..."
462                     echo "     (Run '$diff $seq.out $seq.out.bad' to see the" \
463                          "entire diff)"
464                     err=true
465                 fi
466             fi
467         fi
468
469     fi
470
471     # come here for each test, except when $showme is true
472     #
473     if $err
474     then
475         bad="$bad $seqnum"
476         n_bad=`expr $n_bad + 1`
477         quick=false
478     fi
479     if [ ! -f $seq.notrun ]
480     then
481         try="$try $seqnum"
482         n_try=`expr $n_try + 1`
483         _check_test_fs
484     fi
485     
486     seq="after_$seqnum"
487 done
488
489 interrupt=false
490 status=`expr $n_bad`
491 exit