mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
test_tail: a lot of minor improvements
* fix test_retry7 * fix test_follow_descriptor_vs_rename2 * set permissions with set_permissions instead of a call to chmod * improve documentation
This commit is contained in:
parent
2e918813c1
commit
94fe42634b
1 changed files with 120 additions and 79 deletions
|
@ -119,16 +119,17 @@ fn test_nc_0_wo_follow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(all(unix, not(target_os = "freebsd")))]
|
||||||
#[cfg(feature = "chmod")]
|
|
||||||
fn test_nc_0_wo_follow2() {
|
fn test_nc_0_wo_follow2() {
|
||||||
// verify that -[nc]0 without -f, exit without reading
|
// verify that -[nc]0 without -f, exit without reading
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
at.touch("unreadable");
|
use std::os::unix::fs::PermissionsExt;
|
||||||
ts.ccmd("chmod").arg("0").arg("unreadable").succeeds();
|
at.make_file("unreadable")
|
||||||
|
.set_permissions(PermissionsExt::from_mode(0o000))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
ts.ucmd()
|
ts.ucmd()
|
||||||
.set_stdin(Stdio::null())
|
.set_stdin(Stdio::null())
|
||||||
|
@ -147,14 +148,15 @@ fn test_nc_0_wo_follow2() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(all(unix, not(target_os = "freebsd")))]
|
||||||
#[cfg(feature = "chmod")]
|
|
||||||
fn test_permission_denied() {
|
fn test_permission_denied() {
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
at.touch("unreadable");
|
use std::os::unix::fs::PermissionsExt;
|
||||||
ts.ccmd("chmod").arg("0").arg("unreadable").succeeds();
|
at.make_file("unreadable")
|
||||||
|
.set_permissions(PermissionsExt::from_mode(0o000))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
ts.ucmd()
|
ts.ucmd()
|
||||||
.set_stdin(Stdio::null())
|
.set_stdin(Stdio::null())
|
||||||
|
@ -166,16 +168,18 @@ fn test_permission_denied() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(all(unix, not(target_os = "freebsd")))]
|
||||||
#[cfg(feature = "chmod")]
|
|
||||||
fn test_permission_denied_multiple() {
|
fn test_permission_denied_multiple() {
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
at.touch("file1");
|
at.touch("file1");
|
||||||
at.touch("file2");
|
at.touch("file2");
|
||||||
at.touch("unreadable");
|
|
||||||
ts.ccmd("chmod").arg("0").arg("unreadable").succeeds();
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
at.make_file("unreadable")
|
||||||
|
.set_permissions(PermissionsExt::from_mode(0o000))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
ts.ucmd()
|
ts.ucmd()
|
||||||
.set_stdin(Stdio::null())
|
.set_stdin(Stdio::null())
|
||||||
|
@ -276,7 +280,7 @@ fn test_follow_stdin_name_retry() {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
#[cfg(disable_until_fixed)]
|
#[cfg(disable_until_fixed)]
|
||||||
fn test_follow_stdin_explicit_indefinitely() {
|
fn test_follow_stdin_explicit_indefinitely() {
|
||||||
// see: "gnu/tests/tail-2/follow-stdin.sh"
|
// inspired by: "gnu/tests/tail-2/follow-stdin.sh"
|
||||||
// tail -f - /dev/null </dev/tty
|
// tail -f - /dev/null </dev/tty
|
||||||
// tail: warning: following standard input indefinitely is ineffective
|
// tail: warning: following standard input indefinitely is ineffective
|
||||||
// ==> standard input <==
|
// ==> standard input <==
|
||||||
|
@ -331,7 +335,7 @@ fn test_follow_stdin_explicit_indefinitely() {
|
||||||
#[cfg(disable_until_fixed)]
|
#[cfg(disable_until_fixed)]
|
||||||
fn test_follow_bad_fd() {
|
fn test_follow_bad_fd() {
|
||||||
// Provoke a "bad file descriptor" error by closing the fd
|
// Provoke a "bad file descriptor" error by closing the fd
|
||||||
// see: "gnu/tests/tail-2/follow-stdin.sh"
|
// inspired by: "gnu/tests/tail-2/follow-stdin.sh"
|
||||||
|
|
||||||
// `$ tail -f <&-` OR `$ tail -f - <&-`
|
// `$ tail -f <&-` OR `$ tail -f - <&-`
|
||||||
// tail: cannot fstat 'standard input': Bad file descriptor
|
// tail: cannot fstat 'standard input': Bad file descriptor
|
||||||
|
@ -1051,7 +1055,7 @@ fn test_num_with_undocumented_sign_bytes() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn test_bytes_for_funny_files() {
|
fn test_bytes_for_funny_files() {
|
||||||
// gnu/tests/tail-2/tail-c.sh
|
// inspired by: gnu/tests/tail-2/tail-c.sh
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
for file in ["/proc/version", "/sys/kernel/profiling"] {
|
for file in ["/proc/version", "/sys/kernel/profiling"] {
|
||||||
|
@ -1071,7 +1075,7 @@ fn test_bytes_for_funny_files() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn test_retry1() {
|
fn test_retry1() {
|
||||||
// gnu/tests/tail-2/retry.sh
|
// inspired by: gnu/tests/tail-2/retry.sh
|
||||||
// Ensure --retry without --follow results in a warning.
|
// Ensure --retry without --follow results in a warning.
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
|
@ -1088,7 +1092,7 @@ fn test_retry1() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn test_retry2() {
|
fn test_retry2() {
|
||||||
// gnu/tests/tail-2/retry.sh
|
// inspired by: gnu/tests/tail-2/retry.sh
|
||||||
// The same as test_retry2 with a missing file: expect error message and exit 1.
|
// The same as test_retry2 with a missing file: expect error message and exit 1.
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
|
@ -1111,7 +1115,7 @@ fn test_retry2() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_retry3() {
|
fn test_retry3() {
|
||||||
// gnu/tests/tail-2/retry.sh
|
// inspired by: gnu/tests/tail-2/retry.sh
|
||||||
// Ensure that `tail --retry --follow=name` waits for the file to appear.
|
// Ensure that `tail --retry --follow=name` waits for the file to appear.
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
|
@ -1146,7 +1150,7 @@ fn test_retry3() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_retry4() {
|
fn test_retry4() {
|
||||||
// gnu/tests/tail-2/retry.sh
|
// inspired by: gnu/tests/tail-2/retry.sh
|
||||||
// Ensure that `tail --retry --follow=descriptor` waits for the file to appear.
|
// Ensure that `tail --retry --follow=descriptor` waits for the file to appear.
|
||||||
// Ensure truncation is detected.
|
// Ensure truncation is detected.
|
||||||
|
|
||||||
|
@ -1159,7 +1163,7 @@ fn test_retry4() {
|
||||||
tail: 'missing' has appeared; following new file\n\
|
tail: 'missing' has appeared; following new file\n\
|
||||||
tail: missing: file truncated\n";
|
tail: missing: file truncated\n";
|
||||||
let expected_stdout = "X1\nX\n";
|
let expected_stdout = "X1\nX\n";
|
||||||
let delay = 100;
|
let delay = 1000;
|
||||||
let mut args = vec![
|
let mut args = vec![
|
||||||
"-s.1",
|
"-s.1",
|
||||||
"--max-unchanged-stats=1",
|
"--max-unchanged-stats=1",
|
||||||
|
@ -1193,7 +1197,7 @@ fn test_retry4() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_retry5() {
|
fn test_retry5() {
|
||||||
// gnu/tests/tail-2/retry.sh
|
// inspired by: gnu/tests/tail-2/retry.sh
|
||||||
// Ensure that `tail --follow=descriptor --retry` exits when the file appears untailable.
|
// Ensure that `tail --follow=descriptor --retry` exits when the file appears untailable.
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
|
@ -1227,7 +1231,7 @@ fn test_retry5() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_retry6() {
|
fn test_retry6() {
|
||||||
// gnu/tests/tail-2/retry.sh
|
// inspired by: gnu/tests/tail-2/retry.sh
|
||||||
// Ensure that --follow=descriptor (without --retry) does *not* try
|
// Ensure that --follow=descriptor (without --retry) does *not* try
|
||||||
// to open a file after an initial fail, even when there are other tailable files.
|
// to open a file after an initial fail, even when there are other tailable files.
|
||||||
|
|
||||||
|
@ -1265,19 +1269,22 @@ fn test_retry6() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_retry7() {
|
fn test_retry7() {
|
||||||
// gnu/tests/tail-2/retry.sh
|
// inspired by: gnu/tests/tail-2/retry.sh
|
||||||
// Ensure that `tail -F` retries when the file is initially untailable.
|
// Ensure that `tail -F` retries when the file is initially untailable.
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
let untailable = "untailable";
|
let untailable = "untailable";
|
||||||
|
|
||||||
|
// tail: 'untailable' has appeared; following new file\n\
|
||||||
|
// tail: 'untailable' has become inaccessible: No such file or directory\n\
|
||||||
|
// tail: 'untailable' has appeared; following new file\n";
|
||||||
let expected_stderr = "tail: error reading 'untailable': Is a directory\n\
|
let expected_stderr = "tail: error reading 'untailable': Is a directory\n\
|
||||||
tail: untailable: cannot follow end of this type of file\n\
|
tail: untailable: cannot follow end of this type of file\n\
|
||||||
tail: 'untailable' has appeared; following new file\n\
|
tail: 'untailable' has become accessible\n\
|
||||||
tail: 'untailable' has become inaccessible: No such file or directory\n\
|
tail: 'untailable' has become inaccessible: No such file or directory\n\
|
||||||
tail: 'untailable' has been replaced with an untailable file\n\
|
tail: 'untailable' has been replaced with an untailable file\n\
|
||||||
tail: 'untailable' has appeared; following new file\n";
|
tail: 'untailable' has become accessible\n";
|
||||||
let expected_stdout = "foo\nbar\n";
|
let expected_stdout = "foo\nbar\n";
|
||||||
|
|
||||||
let delay = 1000;
|
let delay = 1000;
|
||||||
|
@ -1364,15 +1371,22 @@ fn test_retry8() {
|
||||||
.run_no_wait();
|
.run_no_wait();
|
||||||
sleep(Duration::from_millis(delay));
|
sleep(Duration::from_millis(delay));
|
||||||
|
|
||||||
at.mkdir(parent_dir);
|
// 'parent_dir/watched_file' is orphan
|
||||||
|
// tail: cannot open 'parent_dir/watched_file' for reading: No such file or directory\n\
|
||||||
|
|
||||||
|
// tail: 'parent_dir/watched_file' has appeared; following new file\n\
|
||||||
|
at.mkdir(parent_dir); // not an orphan anymore
|
||||||
at.append(user_path, "foo\n");
|
at.append(user_path, "foo\n");
|
||||||
sleep(Duration::from_millis(delay));
|
sleep(Duration::from_millis(delay));
|
||||||
|
|
||||||
|
// tail: 'parent_dir/watched_file' has become inaccessible: No such file or directory\n\
|
||||||
at.remove(user_path);
|
at.remove(user_path);
|
||||||
at.rmdir(parent_dir);
|
at.rmdir(parent_dir); // 'parent_dir/watched_file' is orphan *again*
|
||||||
sleep(Duration::from_millis(delay));
|
sleep(Duration::from_millis(delay));
|
||||||
|
|
||||||
at.mkdir(parent_dir);
|
// Since 'parent_dir/watched_file' is orphan, this needs to be picked up by polling
|
||||||
|
// tail: 'parent_dir/watched_file' has appeared; following new file\n";
|
||||||
|
at.mkdir(parent_dir); // not an orphan anymore
|
||||||
at.append(user_path, "bar\n");
|
at.append(user_path, "bar\n");
|
||||||
sleep(Duration::from_millis(delay));
|
sleep(Duration::from_millis(delay));
|
||||||
|
|
||||||
|
@ -1386,7 +1400,7 @@ fn test_retry8() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux
|
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux
|
||||||
fn test_retry9() {
|
fn test_retry9() {
|
||||||
// gnu/tests/tail-2/inotify-dir-recreate.sh
|
// inspired by: gnu/tests/tail-2/inotify-dir-recreate.sh
|
||||||
// Ensure that inotify will switch to polling mode if directory
|
// Ensure that inotify will switch to polling mode if directory
|
||||||
// of the watched file was removed and recreated.
|
// of the watched file was removed and recreated.
|
||||||
|
|
||||||
|
@ -1461,7 +1475,7 @@ fn test_retry9() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_follow_descriptor_vs_rename1() {
|
fn test_follow_descriptor_vs_rename1() {
|
||||||
// gnu/tests/tail-2/descriptor-vs-rename.sh
|
// inspired by: gnu/tests/tail-2/descriptor-vs-rename.sh
|
||||||
// $ ((rm -f A && touch A && sleep 1 && echo -n "A\n" >> A && sleep 1 && \
|
// $ ((rm -f A && touch A && sleep 1 && echo -n "A\n" >> A && sleep 1 && \
|
||||||
// mv A B && sleep 1 && echo -n "B\n" >> B &)>/dev/null 2>&1 &) ; \
|
// mv A B && sleep 1 && echo -n "B\n" >> B &)>/dev/null 2>&1 &) ; \
|
||||||
// sleep 1 && target/debug/tail --follow=descriptor A ---disable-inotify
|
// sleep 1 && target/debug/tail --follow=descriptor A ---disable-inotify
|
||||||
|
@ -1519,6 +1533,7 @@ fn test_follow_descriptor_vs_rename1() {
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_follow_descriptor_vs_rename2() {
|
fn test_follow_descriptor_vs_rename2() {
|
||||||
// Ensure the headers are correct for --verbose.
|
// Ensure the headers are correct for --verbose.
|
||||||
|
// NOTE: GNU's tail does not update the header from FILE_A to FILE_C after `mv FILE_A FILE_C`
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
@ -1533,19 +1548,18 @@ fn test_follow_descriptor_vs_rename2() {
|
||||||
file_a,
|
file_a,
|
||||||
file_b,
|
file_b,
|
||||||
"--verbose",
|
"--verbose",
|
||||||
// TODO: [2021-05; jhscheer] fix this for `--use-polling`
|
"---disable-inotify",
|
||||||
/*"---disable-inotify",*/
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let delay = 100;
|
let delay = 100;
|
||||||
for _ in 0..1 {
|
for _ in 0..2 {
|
||||||
at.touch(file_a);
|
at.touch(file_a);
|
||||||
at.touch(file_b);
|
at.touch(file_b);
|
||||||
let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait();
|
let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait();
|
||||||
sleep(Duration::from_millis(delay));
|
sleep(Duration::from_millis(delay));
|
||||||
at.rename(file_a, file_c);
|
at.rename(file_a, file_c);
|
||||||
sleep(Duration::from_millis(1000));
|
sleep(Duration::from_millis(1000));
|
||||||
at.append(file_c, "x\n");
|
at.append(file_c, "X\n");
|
||||||
sleep(Duration::from_millis(delay));
|
sleep(Duration::from_millis(delay));
|
||||||
p.kill().unwrap();
|
p.kill().unwrap();
|
||||||
sleep(Duration::from_millis(delay));
|
sleep(Duration::from_millis(delay));
|
||||||
|
@ -1553,7 +1567,7 @@ fn test_follow_descriptor_vs_rename2() {
|
||||||
let (buf_stdout, buf_stderr) = take_stdout_stderr(&mut p);
|
let (buf_stdout, buf_stderr) = take_stdout_stderr(&mut p);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
buf_stdout,
|
buf_stdout,
|
||||||
"==> FILE_A <==\n\n==> FILE_B <==\n\n==> FILE_A <==\nx\n"
|
"==> FILE_A <==\n\n==> FILE_B <==\n\n==> FILE_A <==\nX\n"
|
||||||
);
|
);
|
||||||
assert!(buf_stderr.is_empty());
|
assert!(buf_stderr.is_empty());
|
||||||
|
|
||||||
|
@ -1564,8 +1578,8 @@ fn test_follow_descriptor_vs_rename2() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn test_follow_name_remove() {
|
fn test_follow_name_remove() {
|
||||||
// This test triggers a remove event while `tail --follow=name logfile` is running.
|
// This test triggers a remove event while `tail --follow=name file` is running.
|
||||||
// ((sleep 2 && rm logfile &)>/dev/null 2>&1 &) ; tail --follow=name logfile
|
// ((sleep 2 && rm file &)>/dev/null 2>&1 &) ; tail --follow=name file
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
@ -1611,8 +1625,8 @@ fn test_follow_name_remove() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_follow_name_truncate1() {
|
fn test_follow_name_truncate1() {
|
||||||
// This test triggers a truncate event while `tail --follow=name logfile` is running.
|
// This test triggers a truncate event while `tail --follow=name file` is running.
|
||||||
// $ cp logfile backup && head logfile > logfile && sleep 1 && cp backup logfile
|
// $ cp file backup && head file > file && sleep 1 && cp backup file
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
@ -1645,14 +1659,14 @@ fn test_follow_name_truncate1() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn test_follow_name_truncate2() {
|
fn test_follow_name_truncate2() {
|
||||||
// This test triggers a truncate event while `tail --follow=name logfile` is running.
|
// This test triggers a truncate event while `tail --follow=name file` is running.
|
||||||
// $ ((sleep 1 && echo -n "x\nx\nx\n" >> logfile && sleep 1 && \
|
// $ ((sleep 1 && echo -n "x\nx\nx\n" >> file && sleep 1 && \
|
||||||
// echo -n "x\n" > logfile &)>/dev/null 2>&1 &) ; tail --follow=name logfile
|
// echo -n "x\n" > file &)>/dev/null 2>&1 &) ; tail --follow=name file
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
let source = "logfile";
|
let source = "file";
|
||||||
at.touch(source);
|
at.touch(source);
|
||||||
|
|
||||||
let expected_stdout = "x\nx\nx\nx\n";
|
let expected_stdout = "x\nx\nx\nx\n";
|
||||||
|
@ -1683,13 +1697,13 @@ fn test_follow_name_truncate2() {
|
||||||
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS
|
||||||
fn test_follow_name_truncate3() {
|
fn test_follow_name_truncate3() {
|
||||||
// Opening an empty file in truncate mode should not trigger a truncate event while.
|
// Opening an empty file in truncate mode should not trigger a truncate event while.
|
||||||
// $ rm -f logfile && touch logfile
|
// $ rm -f file && touch file
|
||||||
// $ ((sleep 1 && echo -n "x\n" > logfile &)>/dev/null 2>&1 &) ; tail --follow=name logfile
|
// $ ((sleep 1 && echo -n "x\n" > file &)>/dev/null 2>&1 &) ; tail --follow=name file
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
let source = "logfile";
|
let source = "file";
|
||||||
at.touch(source);
|
at.touch(source);
|
||||||
|
|
||||||
let expected_stdout = "x\n";
|
let expected_stdout = "x\n";
|
||||||
|
@ -1791,8 +1805,8 @@ fn test_follow_truncate_fast() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux
|
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux
|
||||||
fn test_follow_name_move_create() {
|
fn test_follow_name_move_create() {
|
||||||
// This test triggers a move/create event while `tail --follow=name logfile` is running.
|
// This test triggers a move/create event while `tail --follow=name file` is running.
|
||||||
// ((sleep 2 && mv logfile backup && sleep 2 && cp backup logfile &)>/dev/null 2>&1 &) ; tail --follow=name logfile
|
// ((sleep 2 && mv file backup && sleep 2 && cp backup file &)>/dev/null 2>&1 &) ; tail --follow=name file
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
@ -1892,8 +1906,8 @@ fn test_follow_name_move_create2() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux
|
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux
|
||||||
fn test_follow_name_move() {
|
fn test_follow_name_move() {
|
||||||
// This test triggers a move event while `tail --follow=name logfile` is running.
|
// This test triggers a move event while `tail --follow=name file` is running.
|
||||||
// ((sleep 2 && mv logfile backup &)>/dev/null 2>&1 &) ; tail --follow=name logfile
|
// ((sleep 2 && mv file backup &)>/dev/null 2>&1 &) ; tail --follow=name file
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
@ -1936,61 +1950,58 @@ fn test_follow_name_move() {
|
||||||
fn test_follow_name_move2() {
|
fn test_follow_name_move2() {
|
||||||
// Like test_follow_name_move, but move to a name that's already monitored.
|
// Like test_follow_name_move, but move to a name that's already monitored.
|
||||||
|
|
||||||
// $ ((sleep 2 ; mv logfile1 logfile2 ; sleep 1 ; echo "more_logfile2_content" >> logfile2 ; sleep 1 ; \
|
// $ echo file1_content > file1; echo file2_content > file2; \
|
||||||
// echo "more_logfile1_content" >> logfile1 &)>/dev/null 2>&1 &) ; \
|
// ((sleep 2 ; mv file1 file2 ; sleep 1 ; echo "more_file2_content" >> file2 ; sleep 1 ; \
|
||||||
// tail --follow=name logfile1 logfile2
|
// echo "more_file1_content" >> file1 &)>/dev/null 2>&1 &) ; \
|
||||||
// ==> logfile1 <==
|
// tail --follow=name file1 file2
|
||||||
// logfile1_content
|
// ==> file1 <==
|
||||||
|
// file1_content
|
||||||
//
|
//
|
||||||
// ==> logfile2 <==
|
// ==> file2 <==
|
||||||
// logfile2_content
|
// file2_content
|
||||||
// tail: logfile1: No such file or directory
|
// tail: file1: No such file or directory
|
||||||
// tail: 'logfile2' has been replaced; following new file
|
// tail: 'file2' has been replaced; following new file
|
||||||
// logfile1_content
|
// file1_content
|
||||||
// more_logfile2_content
|
// more_file2_content
|
||||||
// tail: 'logfile1' has appeared; following new file
|
// tail: 'file1' has appeared; following new file
|
||||||
//
|
//
|
||||||
// ==> logfile1 <==
|
// ==> file1 <==
|
||||||
// more_logfile1_content
|
// more_file1_content
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
let logfile1 = "logfile1";
|
let file1 = "file1";
|
||||||
let logfile2 = "logfile2";
|
let file2 = "file2";
|
||||||
|
|
||||||
let expected_stdout = format!(
|
let expected_stdout = format!(
|
||||||
"==> {0} <==\n{0}_content\n\n==> {1} <==\n{1}_content\n{0}_content\n\
|
"==> {0} <==\n{0}_content\n\n==> {1} <==\n{1}_content\n{0}_content\n\
|
||||||
more_{1}_content\n\n==> {0} <==\nmore_{0}_content\n",
|
more_{1}_content\n\n==> {0} <==\nmore_{0}_content\n",
|
||||||
logfile1, logfile2
|
file1, file2
|
||||||
);
|
);
|
||||||
let expected_stderr = format!(
|
let expected_stderr = format!(
|
||||||
"{0}: {1}: No such file or directory\n\
|
"{0}: {1}: No such file or directory\n\
|
||||||
{0}: '{2}' has been replaced; following new file\n\
|
{0}: '{2}' has been replaced; following new file\n\
|
||||||
{0}: '{1}' has appeared; following new file\n",
|
{0}: '{1}' has appeared; following new file\n",
|
||||||
ts.util_name, logfile1, logfile2
|
ts.util_name, file1, file2
|
||||||
);
|
);
|
||||||
|
|
||||||
at.append(logfile1, "logfile1_content\n");
|
at.append(file1, "file1_content\n");
|
||||||
at.append(logfile2, "logfile2_content\n");
|
at.append(file2, "file2_content\n");
|
||||||
|
|
||||||
// TODO: [2021-05; jhscheer] fix this for `--use-polling`
|
// TODO: [2021-05; jhscheer] fix this for `--use-polling`
|
||||||
let mut args = vec![
|
let mut args = vec!["--follow=name", file1, file2 /*, "--use-polling" */];
|
||||||
"--follow=name",
|
|
||||||
logfile1,
|
|
||||||
logfile2, /*, "--use-polling" */
|
|
||||||
];
|
|
||||||
|
|
||||||
#[allow(clippy::needless_range_loop)]
|
#[allow(clippy::needless_range_loop)]
|
||||||
for _ in 0..1 {
|
for _ in 0..1 {
|
||||||
let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait();
|
let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait();
|
||||||
|
|
||||||
sleep(Duration::from_millis(1000));
|
sleep(Duration::from_millis(1000));
|
||||||
at.rename(logfile1, logfile2);
|
at.rename(file1, file2);
|
||||||
sleep(Duration::from_millis(1000));
|
sleep(Duration::from_millis(1000));
|
||||||
at.append(logfile2, "more_logfile2_content\n");
|
at.append(file2, "more_file2_content\n");
|
||||||
sleep(Duration::from_millis(1000));
|
sleep(Duration::from_millis(1000));
|
||||||
at.append(logfile1, "more_logfile1_content\n");
|
at.append(file1, "more_file1_content\n");
|
||||||
sleep(Duration::from_millis(1000));
|
sleep(Duration::from_millis(1000));
|
||||||
|
|
||||||
p.kill().unwrap();
|
p.kill().unwrap();
|
||||||
|
@ -2007,7 +2018,7 @@ fn test_follow_name_move2() {
|
||||||
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux
|
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux
|
||||||
fn test_follow_name_move_retry() {
|
fn test_follow_name_move_retry() {
|
||||||
// Similar to test_follow_name_move but with `--retry` (`-F`)
|
// Similar to test_follow_name_move but with `--retry` (`-F`)
|
||||||
// This test triggers two move/rename events while `tail --follow=name --retry logfile` is running.
|
// This test triggers two move/rename events while `tail --follow=name --retry file` is running.
|
||||||
|
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = TestScenario::new(util_name!());
|
||||||
let at = &ts.fixtures;
|
let at = &ts.fixtures;
|
||||||
|
@ -2157,3 +2168,33 @@ fn test_fifo() {
|
||||||
assert!(buf_stderr.is_empty());
|
assert!(buf_stderr.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[cfg(disable_until_fixed)]
|
||||||
|
fn test_illegal_seek() {
|
||||||
|
// This is here for reference only.
|
||||||
|
// We don't call seek on fifos, so we don't hit this error case.
|
||||||
|
// (Also see: https://github.com/coreutils/coreutils/pull/36)
|
||||||
|
|
||||||
|
let ts = TestScenario::new(util_name!());
|
||||||
|
let at = &ts.fixtures;
|
||||||
|
at.append("FILE", "foo\n");
|
||||||
|
at.mkfifo("FIFO");
|
||||||
|
|
||||||
|
let mut p = ts.ucmd().arg("FILE").run_no_wait();
|
||||||
|
sleep(Duration::from_millis(500));
|
||||||
|
at.rename("FILE", "FIFO");
|
||||||
|
sleep(Duration::from_millis(500));
|
||||||
|
|
||||||
|
p.kill().unwrap();
|
||||||
|
let (buf_stdout, buf_stderr) = take_stdout_stderr(&mut p);
|
||||||
|
dbg!(&buf_stdout, &buf_stderr);
|
||||||
|
assert_eq!(buf_stdout, "foo\n");
|
||||||
|
assert_eq!(
|
||||||
|
buf_stderr,
|
||||||
|
"tail: 'FILE' has been replaced; following new file\n\
|
||||||
|
tail: FILE: cannot seek to offset 0: Illegal seek\n"
|
||||||
|
);
|
||||||
|
assert_eq!(p.wait().unwrap().code().unwrap(), 1);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue