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