diff --git a/tail_test.go b/tail_test.go index 6d602a4..d874c7b 100644 --- a/tail_test.go +++ b/tail_test.go @@ -47,10 +47,43 @@ func TestMustExist(t *testing.T) { if err != nil { t.Error("MustExist:true on an existing file is violated") } - tail.Stop() tail.Cleanup() } +func TestWaitsForFileToExist(_t *testing.T) { + t := NewTailTest("waits-for-file-to-exist", _t) + tail := t.StartTail("test.txt", Config{}) + go t.VerifyTailOutput(tail, []string{"hello", "world"}) + + <-time.After(100 * time.Millisecond) + t.CreateFile("test.txt", "hello\nworld\n") + t.Cleanup(tail) +} + +func TestWaitsForFileToExistRelativePath(_t *testing.T) { + t := NewTailTest("waits-for-file-to-exist-relative", _t) + + oldWD, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + os.Chdir(t.path) + defer os.Chdir(oldWD) + + tail, err := TailFile("test.txt", Config{}) + if err != nil { + t.Fatal(err) + } + + go t.VerifyTailOutput(tail, []string{"hello", "world"}) + + <-time.After(100 * time.Millisecond) + if err := ioutil.WriteFile("test.txt", []byte("hello\nworld\n"), 0600); err != nil { + t.Fatal(err) + } + t.Cleanup(tail) +} + func TestStop(t *testing.T) { tail, err := TailFile("_no_such_file", Config{Follow: true, MustExist: false}) if err != nil { @@ -70,15 +103,10 @@ func TestStopAtEOF(_t *testing.T) { // read "hello" <-tail.Lines - done := make(chan struct{}) - go func() { - <-time.After(100 * time.Millisecond) - t.VerifyTailOutput(tail, []string{"there", "world"}) - close(done) - }() + <-time.After(100 * time.Millisecond) + t.VerifyTailOutput(tail, []string{"there", "world"}) tail.StopAtEOF() - <-done - tail.Cleanup() + t.Cleanup(tail) } func MaxLineSizeT(_t *testing.T, follow bool, fileContent string, expected []string) { @@ -91,8 +119,7 @@ func MaxLineSizeT(_t *testing.T, follow bool, fileContent string, expected []str // to read all lines. <-time.After(100 * time.Millisecond) t.RemoveFile("test.txt") - tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } func TestMaxLineSizeFollow(_t *testing.T) { @@ -115,8 +142,7 @@ func TestOver4096ByteLine(_t *testing.T) { // to read all lines. <-time.After(100 * time.Millisecond) t.RemoveFile("test.txt") - tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } func TestOver4096ByteLineWithSetMaxLineSize(_t *testing.T) { t := NewTailTest("Over4096ByteLineMaxLineSize", _t) @@ -129,8 +155,7 @@ func TestOver4096ByteLineWithSetMaxLineSize(_t *testing.T) { // to read all lines. <-time.After(100 * time.Millisecond) t.RemoveFile("test.txt") - // tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } func TestLocationFull(_t *testing.T) { @@ -143,8 +168,7 @@ func TestLocationFull(_t *testing.T) { // to read all lines. <-time.After(100 * time.Millisecond) t.RemoveFile("test.txt") - tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } func TestLocationFullDontFollow(_t *testing.T) { @@ -158,8 +182,7 @@ func TestLocationFullDontFollow(_t *testing.T) { t.AppendFile("test.txt", "more\ndata\n") <-time.After(100 * time.Millisecond) - tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } func TestLocationEnd(_t *testing.T) { @@ -175,8 +198,7 @@ func TestLocationEnd(_t *testing.T) { // to read all lines. <-time.After(100 * time.Millisecond) t.RemoveFile("test.txt") - tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } func TestLocationMiddle(_t *testing.T) { @@ -193,8 +215,7 @@ func TestLocationMiddle(_t *testing.T) { // to read all lines. <-time.After(100 * time.Millisecond) t.RemoveFile("test.txt") - tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } func _TestReOpen(_t *testing.T, poll bool) { @@ -225,7 +246,7 @@ func _TestReOpen(_t *testing.T, poll bool) { <-time.After(delay) t.RenameFile("test.txt", "test.txt.rotated") <-time.After(delay) - t.CreateFile("test.txt", "endofworld") + t.CreateFile("test.txt", "endofworld\n") // Delete after a reasonable delay, to give tail sufficient time // to read all lines. @@ -236,8 +257,7 @@ func _TestReOpen(_t *testing.T, poll bool) { // Do not bother with stopping as it could kill the tomb during // the reading of data written above. Timings can vary based on // test environment. - // tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } // The use of polling file watcher could affect file rotation @@ -279,8 +299,7 @@ func _TestReSeek(_t *testing.T, poll bool) { // Do not bother with stopping as it could kill the tomb during // the reading of data written above. Timings can vary based on // test environment. - // tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } // The use of polling file watcher could affect file rotation @@ -319,8 +338,7 @@ func TestRateLimiting(_t *testing.T) { <-time.After(100 * time.Millisecond) t.RemoveFile("test.txt") - // tail.Stop() - tail.Cleanup() + t.Cleanup(tail) } func TestTell(_t *testing.T) { @@ -384,11 +402,12 @@ func TestBlockUntilExists(_t *testing.T) { type TailTest struct { Name string path string + done chan struct{} *testing.T } func NewTailTest(name string, t *testing.T) TailTest { - tt := TailTest{name, ".test/" + name, t} + tt := TailTest{name, ".test/" + name, make(chan struct{}), t} err := os.MkdirAll(tt.path, os.ModeTemporary|0700) if err != nil { tt.Fatal(err) @@ -453,6 +472,7 @@ func (t TailTest) StartTail(name string, config Config) *Tail { } func (t TailTest) VerifyTailOutput(tail *Tail, lines []string) { + defer close(t.done) for idx, line := range lines { tailedLine, ok := <-tail.Lines if !ok { @@ -475,8 +495,18 @@ func (t TailTest) VerifyTailOutput(tail *Tail, lines []string) { line, tailedLine.Text) } } + if tail.Follow { + return + } line, ok := <-tail.Lines if ok { t.Fatalf("more content from tail: %+v", line) } } + +func (t TailTest) Cleanup(tail *Tail) { + <-time.After(100 * time.Millisecond) + tail.Stop() + tail.Cleanup() + <-t.done +}