From 8ee3ca4bb96f61ed5fc12da1d751a29fec6f7979 Mon Sep 17 00:00:00 2001 From: =?utf8?q?P=C3=A1draig=20Brady?= Date: Sat, 2 May 2015 10:52:37 +0100 Subject: [PATCH] tests: fix races in and standardize the tail tests * 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. --- tests/local.mk | 1 - tests/tail-2/F-vs-missing.sh | 48 +++++++++----------- tests/tail-2/F-vs-rename.sh | 15 ++++-- tests/tail-2/append-only.sh | 7 ++- tests/tail-2/{f-vs-rename.sh => assert-2.sh} | 33 ++++++++------ tests/tail-2/assert.sh | 68 +++++++++++++++------------- tests/tail-2/f-vs-rename.sh | 14 ++++-- tests/tail-2/flush-initial.sh | 10 ++-- tests/tail-2/infloop-1.sh | 46 ------------------- tests/tail-2/inotify-hash-abuse.sh | 51 +++++++++++---------- tests/tail-2/inotify-hash-abuse2.sh | 28 +++++++----- tests/tail-2/inotify-rotate-resources.sh | 14 +++--- tests/tail-2/inotify-rotate.sh | 6 ++- tests/tail-2/pid.sh | 14 +++--- tests/tail-2/pipe-f2.sh | 7 ++- tests/tail-2/retry.sh | 41 ++++++++++------- tests/tail-2/symlink.sh | 26 +++++++---- tests/tail-2/tail-n0f.sh | 6 +-- tests/tail-2/wait.sh | 27 ++++++----- 19 files changed, 236 insertions(+), 226 deletions(-) copy tests/tail-2/{f-vs-rename.sh => assert-2.sh} (54%) delete mode 100755 tests/tail-2/infloop-1.sh diff --git a/tests/local.mk b/tests/local.mk index 1be31ad1d..0d4f9df75 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -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 \ diff --git a/tests/tail-2/F-vs-missing.sh b/tests/tail-2/F-vs-missing.sh index 5d2cc2fe4..6622f7e42 100755 --- a/tests/tail-2/F-vs-missing.sh +++ b/tests/tail-2/F-vs-missing.sh @@ -21,10 +21,6 @@ . "${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 diff --git a/tests/tail-2/F-vs-rename.sh b/tests/tail-2/F-vs-rename.sh index f95b71a6f..e087ec2e8 100755 --- a/tests/tail-2/F-vs-rename.sh +++ b/tests/tail-2/F-vs-rename.sh @@ -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: diff --git a/tests/tail-2/append-only.sh b/tests/tail-2/append-only.sh index 8baba7e91..9da10ae9c 100755 --- a/tests/tail-2/append-only.sh +++ b/tests/tail-2/append-only.sh @@ -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 diff --git a/tests/tail-2/f-vs-rename.sh b/tests/tail-2/assert-2.sh similarity index 54% copy from tests/tail-2/f-vs-rename.sh copy to tests/tail-2/assert-2.sh index 4bff41ce3..aaf8785ae 100755 --- a/tests/tail-2/f-vs-rename.sh +++ b/tests/tail-2/assert-2.sh @@ -1,9 +1,9 @@ #!/bin/sh -# Demonstrate that tail -f works when renaming the tailed files. -# Between coreutils 7.5 and 8.23 inclusive, 'tail -f a' would -# stop tracking additions to b after 'mv a b'. +# 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. -# Copyright (C) 2015 Free Software Foundation, Inc. +# Copyright (C) 2000-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 @@ -28,23 +28,28 @@ 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 foo out + touch a || framework_failure_ - # 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 $mode --follow=name $fastpoll a foo > out 2>&1 & pid=$! - mv a b || fail=1 + # 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; } - 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 + # 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 diff --git a/tests/tail-2/assert.sh b/tests/tail-2/assert.sh index faf7e32d0..906e364b5 100755 --- a/tests/tail-2/assert.sh +++ b/tests/tail-2/assert.sh @@ -26,36 +26,42 @@ . "${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 diff --git a/tests/tail-2/f-vs-rename.sh b/tests/tail-2/f-vs-rename.sh index 4bff41ce3..bfd0949b4 100755 --- a/tests/tail-2/f-vs-rename.sh +++ b/tests/tail-2/f-vs-rename.sh @@ -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 diff --git a/tests/tail-2/flush-initial.sh b/tests/tail-2/flush-initial.sh index 1c8d6b027..aaeb878f5 100755 --- a/tests/tail-2/flush-initial.sh +++ b/tests/tail-2/flush-initial.sh @@ -19,11 +19,13 @@ . "${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 index 61f97194e..000000000 --- a/tests/tail-2/infloop-1.sh +++ /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 . - -. "${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 diff --git a/tests/tail-2/inotify-hash-abuse.sh b/tests/tail-2/inotify-hash-abuse.sh index b819b9794..d8c14c1c5 100755 --- a/tests/tail-2/inotify-hash-abuse.sh +++ b/tests/tail-2/inotify-hash-abuse.sh @@ -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 diff --git a/tests/tail-2/inotify-hash-abuse2.sh b/tests/tail-2/inotify-hash-abuse2.sh index 241f26e6d..b05423795 100755 --- a/tests/tail-2/inotify-hash-abuse2.sh +++ b/tests/tail-2/inotify-hash-abuse2.sh @@ -20,20 +20,24 @@ . "${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 diff --git a/tests/tail-2/inotify-rotate-resources.sh b/tests/tail-2/inotify-rotate-resources.sh index a43f17689..b65ceb7c5 100755 --- a/tests/tail-2/inotify-rotate-resources.sh +++ b/tests/tail-2/inotify-rotate-resources.sh @@ -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 diff --git a/tests/tail-2/inotify-rotate.sh b/tests/tail-2/inotify-rotate.sh index 64724f9fd..be1f07e5b 100755 --- a/tests/tail-2/inotify-rotate.sh +++ b/tests/tail-2/inotify-rotate.sh @@ -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 diff --git a/tests/tail-2/pid.sh b/tests/tail-2/pid.sh index e6b75a51c..7a4986763 100755 --- a/tests/tail-2/pid.sh +++ b/tests/tail-2/pid.sh @@ -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 diff --git a/tests/tail-2/pipe-f2.sh b/tests/tail-2/pipe-f2.sh index a40d55295..4d5fe5102 100755 --- a/tests/tail-2/pipe-f2.sh +++ b/tests/tail-2/pipe-f2.sh @@ -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 diff --git a/tests/tail-2/retry.sh b/tests/tail-2/retry.sh index 97bd6d3d4..6aee9967b 100755 --- a/tests/tail-2/retry.sh +++ b/tests/tail-2/retry.sh @@ -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; } diff --git a/tests/tail-2/symlink.sh b/tests/tail-2/symlink.sh index 274df9587..9f1a2010f 100755 --- a/tests/tail-2/symlink.sh +++ b/tests/tail-2/symlink.sh @@ -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. diff --git a/tests/tail-2/tail-n0f.sh b/tests/tail-2/tail-n0f.sh index 26a7b26b4..f713a1257 100755 --- a/tests/tail-2/tail-n0f.sh +++ b/tests/tail-2/tail-n0f.sh @@ -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 diff --git a/tests/tail-2/wait.sh b/tests/tail-2/wait.sh index 839fcf695..ebae62bd2 100755 --- a/tests/tail-2/wait.sh +++ b/tests/tail-2/wait.sh @@ -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 -- 2.11.4.GIT