Print this page
3484 enhance and document tail follow support
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
@@ -11,131 +11,357 @@
# at http://www.illumos.org/license/CDDL.
#
#
# Copyright 2010 Chris Love. All rights reserved.
+# Copyright (c) 2013, Joyent, Inc. All rights reserved.
#
+checktest()
+{
+ local actual=$1
+ local output=$2
+ local test=$3
+ if [[ "$actual" != "$output" ]]; then
+ echo "$CMD: test $test: FAIL"
+ echo -e "$CMD: test $test: expected output:\n$o"
+ echo -e "$CMD: test $test: actual output:\n$a"
+ else
+ echo "$CMD: test $test: pass"
+ fi
+}
+
#
# Test cases for 'tail', some based on CoreUtils test cases (validated
-# with legacy Solaris 'tail' and/or xpg4 'tail')
+# with legacy Solaris 'tail' and/or xpg4 'tail'). Note that this is designed
+# to be able to run on BSD systems as well to check our behavior against
+# theirs (some behavior that is known to be idiosyncratic to illumos is
+# skipped on non-illumos systems).
#
PROG=/usr/bin/tail
+CMD=`basename $0`
+DIR=""
-case $1 in
+while [[ $# -gt 0 ]]; do
+ case $1 in
-x)
PROG=/usr/xpg4/bin/tail
+ shift
;;
-o)
PROG=$2
+ shift 2
;;
- -?)
- echo "Usage: tailtests.sh [-x][-o <override tail executable>]"
+ -d)
+ DIR=$2
+ shift 2
+ ;;
+ *)
+ echo "Usage: tailtests.sh" \
+ "[-x][-o <override tail executable>]" \
+ "[-d <override output directory>]"
exit 1
;;
-esac
+ esac
+done
-echo "Using $PROG"
+#
+# Shut bash up upon receiving a term so we can drop it on our children
+# without disrupting the output.
+#
+trap "exit 0" TERM
+echo "$CMD: program is $PROG"
+
+if [[ $DIR != "" ]]; then
+ echo "$CMD: directory is $DIR"
+fi
+
o=`echo -e "bcd"`
a=`echo -e "abcd" | $PROG +2c`
-[[ "$a" != "$o" ]] && echo "Fail test 1 - $a"
+checktest "$a" "$o" 1
o=`echo -e ""`
a=`echo "abcd" | $PROG +8c`
-[[ "$a" != "$o" ]] && echo "Fail test 2 - $a"
+checktest "$a" "$o" 2
o=`echo -e "abcd"`
a=`echo "abcd" | $PROG -9c`
-[[ "$a" != "$o" ]] && echo "Fail test 3 - $a"
+checktest "$a" "$o" 3
o=`echo -e "x"`
a=`echo -e "x" | $PROG -1l`
-[[ "$a" != "x" ]] && echo "Fail test 4 - $a"
+checktest "$a" "$o" 4
o=`echo -e "\n"`
a=`echo -e "x\ny\n" | $PROG -1l`
-[[ "$a" != "$o" ]] && echo "Fail test 5 - $a"
+checktest "$a" "$o" 5
o=`echo -e "y\n"`
a=`echo -e "x\ny\n" | $PROG -2l`
-[[ "$a" != "$o" ]] && echo "Fail test 6 - $a"
+checktest "$a" "$o" 6
o=`echo -e "y"`
a=`echo -e "x\ny" | $PROG -1l`
-[[ "$a" != "$o" ]] && echo "Fail test 7 - $a"
+checktest "$a" "$o" 7
o=`echo -e "x\ny\n"`
a=`echo -e "x\ny\n" | $PROG +1l`
-[[ "$a" != "$o" ]] && echo "Fail test 8 - $a"
+checktest "$a" "$o" 8
o=`echo -e "y\n"`
a=`echo -e "x\ny\n" | $PROG +2l`
-[[ "$a" != "$o" ]] && echo "Fail test 9 - $a"
+checktest "$a" "$o" 9
o=`echo -e "x"`
a=`echo -e "x" | $PROG -1`
-[[ "$a" != "$o" ]] && echo "Fail test 10 - $a"
+checktest "$a" "$o" 10
o=`echo -e "\n"`
a=`echo -e "x\ny\n" | $PROG -1`
-[[ "$a" != "$o" ]] && echo "Fail test 11 - $a"
+checktest "$a" "$o" 11
o=`echo -e "y\n"`
a=`echo -e "x\ny\n" | $PROG -2`
-[[ "$a" != "$o" ]] && echo "Fail test 12 - $a"
+checktest "$a" "$o" 12
o=`echo -e "y"`
a=`echo -e "x\ny" | $PROG -1`
-[[ "$a" != "$o" ]] && echo "Fail test 13 - $a"
+checktest "$a" "$o" 13
o=`echo -e "x\ny\n"`
a=`echo -e "x\ny\n" | $PROG +1`
-[[ "$a" != "$o" ]] && echo "Fail test 14 - $a"
+checktest "$a" "$o" 14
o=`echo -e "y\n"`
a=`echo -e "x\ny\n" | $PROG +2`
-[[ "$a" != "$o" ]] && echo "Fail test 15 - $a"
+checktest "$a" "$o" 15
-# For compatibility with Legacy Solaris tail this should also work as '+c'
o=`echo -e "yyz"`
a=`echo -e "xyyyyyyyyyyz" | $PROG +10c`
-[[ "$a" != "$o" ]] && echo "Fail test 16 - $a"
+checktest "$a" "$o" 16
-o=`echo -e "yyz"`
-a=`echo -e "xyyyyyyyyyyz" | $PROG +c`
-[[ "$a" != "$o" ]] && echo "Fail test 16a - $a"
-
-
-# For compatibility with Legacy Solaris tail this should also work as '+l'
o=`echo -e "y\ny\nz"`
a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG +10l`
-[[ "$a" != "$o" ]] && echo "Fail test 17 - $a"
+checktest "$a" "$o" 17
-o=`echo -e "y\ny\nz"`
-a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG +l`
-[[ "$a" != "$o" ]] && echo "Fail test 17a - $a"
-
-
-# For compatibility with Legacy Solaris tail this should also work as '-l'
o=`echo -e "y\ny\ny\ny\ny\ny\ny\ny\ny\nz"`
a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG -10l`
-[[ "$a" != "$o" ]] && echo "Fail test 18 - $a"
+checktest "$a" "$o" 18
-o=`echo -e "y\ny\ny\ny\ny\ny\ny\ny\ny\nz"`
-a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG -l`
-[[ "$a" != "$o" ]] && echo "Fail test 18a - $a"
+#
+# For reasons that are presumably as accidental as they are ancient, legacy
+# (and closed) Solaris tail(1) allows +c, +l and -l to be aliases for +10c,
+# +10l and -10l, respectively. If we are on SunOS, verify that this silly
+# behavior is functional.
+#
+if [[ `uname -s` == "SunOS" ]]; then
+ o=`echo -e "yyz"`
+ a=`echo -e "xyyyyyyyyyyz" | $PROG +c`
+ checktest "$a" "$o" 16a
+ o=`echo -e "y\ny\nz"`
+ a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG +l`
+ checktest "$a" "$o" 17a
+
+ o=`echo -e "y\ny\ny\ny\ny\ny\ny\ny\ny\nz"`
+ a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG -l`
+ checktest "$a" "$o" 18a
+fi
+
o=`echo -e "c\nb\na"`
a=`echo -e "a\nb\nc" | $PROG -r`
-[[ "$a" != "$o" ]] && echo "Fail test 19 - $a"
+checktest "$a" "$o" 19
+#
+# Now we want to do a series of follow tests.
+#
+if [[ $DIR == "" ]]; then
+ tdir=$(mktemp -d -t tailtest.XXXXXXXX || exit 1)
+else
+ tdir=$(mktemp -d $DIR/tailtest.XXXXXXXX || exit 1)
+fi
-echo "Completed"
+follow=$tdir/follow
+moved=$tdir/follow.moved
+out=$tdir/out
-exit 0
+#
+# First, verify that following works in its most basic sense.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "d\ne\nf" >> $follow
+sleep 1
+kill $child
+sleep 1
-# Template for additional test cases
-#o=`echo -e ""`
-#a=`echo -e "" | $PROG `
-#[[ "$a" != "$o" ]] && echo "Fail test - $a"
+o=`echo -e "a\nb\nc\nd\ne\nf\n"`
+a=`cat $out`
+checktest "$a" "$o" 20
+rm $follow
+
+#
+# Now verify that following correctly follows the file being moved.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+mv $follow $moved
+
+echo -e "d\ne\nf" >> $moved
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\n"`
+a=`cat $out`
+checktest "$a" "$o" 21
+rm $moved
+
+#
+# And now truncation with the new offset being less than the old offset.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "d\ne\nf" >> $follow
+sleep 1
+echo -e "g\nh\ni" > $follow
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\n"`
+a=`cat $out`
+checktest "$a" "$o" 22
+rm $follow
+
+#
+# And truncation with the new offset being greater than the old offset.
+#
+echo -e "a\nb\nc" > $follow
+sleep 1
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "d\ne\nf" >> $follow
+sleep 1
+echo -e "g\nh\ni\nj\nk\nl\nm\no\np\nq" > $follow
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\no\np\nq"`
+a=`cat $out`
+checktest "$a" "$o" 23
+rm $follow
+
+#
+# Verify that we can follow the moved file and correctly see a truncation.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+mv $follow $moved
+
+echo -e "d\ne\nf" >> $moved
+sleep 1
+echo -e "g\nh\ni\nj\nk\nl\nm\no\np\nq" > $moved
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\no\np\nq"`
+a=`cat $out`
+checktest "$a" "$o" 24
+rm $moved
+
+#
+# Verify that capital-F follow properly deals with truncation
+#
+echo -e "a\nb\nc" > $follow
+$PROG -F $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "d\ne\nf" >> $follow
+sleep 1
+echo -e "g\nh\ni" > $follow
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\n"`
+a=`cat $out`
+checktest "$a" "$o" 25
+rm $follow
+
+#
+# Verify that capital-F follow _won't_ follow the moved file and will
+# correctly deal with recreation of the original file.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -F $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+mv $follow $moved
+
+echo -e "x\ny\nz" >> $moved
+echo -e "d\ne\nf" > $follow
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\n"`
+a=`cat $out`
+checktest "$a" "$o" 26
+rm $moved
+
+#
+# Verify that following two files works.
+#
+echo -e "one" > $follow
+echo -e "two" > $moved
+$PROG -f $follow $moved > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "three" >> $follow
+sleep 1
+echo -e "four" >> $moved
+sleep 1
+echo -e "five" >> $follow
+sleep 1
+kill $child
+sleep 1
+
+# There is a bug where the content comes before the header lines,
+# where rlines/mapprint happens before the header. A pain to fix.
+# In this test, just make sure we see both files change.
+o="one
+
+==> $follow <==
+two
+
+==> $moved <==
+
+==> $follow <==
+three
+
+==> $moved <==
+four
+
+==> $follow <==
+five"
+a=`cat $out`
+checktest "$a" "$o" 27
+rm $follow $moved
+
+echo "$CMD: completed"
+
+exit $errs
+