]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
tests: fix races in and standardize the tail tests
authorPádraig Brady <P@draigBrady.com>
Sat, 2 May 2015 09:52:37 +0000 (10:52 +0100)
committerPádraig Brady <P@draigBrady.com>
Mon, 11 May 2015 13:41:17 +0000 (14:41 +0100)
* tests/tail-2/F-vs-missing.sh: Use standard "fastpoll" options
(-s.1 --max-unchanged-stats=1) to speedup the non-inotify case.
Add the non-inotify case to the test. `wait` on the background
tail process to terminate which should avoid the need for the
non standard `retry_delay_ cleanup ...` on NFS.
* tests/tail-2/F-vs-rename.sh: Remove 'out' at the start of the loop,
to avoid a race in checking its contents.  Also ensure 'a' & 'b'
files are present before the tail process starts.  Use the standard
"fastpoll" options as above.
* tests/tail-2/f-vs-rename.sh: Likewise.
* tests/tail-2/append-only.sh: Use more standard variable names.
* tests/tail-2/flush-initial.sh: Use "fastpoll" options for
non-inotify platforms.  Also `wait` on the background tail to avoid
stray processes and file cleanup issues on NFS.
* tests/tail-2/inotify-hash-abuse.sh: Always run non-inotify case.
Use "fastpoll" options.  Use a more standard retry_delay_ instead
of a hardcoded sleep loop.  Add a `wait` on the background tail.
* tests/tail-2/inotify-hash-abuse2.sh: Likewise.
* tests/tail-2/inotify-rotate-resources.sh: Wait just on the
specific tail $pid needed.
* tests/tail-2/inotify-rotate.sh: Use "fastpoll" options.
* tests/tail-2/pid.sh: Use standard variable names.
Add a `wait` on the background tails.
* tests/tail-2/pipe-f2.sh: Likewise.
* tests/tail-2/tail-n0f.sh: Likewise.
* tests/tail-2/retry.sh: Use "fastpoll" options.
* tests/tail-2/symlink.sh: Likewise.
* tests/tail-2/wait.sh: Likewise.  Speedup by using sub second
parameters to timeout(1).  Improve the part ensuring that
-F never follows a renamed file.
* tests/tail-2/infloop-1.sh: Remove invalid test.  tail(1) was not
being passed the --pid=$yes_pid option, retry_delay_ wasn't used
to avoid races, and yes could write huge files before being killed.
* tests/local.mk: Remove the invalid test reference.
* tests/tail-2/assert-2.sh: Rewrite using retry_delay_().  Since
no longer hardcoding large delays, remove the VERY_EXPENSIVE tag.
* tests/tail-2/assert.sh: Likewise.

19 files changed:
tests/local.mk
tests/tail-2/F-vs-missing.sh
tests/tail-2/F-vs-rename.sh
tests/tail-2/append-only.sh
tests/tail-2/assert-2.sh
tests/tail-2/assert.sh
tests/tail-2/f-vs-rename.sh
tests/tail-2/flush-initial.sh
tests/tail-2/infloop-1.sh [deleted file]
tests/tail-2/inotify-hash-abuse.sh
tests/tail-2/inotify-hash-abuse2.sh
tests/tail-2/inotify-rotate-resources.sh
tests/tail-2/inotify-rotate.sh
tests/tail-2/pid.sh
tests/tail-2/pipe-f2.sh
tests/tail-2/retry.sh
tests/tail-2/symlink.sh
tests/tail-2/tail-n0f.sh
tests/tail-2/wait.sh

index 1be31ad1df935ab2694fb112064eb4e497940f53..0d4f9df7551ac946e9bc76f35d7e0d6e35e0a87d 100644 (file)
@@ -197,7 +197,6 @@ all_tests =                                 \
   tests/rm/i-1.sh                              \
   tests/rm/i-never.sh                          \
   tests/rm/i-no-r.sh                           \
-  tests/tail-2/infloop-1.sh                    \
   tests/rm/ignorable.sh                                \
   tests/rm/inaccessible.sh                     \
   tests/rm/interactive-always.sh               \
index 5d2cc2fe46afb5a99a486305ef0c5a867c7b8b20..6622f7e428ec06ab8e8834b7a87c8ea3229cd235 100755 (executable)
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ tail
 
-debug='---disable-inotify'
-debug=
-tail $debug -F -s.1 missing/file > out 2>&1 & pid=$!
-
 check_tail_output()
 {
   local delay="$1"
@@ -32,33 +28,31 @@ check_tail_output()
     { sleep $delay; return 1; }
 }
 
-# Wait up to 12.7s for tail to start with diagnostic:
-# tail: cannot open 'missing/file' for reading: No such file or directory
-tail_re='cannot open' retry_delay_ check_tail_output .1 7 || fail=1
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
 
-mkdir missing || fail=1
-(cd missing && echo x > file)
+for mode in '' '---disable-inotify'; do
+  rm -rf out missing
 
-# Wait up to 12.7s for this to appear in the output:
-# "tail: '...' has appeared;  following end of new file"
-tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
-  { echo "$0: file: unexpected delay?"; cat out; fail=1; }
+  tail $mode -F $fastpoll missing/file > out 2>&1 & pid=$!
 
-kill -HUP $pid
+  # Wait up to 12.7s for tail to start with diagnostic:
+  # tail: cannot open 'missing/file' for reading: No such file or directory
+  tail_re='cannot open' retry_delay_ check_tail_output .1 7 ||
+    { cat out; fail=1; }
 
-cleanup()
-{
-  local delay="$1"
-  rm -rf missing ||
-    { sleep $delay; return 1; }
-}
+  mkdir missing || framework_failure_
+  (cd missing && echo x > file) || framework_failure_
+
+  # Wait up to 12.7s for this to appear in the output:
+  # "tail: '...' has appeared;  following end of new file"
+  tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
+    { echo "$0: file: unexpected delay?"; cat out; fail=1; }
+
+  kill $pid
+
+  wait $pid
+done
 
-# Try repeatedly to remove the temporary directory.
-# This is normally unnecessary, because the containing directory will
-# be removed by code from init.sh.  However, when this particular test
-# is run on an NFS-mounted volume, sometimes init.sh's cleanup code
-# fails because the directory is not yet really empty, perhaps because
-# the tail process (reading missing/file) is not yet killed.
-retry_delay_ cleanup .1 6
 
 Exit $fail
index f95b71a6f734b6975a971d0b413cb48bcf08708d..e087ec2e8ca19c7d053f10ac50a7dc531da0f8ad 100755 (executable)
@@ -28,20 +28,25 @@ check_tail_output()
     { sleep $delay; return 1; }
 }
 
-touch a b || framework_failure_
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
 
 for mode in '' '---disable-inotify'; do
-  tail $mode -F -s.1 a b > out 2>&1 & pid=$!
+  rm -f a b out
+  touch a b || framework_failure_
+
+  tail $mode -F $fastpoll a b > out 2>&1 & pid=$!
 
   # Wait up to 12.7s for tail to start.
   echo x > a
-  tail_re='^x$' retry_delay_ check_tail_output .1 7 || fail=1
+  tail_re='^x$' retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
 
-  mv a b || fail=1
+  mv a b || framework_failure_
 
   # Wait 12.7s for this diagnostic:
   # tail: 'a' has become inaccessible: No such file or directory
-  tail_re='inaccessible' retry_delay_ check_tail_output .1 7 || fail=1
+  tail_re='inaccessible' retry_delay_ check_tail_output .1 7 ||
+    { cat out; fail=1; }
 
   echo x > a
   # Wait up to 12.7s for this to appear in the output:
index 8baba7e91a00364db96bca77a13bb2ea2f7a22c7..9da10ae9c2d0573743e17ed1c2aab8dab77f4bcb 100755 (executable)
@@ -32,10 +32,9 @@ if test $chattr_a_works = 0; then
 fi
 
 
-for inotify in ---disable-inotify ''; do
-  sleep 1 &
-  pid=$!
-  tail --pid=$pid -f $inotify f || fail=1
+for mode in '' '---disable-inotify'; do
+  sleep 1 & pid=$!
+  tail --pid=$pid -f $mode f || fail=1
 done
 
 chattr -a f 2>/dev/null
index 2d4671b8c8a660a2c3d8563d08ce1443afd6bc41..aaf8785ae871b889b8154b549835698e74fbd095 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/sh
-# This variant of 'assert' would get a UMR reliably in 2.0.9.
+# This variant of 'assert' would get a Uninit Mem Read reliably in 2.0.9.
 # Due to a race condition in the test, the 'assert' script would get
 # the UMR on Solaris only some of the time, and not at all on Linux/GNU.
 
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ tail
 
-# Not "expensive" per se, but sleeping for so long is annoying.
-very_expensive_
+check_tail_output()
+{
+  local delay="$1"
+  grep "$tail_re" out ||
+    { sleep $delay; return 1; }
+}
 
-ok='ok ok ok'
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
 
-touch a
-tail --follow=name a foo > err 2>&1 &
-tail_pid=$!
-# Arrange for the tail process to die after 12 seconds.
-(sleep 12; kill $tail_pid) &
-echo $ok > f
-echo sleeping for 7 seconds...
-sleep 7
-mv f foo
 
-# echo waiting....
-wait
+for mode in '' '---disable-inotify'; do
+  rm -f a foo out
+  touch a || framework_failure_
 
-case "$(cat err)" in
-  *$ok) ;;
-  *) fail=1;;
-esac
+  tail $mode --follow=name $fastpoll a foo > out 2>&1 & pid=$!
 
-test $fail = 1 && cat err
+  # Wait up to 12.7s for tail to start.
+  echo x > a || framework_failure_
+  tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+    { cat out; fail=1; }
+
+  # Wait up to 12.7s for tail to notice new foo file
+  ok='ok ok ok'
+  echo "$ok" > foo || framework_failure_
+  tail_re="^$ok$" retry_delay_ check_tail_output .1 7 ||
+    { echo "$0: foo: unexpected delay?"; cat out; fail=1; }
+
+  kill $pid
+  wait $pid
+done
 
 Exit $fail
index faf7e32d082f556e5e114936029fb7db8a600a9a..906e364b5d56ecb415063bbe943ce672feb136e2 100755 (executable)
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ tail
 
-# Not "expensive" per se, but sleeping for so long is annoying.
-very_expensive_
-
-ok='ok ok ok'
-
-touch a foo
-tail --follow=name a foo > err 2>&1 &
-tail_pid=$!
-# Arrange for the tail process to die after 12 seconds.
-(sleep 12; kill $tail_pid) &
-
-echo sleeping for 7 seconds...
-
-# Give the backgrounded 'tail' a chance to start before removing foo.
-# Otherwise, without --retry, tail wouldn't try to open 'foo' again.
-sleep 1
-
-rm -f foo
-sleep 6
-echo $ok > f
-mv f foo
-
-# echo waiting....
-wait
-
-case "$(cat err)" in
-  *$ok) ;;
-  *) fail=1;;
-esac
-
-test $fail = 1 && cat err
+check_tail_output()
+{
+  local delay="$1"
+  grep "$tail_re" out ||
+    { sleep $delay; return 1; }
+}
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+
+for mode in '' '---disable-inotify'; do
+  rm -f a foo out
+  touch a foo || framework_failure_
+
+  tail $mode --follow=name $fastpoll a foo > out 2>&1 & pid=$!
+
+  # Wait up to 12.7s for tail to start.
+  echo x > a || framework_failure_
+  tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+    { cat out; fail=1; }
+
+  # Wait 12.7s for this diagnostic:
+  # tail: foo: No such file or directory
+  rm foo || framework_failure_
+  tail_re='No such file' retry_delay_ check_tail_output .1 7 ||
+    { cat out; fail=1; }
+
+  # Wait up to 12.7s for tail to notice new foo file
+  ok='ok ok ok'
+  echo "$ok" > foo || framework_failure_
+  tail_re="^$ok$" retry_delay_ check_tail_output .1 7 ||
+    { echo "$0: foo: unexpected delay?"; cat out; fail=1; }
+
+  kill $pid
+  wait $pid
+done
 
 Exit $fail
index 4bff41ce333b216b383ca2da76ef2a965a339d49..bfd0949b47de764422f3164da48f81b81e131c61 100755 (executable)
@@ -28,20 +28,24 @@ check_tail_output()
     { sleep $delay; return 1; }
 }
 
-touch a || framework_failure_
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
 
 for mode in '' '---disable-inotify'; do
-  tail $mode -f -s.1 a > out 2>&1 & pid=$!
+  rm -f a out
+  touch a || framework_failure_
+
+  tail $mode $fastpoll -f a > out 2>&1 & pid=$!
 
   # Wait up to 12.7s for tail to start.
   echo x > a
-  tail_re='^x$' retry_delay_ check_tail_output .1 7 || fail=1
+  tail_re='^x$' retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
 
-  mv a b || fail=1
+  mv a b || framework_failure_
 
   echo y >> b
   # Wait up to 12.7s for "y" to appear in the output:
-  tail_re='^y$' retry_delay_ check_tail_output .1 7 || fail=1
+  tail_re='^y$' retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
 
   kill $pid
 
index 1c8d6b027653343b00637110a0b1b6281fd860c2..aaeb878f5585aa18603946be197d774fc4191897 100755 (executable)
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ tail
 
-echo line > in || fail=1
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+echo line > in || framework_failure_
 # Output should be buffered since we're writing to file
 # so we're depending on the flush to write out
-tail -f in > out &
-tail_pid=$!
+tail $fastpoll -f in > out & tail_pid=$!
 
 # Wait for 3.1s for the file to be flushed.
 tail_flush()
@@ -37,4 +39,6 @@ retry_delay_ tail_flush .1 5 || fail=1
 
 kill $tail_pid
 
+wait $tail_pid
+
 Exit $fail
diff --git a/tests/tail-2/infloop-1.sh b/tests/tail-2/infloop-1.sh
deleted file mode 100755 (executable)
index 61f9719..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-# This test would fail with tail from pre-1.22i textutils.
-
-# Copyright (C) 1999-2015 Free Software Foundation, Inc.
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
-print_ver_ tail
-
-yes > t &
-yes_pid=$!
-while :; do
-  test -s t \
-    && break
-  sleep .1
-done
-tail -n 1 t &
-tail_pid=$!
-kill $yes_pid
-
-# This test is racy, and can fail under unusual circumstances.
-# On a very busy system, tail will fail to notice that $yes_pid is gone.
-# Then the following kill will succeed and cause this test to fail.
-
-# Wait for up to 3 seconds for tail to detect the death of $yes_pid.
-for i in $(seq 30); do
-    kill -0 $tail_pid || break
-    echo sleep 0.1s
-    sleep .1
-done
-
-kill $tail_pid && fail=1 || :
-
-Exit $fail
index b819b97946c08876b97138a3be7fe48eb5b12811..d8c14c1c5eb29897d38dab4f8972e396aaec8734 100755 (executable)
@@ -23,10 +23,6 @@ print_ver_ tail
 n=9
 seq $n | xargs touch || framework_failure_
 
-debug='---disable-inotify'
-debug=
-tail $debug -s.1 -qF $(seq $n) > out 2>&1 & pid=$!
-
 check_tail_output()
 {
   local delay="$1"
@@ -34,30 +30,39 @@ check_tail_output()
     { sleep $delay; return 1; }
 }
 
-# Wait up to 12.7s for tail to start
-echo x > $n
-tail_re='^x$' retry_delay_ check_tail_output .1 7 || fail=1
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
 
-mv 1 f || fail=1
+for mode in '' '---disable-inotify'; do
+  rm -f out
 
-# Wait 12.7s for this diagnostic:
-# tail: '1' has become inaccessible: No such file or directory
-tail_re='inaccessible' retry_delay_ check_tail_output .1 7 || fail=1
+  tail $mode $fastpoll -qF $(seq $n) > out 2>&1 & pid=$!
 
-# Trigger the bug.  Before the fix, this would provoke the abort.
-echo a > 1 || fail=1
+  # Wait up to 12.7s for tail to start
+  echo x > $n
+  tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+    { cat out; fail=1; }
 
-# Wait up to 2s for the buggy tail to die,
-# or for the "tail: '1' has appeared;  following end of new file" output
-for i in $(seq 10); do
-  kill -0 $pid || break
-  grep 'has appeared;' out > /dev/null && break
-  sleep .2
-done
+  mv 1 f || framework_failure_
+
+  # Wait 12.7s for this diagnostic:
+  # tail: '1' has become inaccessible: No such file or directory
+  tail_re='inaccessible' retry_delay_ check_tail_output .1 7 ||
+    { cat out; fail=1; }
+
+  # Trigger the bug.  Before the fix, this would provoke the abort.
+  echo a > 1 || framework_failure_
 
-# Kill the working tail, or fail if it has already aborted
-kill $pid || fail=1
+  # Wait up to 6.3s for the "tail: '1' has appeared; ..." message
+  # (or for the buggy tail to die)
+  tail_re='has appeared' retry_delay_ check_tail_output .1 6 ||
+    { cat out; fail=1; }
+
+  # Kill the working tail, or fail if it has already aborted
+  kill $pid || fail=1
+
+  wait $pid
+done
 
-cat out
 
 Exit $fail
index 241f26e6d0f76eac2df57a6f21571c8b8f83d59f..b054237951ebeab55ab2992f5c279c3a7d789ae1 100755 (executable)
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ tail
 
-touch f || framework_failure_
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
 
-debug='---disable-inotify -s .001'
-debug=
-tail $debug -F f & pid=$!
-cleanup_() { kill $pid; }
+for mode in '' '---disable-inotify'; do
+  touch f || framework_failure_
 
-for i in $(seq 200); do
-  kill -0 $pid || break;
-  mv f g
-  touch f
-done
+  tail $mode $fastpoll -F f & pid=$!
+
+  for i in $(seq 200); do
+    kill -0 $pid || break;
+    mv f g
+    touch f
+  done
 
-# Kill the working tail, or fail if it has already aborted
-kill $pid || fail=1
+  # Kill the working tail, or fail if it has already aborted
+  kill $pid || fail=1
+
+  wait $pid
+done
 
 Exit $fail
index a43f17689f47306f04a159d5895280f9b426e167..b65ceb7c5b356c5c30b522bccf37d5f5a075aa92 100755 (executable)
@@ -34,10 +34,10 @@ check_tail_output()
 # Wait up to 25.5 seconds for grep REGEXP 'out' to succeed.
 grep_timeout() { tail_re="$1" retry_delay_ check_tail_output .1 8; }
 
-strace_output()
+check_strace()
 {
   local delay="$1"
-  test -s strace.out ||
+  grep "$strace_re" strace.out > /dev/null ||
     { sleep $delay; return 1; }
 }
 
@@ -48,13 +48,15 @@ cleanup_fail()
   fail=1
 }
 
+fastpoll='-s.1 --max-unchanged-stats=1'
+
 # Normally less than a second is required here, but with heavy load
 # and a lot of disk activity, even 20 seconds per grep_timeout is insufficient,
 # which leads to this timeout (used as a safety net for cleanup)
 # killing tail before processing is completed.
 touch k || framework_failure_
-timeout 180 strace -e inotify_rm_watch -o strace.out tail -F k >> out 2>&1 &
-pid=$!
+timeout 180 strace -e inotify_rm_watch -o strace.out \
+  tail -F $fastpoll k >> out 2>&1 & pid=$!
 
 reverted_to_polling_=0
 for i in $(seq 2); do
@@ -82,7 +84,7 @@ for i in $(seq 2); do
     # may not be supported in future, instead being auto scaled to RAM
     # like the Linux epoll resources were.
     if test "$i" -gt 1; then
-      retry_delay_ strace_output .1 8 ||
+      strace_re='inotify_rm_watch' retry_delay_ check_strace .1 8 ||
         { cleanup_fail 'failed to find inotify_rm_watch syscall'; break; }
     fi
 
@@ -91,6 +93,6 @@ done
 
 test "$reverted_to_polling_" = 1 && skip_ 'inotify resources already depleted'
 kill $pid
-wait
+wait $pid
 
 Exit $fail
index 64724f9fd0a8ca09572cbb52b5e29348da538182..be1f07e5bbced6a74a0bd1e42a06acacae95f50f 100755 (executable)
@@ -40,6 +40,9 @@ cleanup_fail()
   fail=1
 }
 
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
 # Perform at least this many iterations, because on multi-core systems
 # the offending sequence of events can be surprisingly uncommon.
 # See: http://lists.gnu.org/archive/html/bug-coreutils/2009-11/msg00213.html
@@ -51,8 +54,7 @@ for i in $(seq 50); do
     # and a lot of disk activity, even 20 seconds is insufficient, which
     # leads to this timeout killing tail before the "ok" is written below.
     >k && >x || framework_failure_ failed to initialize files
-    timeout 60 tail -s.1 --max-unchanged-stats=1 -F k > out 2>&1 &
-    pid=$!
+    timeout 60 tail $fastpoll -F k > out 2>&1 & pid=$!
 
     echo 'tailed' > k;
     # wait for 'tailed' to appear in out
index e6b75a51cfe64ff032f069c4577fe3786ae8ea09..7a4986763b4b8655d4ff285e3b0464d5ee8a3d05 100755 (executable)
@@ -23,28 +23,28 @@ getlimits_
 touch empty here || framework_failure_
 
 
-for inotify in ---disable-inotify ''; do
+for mode in '' '---disable-inotify'; do
   # Use tail itself to create a background process to monitor,
   # which will auto exit when "here" is removed.
-  tail -f $inotify here &
-  bg_pid=$!
+  tail -f $mode here & pid=$!
 
   # Ensure that tail --pid=PID does not exit when PID is alive.
-  timeout 1 tail -f -s.1 --pid=$bg_pid $inotify here
+  timeout 1 tail -f -s.1 --pid=$pid $mode here
   test $? = 124 || fail=1
 
   # Cleanup background process
-  kill $bg_pid
+  kill $pid
+  wait $pid
 
   # Ensure that tail --pid=PID exits with success status when PID is dead.
   # Use an unlikely-to-be-live PID
-  timeout 10 tail -f -s.1 --pid=$PID_T_MAX $inotify empty
+  timeout 10 tail -f -s.1 --pid=$PID_T_MAX $mode empty
   ret=$?
   test $ret = 124 && skip_ "pid $PID_T_MAX present or tail too slow"
   test $ret = 0 || fail=1
 
   # Ensure tail doesn't wait for data when PID is dead
-  timeout 10 tail -f -s10 --pid=$PID_T_MAX $inotify empty
+  timeout 10 tail -f -s10 --pid=$PID_T_MAX $mode empty
   test $? = 124 && fail=1
 done
 
index a40d55295c9aec1dbcee314e83b6b5f4427b0ad5..4d5fe51025491ad6d404ed7857f5d2cd754019ad 100755 (executable)
@@ -24,7 +24,10 @@ mkfifo_or_skip_ fifo
 echo 1 > fifo &
 echo 1 > exp || framework_failure_
 
-timeout 10 tail -f fifo > out & pid=$!
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+timeout 10 tail $fastpoll -f fifo > out & pid=$!
 
 check_tail_output()
 {
@@ -40,4 +43,6 @@ compare exp out || fail=1
 # Kill the still-running tail, or fail if it's gone.
 kill $pid || fail=1
 
+wait $pid
+
 Exit $fail
index 97bd6d3d4619e24ac569d7dd0c2dcdb50727c2ff..6aee9967b948a9f7c0a630df098e587590cb873d 100755 (executable)
@@ -36,27 +36,32 @@ wait4lines_ ()
   [ "$(countlines_)" -ge "$elc" ] || { sleep $delay; return 1; }
 }
 
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
 # === Test:
 # Retry without --follow results in a warning.
 touch file
 tail --retry file > out 2>&1 || fail=1
-[ "$(countlines_)" = 1 ]                     || fail=1
-grep -F 'tail: warning: --retry ignored' out || fail=1
+[ "$(countlines_)" = 1 ]                     || { cat out; fail=1; }
+grep -F 'tail: warning: --retry ignored' out || { cat out; fail=1; }
 
 # === Test:
 # The same with a missing file: expect error message and exit 1.
 tail --retry missing > out 2>&1 && fail=1
-[ "$(countlines_)" = 2 ]                     || fail=1
-grep -F 'tail: warning: --retry ignored' out || fail=1
+[ "$(countlines_)" = 2 ]                     || { cat out; fail=1; }
+grep -F 'tail: warning: --retry ignored' out || { cat out; fail=1; }
 
 # === Test:
 # Ensure that "tail --retry --follow=name" waits for the file to appear.
 # Clear 'out' so that we can check its contents without races
 >out                            || framework_failure_
-timeout 10 tail -s.1 --follow=name --retry missing >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 1 || fail=1  # Wait for "cannot open" error.
-echo "X" > missing              || fail=1
-retry_delay_ wait4lines_ .1 6 3 || fail=1  # Wait for the expected output.
+timeout 10 tail $fastpoll --follow=name --retry missing >out 2>&1 & pid=$!
+# Wait for "cannot open" error.
+retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
+echo "X" > missing              || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 3 || { cat out; fail=1; }
 kill $pid
 wait $pid
 # Expect 3 lines in the output file.
@@ -69,10 +74,12 @@ rm -f missing out          || framework_failure_
 # === Test:
 # Ensure that "tail --retry --follow=descriptor" waits for the file to appear.
 # tail-8.21 failed at this (since the implementation of the inotify support).
-timeout 10 tail -s.1 --follow=descriptor --retry missing >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 2 || fail=1  # Wait for "cannot open" error.
-echo "X" > missing              || fail=1
-retry_delay_ wait4lines_ .1 6 4 || fail=1  # Wait for the expected output.
+timeout 10 tail $fastpoll --follow=descriptor --retry missing >out 2>&1 & pid=$!
+# Wait for "cannot open" error.
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+echo "X" > missing              || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
 kill $pid
 wait $pid
 # Expect 4 lines in the output file.
@@ -87,10 +94,12 @@ rm -f missing out          || framework_failure_
 # === Test:
 # Ensure that tail --follow=descriptor --retry exits when the file appears
 # untailable. Expect exit status 1.
-timeout 10 tail -s.1 --follow=descriptor --retry missing >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 2 || fail=1  # Wait for "cannot open" error.
-mkdir missing                   || fail=1  # Create untailable 'missing'.
-retry_delay_ wait4lines_ .1 6 4 || fail=1  # Wait for the expected output.
+timeout 10 tail $fastpoll --follow=descriptor --retry missing >out 2>&1 & pid=$!
+# Wait for "cannot open" error.
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+mkdir missing                   || framework_failure_  # Create untailable
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
 wait $pid
 rc=$?
 [ "$(countlines_)" = 4 ]                       || { fail=1; cat out; }
index 274df958758c3e5d670bd183edb84f4259007ad5..9f1a2010f00eeba1858791eaba106a02fc0ad72f 100755 (executable)
@@ -36,15 +36,20 @@ wait4lines_ ()
   [ "$(countlines_)" -ge "$elc" ] || { sleep $delay; return 1; }
 }
 
+# speedup non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
 # Ensure changing targets of cli specified symlinks are handled.
 # Prior to v8.22, inotify would fail to recognize changes in the targets.
 # Clear 'out' so that we can check its contents without races.
 >out                            || framework_failure_
 ln -nsf target symlink          || framework_failure_
-timeout 10 tail -s.1 -F symlink >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 1 || fail=1  # Wait for "cannot open..."
-echo "X" > target               || fail=1
-retry_delay_ wait4lines_ .1 6 3 || fail=1  # Wait for the expected output.
+timeout 10 tail $fastpoll -F symlink >out 2>&1 & pid=$!
+# Wait for "cannot open..."
+retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
+echo "X" > target               || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 3 || { cat out; fail=1; }
 kill $pid
 wait $pid
 # Expect 3 lines in the output file.
@@ -60,12 +65,15 @@ rm -f target out           || framework_failure_
 >out                            || framework_failure_
 echo "X1" > target1             || framework_failure_
 ln -nsf target1 symlink         || framework_failure_
-timeout 10 tail -s.1 -F symlink >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 1 || fail=1  # Wait for the expected output.
+timeout 10 tail $fastpoll -F symlink >out 2>&1 & pid=$!
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
 ln -nsf target2 symlink         || framework_failure_
-retry_delay_ wait4lines_ .1 6 2 || fail=1  # Wait for "become inaccess..."
-echo "X2" > target2             || fail=1
-retry_delay_ wait4lines_ .1 6 4 || fail=1  # Wait for the expected output.
+# Wait for "become inaccess..."
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+echo "X2" > target2             || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
 kill $pid
 wait $pid
 # Expect 4 lines in the output file.
index 26a7b26b4740c6fbdeedfa2efa0688945b94bc9d..f713a1257b87a35461b4bd906d7e243ac5496ac2 100755 (executable)
@@ -35,11 +35,10 @@ chmod 0 unreadable || framework_failure_
 tail -c0 unreadable || fail=1
 tail -n0 unreadable || fail=1
 
-for inotify in ---disable-inotify ''; do
+for mode in '' '---disable-inotify'; do
   for file in empty nonempty; do
     for c_or_n in c n; do
-      tail --sleep=4 -${c_or_n} 0 -f $inotify $file &
-      pid=$!
+      tail --sleep=4 -${c_or_n} 0 -f $mode $file & pid=$!
       tail_sleeping()
       {
         local delay="$1"; sleep $delay
@@ -53,6 +52,7 @@ for inotify in ---disable-inotify ''; do
       retry_delay_ tail_sleeping .1 4 ||
         { echo $0: process in unexpected state: $state >&2; fail=1; }
       kill $pid
+      wait $pid
     done
   done
 done
index 839fcf69553905d63f111ffb1f731998fda87bf8..ebae62bd24226268a3097392aaf42497beaffabf 100755 (executable)
@@ -23,30 +23,32 @@ print_ver_ tail
 touch here || framework_failure_
 { touch unreadable && chmod a-r unreadable; } || framework_failure_
 
+# speedup non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
 
-for inotify in ---disable-inotify ''; do
-  timeout 10 tail -s0.1 -f $inotify not_here
+for mode in '' '---disable-inotify'; do
+  timeout 10 tail $fastpoll -f $mode not_here
   test $? = 124 && fail=1
 
   if test ! -r unreadable; then # can't test this when root
-    timeout 10 tail -s0.1 -f $inotify unreadable
+    timeout 10 tail $fastpoll -f $mode unreadable
     test $? = 124 && fail=1
   fi
 
-  timeout 1 tail -s0.1 -f $inotify here 2>tail.err
+  timeout .1 tail $fastpoll -f $mode here 2>tail.err
   test $? = 124 || fail=1
 
   # 'tail -F' must wait in any case.
 
-  timeout 1 tail -s0.1 -F $inotify here 2>>tail.err
+  timeout .1 tail $fastpoll -F $mode here 2>>tail.err
   test $? = 124 || fail=1
 
   if test ! -r unreadable; then # can't test this when root
-    timeout 1 tail -s0.1 -F $inotify unreadable
+    timeout .1 tail $fastpoll -F $mode unreadable
     test $? = 124 || fail=1
   fi
 
-  timeout 1 tail -s0.1 -F $inotify not_here
+  timeout .1 tail $fastpoll -F $mode not_here
   test $? = 124 || fail=1
 
   grep -Ev 'inotify (resources exhausted|cannot be used)' tail.err > x
@@ -54,13 +56,14 @@ for inotify in ---disable-inotify ''; do
   compare /dev/null tail.err || fail=1
   >tail.err
 
+  # Ensure -F never follows a descriptor after rename
+  # either with tiny or significant delays between operations
   tail_F()
   {
     local delay="$1"
 
     touch k || framework_failure_
-    tail -s.1 --max-unchanged-stats=2 -F $inotify k > tail.out &
-    pid=$!
+    tail $fastpoll -F $mode k > tail.out & pid=$!
     sleep $delay
     mv k l
     sleep $delay
@@ -70,11 +73,13 @@ for inotify in ---disable-inotify ''; do
     echo NO >> l
     sleep $delay
     kill $pid
+    wait $pid
     rm -f k l
 
-    test -s tail.out
+    test -s tail.out
   }
-  retry_delay_ tail_F .1 4 || fail=1
+  retry_delay_ tail_F 0 1 && { cat tail.out; fail=1; }
+  retry_delay_ tail_F .2 1 && { cat tail.out; fail=1; }
 done
 
 Exit $fail