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