Unleashed v1.4
[unleashed.git] / usr / src / cmd / tail / tests / tailtests.sh
blobd7eee2642942e07c6f18255e364428520e0c23d6
1 #!/bin/bash
4 # This file and its contents are supplied under the terms of the
5 # Common Development and Distribution License ("CDDL"), version 1.0.
6 # You may only use this file in accordance with the terms of version
7 # 1.0 of the CDDL.
9 # A full copy of the text of the CDDL should have accompanied this
10 # source. A copy is of the CDDL is also available via the Internet
11 # at http://www.illumos.org/license/CDDL.
15 # Copyright 2010 Chris Love. All rights reserved.
16 # Copyright 2017, Joyent, Inc.
19 BLOCK=""
20 for i in {1..512}; do
21 BLOCK+="."
22 done
25 checktest()
27 local actual=$1
28 local output=$2
29 local test=$3
31 if [[ "$actual" != "$output" ]]; then
32 echo "$CMD: test $test: FAIL"
33 echo -e "$CMD: test $test: expected output:\n$output"
34 echo -e "$CMD: test $test: actual output:\n$actual"
35 else
36 echo "$CMD: test $test: pass"
40 checkfail()
42 printf "foobar" | $PROG $* &> /dev/null
44 if [[ $? -eq 0 ]]; then
45 printf '%s: test "test %s": was supposed to fail\n' "$CMD" "$*"
46 else
47 printf '%s: test "%s": pass\n' "$CMD" "$*"
52 # Test cases for 'tail', some based on CoreUtils test cases. Note that
53 # this is designed to be able to run on BSD systems as well to check
54 # our behavior against theirs (some behavior that is known to be
55 # idiosyncratic to illumos is skipped on non-illumos systems).
57 PROG=/usr/bin/tail
58 CMD=`basename $0`
59 DIR=""
61 while [[ $# -gt 0 ]]; do
62 case $1 in
63 -o)
64 PROG=$2
65 shift 2
67 -d)
68 DIR=$2
69 shift 2
72 echo "Usage: tailtests.sh" \
73 "[-o <override tail executable>]" \
74 "[-d <override output directory>]"
75 exit 1
77 esac
78 done
81 # Shut bash up upon receiving a term so we can drop it on our children
82 # without disrupting the output.
84 trap "exit 0" TERM
86 echo "$CMD: program is $PROG"
88 if [[ $DIR != "" ]]; then
89 echo "$CMD: directory is $DIR"
92 o=`echo -e "bcd"`
93 a=`echo -e "abcd" | $PROG +2c`
94 checktest "$a" "$o" 1
96 o=`echo -e ""`
97 a=`echo "abcd" | $PROG +8c`
98 checktest "$a" "$o" 2
100 o=`echo -e "abcd"`
101 a=`echo "abcd" | $PROG -9c`
102 checktest "$a" "$o" 3
104 o=`echo -e "x"`
105 a=`echo -e "x" | $PROG -1l`
106 checktest "$a" "$o" 4
108 o=`echo -e "\n"`
109 a=`echo -e "x\ny\n" | $PROG -1l`
110 checktest "$a" "$o" 5
112 o=`echo -e "y\n"`
113 a=`echo -e "x\ny\n" | $PROG -2l`
114 checktest "$a" "$o" 6
116 o=`echo -e "y"`
117 a=`echo -e "x\ny" | $PROG -1l`
118 checktest "$a" "$o" 7
120 o=`echo -e "x\ny\n"`
121 a=`echo -e "x\ny\n" | $PROG +1l`
122 checktest "$a" "$o" 8
124 o=`echo -e "y\n"`
125 a=`echo -e "x\ny\n" | $PROG +2l`
126 checktest "$a" "$o" 9
128 o=`echo -e "x"`
129 a=`echo -e "x" | $PROG -1`
130 checktest "$a" "$o" 10
132 o=`echo -e "\n"`
133 a=`echo -e "x\ny\n" | $PROG -1`
134 checktest "$a" "$o" 11
136 o=`echo -e "y\n"`
137 a=`echo -e "x\ny\n" | $PROG -2`
138 checktest "$a" "$o" 12
140 o=`echo -e "y"`
141 a=`echo -e "x\ny" | $PROG -1`
142 checktest "$a" "$o" 13
144 o=`echo -e "x\ny\n"`
145 a=`echo -e "x\ny\n" | $PROG +1`
146 checktest "$a" "$o" 14
148 o=`echo -e "y\n"`
149 a=`echo -e "x\ny\n" | $PROG +2`
150 checktest "$a" "$o" 15
152 o=`printf "yyz\n"`
153 a=`printf "xyyyyyyyyyyz\n" | $PROG +10c`
154 checktest "$a" "$o" 16
156 o=`printf "y\ny\nz\n"`
157 a=`printf "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz\n" | $PROG +10l`
158 checktest "$a" "$o" 17
160 o=`printf "y\ny\ny\ny\ny\ny\ny\ny\ny\nz\n"`
161 a=`printf "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz\n" | $PROG -10l`
162 checktest "$a" "$o" 18
164 a=`printf "o\nn\nm\nl\nk\nj\ni\nh\ng\n"`
165 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG +10lr`
166 checktest "$a" "$o" 19
168 a=`printf "o\nn\nm\nl\nk\nj\ni\nh\ng\nf\n"`
169 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG -10lr`
170 checktest "$a" "$o" 20
172 a=`printf "o\nn\nm\nl\n"`
173 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG +10cr`
174 checktest "$a" "$o" 21
176 a=`printf "o\nn\nm\nl\nk\n"`
177 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG -10cr`
178 checktest "$a" "$o" 22
181 # For reasons that are presumably as accidental as they are ancient, legacy
182 # (and closed) Solaris tail(1) allows +c, +l and -l to be aliases for +10c,
183 # +10l and -10l, respectively. If we are on SunOS, verify that this silly
184 # behavior is functional.
186 if [[ `uname -s` == "SunOS" ]]; then
187 o=`printf "yyz\n"`
188 a=`printf "xyyyyyyyyyyz\n" | $PROG +c`
189 checktest "$a" "$o" 16a
191 o=`printf "y\ny\nz\n"`
192 a=`printf "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz\n" | $PROG +l`
193 checktest "$a" "$o" 17a
195 o=`printf "y\ny\ny\ny\ny\ny\ny\ny\ny\nz\n"`
196 a=`printf "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz\n" | $PROG -l`
197 checktest "$a" "$o" 18a
199 a=`printf "o\nn\nm\nl\nk\nj\ni\nh\ng\n"`
201 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG +lr`
202 checktest "$a" "$o" 19a
204 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG +l -r`
205 checktest "$a" "$o" 19a
207 a=`printf "o\nn\nm\nl\nk\nj\ni\nh\ng\nf\n"`
209 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG -lr`
210 checktest "$a" "$o" 20a
212 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG -l -r`
213 checktest "$a" "$o" 20b
215 a=`printf "o\nn\nm\nl\n"`
217 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG +cr`
218 checktest "$a" "$o" 21a
220 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG +c -r`
221 checktest "$a" "$o" 21a
223 a=`printf "o\nn\nm\nl\nk\n"`
225 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG -cr`
226 checktest "$a" "$o" 22a
228 o=`printf "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\n" | $PROG -c -r`
229 checktest "$a" "$o" 22b
232 o=`echo -e "c\nb\na"`
233 a=`echo -e "a\nb\nc" | $PROG -r`
234 checktest "$a" "$o" 23
237 # Now we want to do a series of follow tests.
239 if [[ $DIR == "" ]]; then
240 export TMPDIR=/var/tmp
241 tdir=$(mktemp -d -t tailtest.XXXXXXXX || exit 1)
242 else
243 tdir=$(mktemp -d $DIR/tailtest.XXXXXXXX || exit 1)
246 follow=$tdir/follow
247 moved=$tdir/follow.moved
248 out=$tdir/out
251 # First, verify that following works in its most basic sense.
253 echo -e "a\nb\nc" > $follow
254 $PROG -f $follow > $out 2> /dev/null &
255 child=$!
256 sleep 2
257 echo -e "d\ne\nf" >> $follow
258 sleep 1
259 kill $child
260 sleep 1
262 o=`echo -e "a\nb\nc\nd\ne\nf\n"`
263 a=`cat $out`
264 checktest "$a" "$o" 24
265 rm $follow
268 # Now verify that following correctly follows the file being moved.
270 echo -e "a\nb\nc" > $follow
271 $PROG -f $follow > $out 2> /dev/null &
272 child=$!
273 sleep 2
274 mv $follow $moved
276 echo -e "d\ne\nf" >> $moved
277 sleep 1
278 kill $child
279 sleep 1
281 o=`echo -e "a\nb\nc\nd\ne\nf\n"`
282 a=`cat $out`
283 checktest "$a" "$o" 25
284 rm $moved
287 # And now truncation with the new offset being less than the old offset.
289 echo -e "a\nb\nc" > $follow
290 $PROG -f $follow > $out 2> /dev/null &
291 child=$!
292 sleep 2
293 echo -e "d\ne\nf" >> $follow
294 sleep 1
295 echo -e "g\nh\ni" > $follow
296 sleep 1
297 kill $child
298 sleep 1
300 o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\n"`
301 a=`cat $out`
302 checktest "$a" "$o" 26
303 rm $follow
306 # And truncation with the new offset being greater than the old offset.
308 echo -e "a\nb\nc" > $follow
309 sleep 1
310 $PROG -f $follow > $out 2> /dev/null &
311 child=$!
312 sleep 2
313 echo -e "d\ne\nf" >> $follow
314 sleep 1
315 echo -e "g\nh\ni\nj\nk\nl\nm\no\np\nq" > $follow
316 sleep 1
317 kill $child
318 sleep 1
320 o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\no\np\nq"`
321 a=`cat $out`
322 checktest "$a" "$o" 27
323 rm $follow
326 # Verify that we can follow the moved file and correctly see a truncation.
328 echo -e "a\nb\nc" > $follow
329 $PROG -f $follow > $out 2> /dev/null &
330 child=$!
331 sleep 2
332 mv $follow $moved
334 echo -e "d\ne\nf" >> $moved
335 sleep 1
336 echo -e "g\nh\ni\nj\nk\nl\nm\no\np\nq" > $moved
337 sleep 1
338 kill $child
339 sleep 1
341 o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\no\np\nq"`
342 a=`cat $out`
343 checktest "$a" "$o" 28
344 rm $moved
347 # Verify that capital-F follow properly deals with truncation
349 echo -e "a\nb\nc" > $follow
350 $PROG -F $follow > $out 2> /dev/null &
351 child=$!
352 sleep 2
353 echo -e "d\ne\nf" >> $follow
354 sleep 1
355 echo -e "g\nh\ni" > $follow
356 sleep 1
357 kill $child
358 sleep 1
360 o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\n"`
361 a=`cat $out`
362 checktest "$a" "$o" 29
363 rm $follow
366 # Verify that capital-F follow _won't_ follow the moved file and will
367 # correctly deal with recreation of the original file.
369 echo -e "a\nb\nc" > $follow
370 $PROG -F $follow > $out 2> /dev/null &
371 child=$!
372 sleep 2
373 mv $follow $moved
375 echo -e "x\ny\nz" >> $moved
378 # At this point, tail is polling on stat'ing the missing file; we need to
379 # be sure to sleep long enough after recreating it to know that it will pick
380 # it up.
382 echo -e "d\ne\nf" > $follow
383 sleep 5
384 kill $child
385 sleep 1
387 o=`echo -e "a\nb\nc\nd\ne\nf\n"`
388 a=`cat $out`
389 checktest "$a" "$o" 30
390 rm $moved
393 # Verify that following two files works.
395 echo -e "one" > $follow
396 echo -e "two" > $moved
397 $PROG -f $follow $moved > $out 2> /dev/null &
398 child=$!
399 sleep 2
400 echo -e "three" >> $follow
401 sleep 1
402 echo -e "four" >> $moved
403 sleep 1
404 echo -e "five" >> $follow
405 sleep 1
406 kill $child
407 sleep 1
409 # There is a bug where the content comes before the header lines,
410 # where rlines/mapprint happens before the header. A pain to fix.
411 # In this test, just make sure we see both files change.
412 o="one
414 ==> $follow <==
417 ==> $moved <==
419 ==> $follow <==
420 three
422 ==> $moved <==
423 four
425 ==> $follow <==
426 five"
427 a=`cat $out`
428 checktest "$a" "$o" 31
429 rm $follow $moved
431 if [[ `uname -s` == "SunOS" ]]; then
433 # Use DTrace to truncate the file between the return from port_get()
434 # and the reassociation of the file object with the port, exposing
435 # any race conditions whereby FILE_TRUNC events are lost.
437 cat /dev/null > $follow
438 dtrace -c "$PROG -f $follow" -s /dev/stdin > $out <<EOF
439 #pragma D option destructive
440 #pragma D option quiet
442 pid\$target::port_get:return
443 /++i == 5/
445 stop();
446 system("cat /dev/null > $follow");
447 system("prun %d", pid);
450 tick-1sec
452 system("echo %d >> $follow", j++);
455 tick-1sec
456 /j == 10/
458 exit(0);
462 o=`echo -e "0\n1\n2\n3\n5\n6\n7\n8\n9\n"`
463 a=`cat $out`
464 checktest "$a" "$o" 31a
465 rm $follow
467 cat /dev/null > $follow
468 dtrace -c "$PROG -f $follow" -s /dev/stdin > $out <<EOF
469 #pragma D option destructive
470 #pragma D option quiet
472 pid\$target::port_get:return
473 /++i == 5/
475 stop();
476 system("mv $follow $moved");
477 system("cat /dev/null > $moved");
478 system("prun %d", pid);
481 tick-1sec
483 system("echo %d >> %s", j++,
484 i < 5 ? "$follow" : "$moved");
487 tick-1sec
488 /j == 10/
490 exit(0);
494 o=`echo -e "0\n1\n2\n3\n5\n6\n7\n8\n9\n"`
495 a=`cat $out`
496 checktest "$a" "$o" 31b
497 rm $moved
500 # Verify that -F will deal properly with the file being truncated
501 # not by truncation, but rather via an ftruncate() from logadm.
503 cat /dev/null > $follow
504 ( $PROG -F $follow > $out ) &
505 child=$!
506 echo -e "a\nb\nc\nd\ne\nf" >> $follow
507 logadm -c $follow
508 sleep 2
509 echo -e "g\nh\ni" >> $follow
510 sleep 2
511 kill $child
512 sleep 1
514 o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\n"`
515 a=`cat $out`
516 checktest "$a" "$o" 31c
520 # We're now going to test that while we may miss output due to truncations
521 # occurring faster than tail can read, we don't ever repeat output.
523 cat /dev/null > $follow
524 ( $PROG -f $follow > $out ) &
525 tchild=$!
526 ( let i=0 ; while true; do echo $i > $follow ; sleep 0.1; let i=i+1 ; done ) &
527 child=$!
528 sleep 10
529 kill $tchild
530 kill $child
532 a=`sort $out | uniq -c | sort -n | tail -1 | awk '{ print $1 }'`
535 checktest "$a" "$o" 32
537 # Test different ways of specifying character offsets
538 o=`printf "d\n"`
540 a=`printf "hello\nworld\n" | $PROG -c2`
541 checktest "$a" "$o" 33
543 a=`printf "hello\nworld\n" | $PROG -c-2`
544 checktest "$a" "$o" 34
546 a=`printf "hello\nworld\n" | $PROG -c 2`
547 checktest "$a" "$o" 35
549 a=`printf "hello\nworld\n" | $PROG -c -2`
550 checktest "$a" "$o" 36
552 a=`printf "hello\nworld\n" | $PROG -2c`
553 checktest "$a" "$o" 37
555 o=`printf "llo\nworld\n"`
557 a=`printf "hello\nworld\n" | $PROG -c +3`
558 checktest "$a" "$o" 38
560 a=`printf "hello\nworld\n" | $PROG -c+3`
561 checktest "$a" "$o" 39
563 a=`printf "hello\nworld\n" | $PROG +3c`
564 checktest "$a" "$o" 40
566 # Test various ways of specifying block offsets
567 o=`printf "$BLOCK"`
569 a=`printf "${BLOCK//./x}$BLOCK" | $PROG -b1`
570 checktest "$a" "$o" 41
572 a=`printf "${BLOCK//./x}$BLOCK" | $PROG -b 1`
573 checktest "$a" "$o" 42
575 a=`printf "${BLOCK//./x}$BLOCK" | $PROG -b -1`
576 checktest "$a" "$o" 43
578 a=`printf "${BLOCK//./x}$BLOCK" | $PROG -b +2`
579 checktest "$a" "$o" 44
581 # Test that illegal arguments aren't allowed
583 checkfail +b2
584 checkfail +c3
585 checkfail -l3
586 checkfail -cz
587 checkfail -bz
588 checkfail -nz
589 checkfail -3n
590 checkfail +3n
591 checkfail +n3
592 checkfail -lfoobar
594 echo "$CMD: completed"
596 exit $errs