Wait for goroutines to finish before leaving test functions.
VerifyTailOutput is started in a goroutine, but the test function doesn't wait for this goroutine to exit before returning, so any errors raised by VerifyTailOutput after the function returns are lost. Also add a failing test for tailing a file with a relative path.
This commit is contained in:
parent
4b368d1590
commit
0da4e86639
91
tail_test.go
91
tail_test.go
|
@ -6,15 +6,14 @@
|
||||||
package tail
|
package tail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"./watch"
|
|
||||||
"github.com/ActiveState/tail/ratelimiter"
|
"github.com/ActiveState/tail/ratelimiter"
|
||||||
|
"github.com/ActiveState/tail/watch"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -44,6 +43,40 @@ func TestMustExist(t *testing.T) {
|
||||||
tail.Cleanup()
|
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) {
|
func TestStop(t *testing.T) {
|
||||||
tail, err := TailFile("_no_such_file", Config{Follow: true, MustExist: false})
|
tail, err := TailFile("_no_such_file", Config{Follow: true, MustExist: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -65,8 +98,7 @@ func MaxLineSizeT(_t *testing.T, follow bool, fileContent string, expected []str
|
||||||
// to read all lines.
|
// to read all lines.
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
tail.Stop()
|
t.Cleanup(tail)
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMaxLineSizeFollow(_t *testing.T) {
|
func TestMaxLineSizeFollow(_t *testing.T) {
|
||||||
|
@ -89,9 +121,9 @@ func TestOver4096ByteLine(_t *testing.T) {
|
||||||
// to read all lines.
|
// to read all lines.
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
tail.Stop()
|
t.Cleanup(tail)
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOver4096ByteLineWithSetMaxLineSize(_t *testing.T) {
|
func TestOver4096ByteLineWithSetMaxLineSize(_t *testing.T) {
|
||||||
t := NewTailTest("Over4096ByteLineMaxLineSize", _t)
|
t := NewTailTest("Over4096ByteLineMaxLineSize", _t)
|
||||||
testString := strings.Repeat("a", 4097)
|
testString := strings.Repeat("a", 4097)
|
||||||
|
@ -103,8 +135,7 @@ func TestOver4096ByteLineWithSetMaxLineSize(_t *testing.T) {
|
||||||
// to read all lines.
|
// to read all lines.
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
// tail.Stop()
|
t.Cleanup(tail)
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocationFull(_t *testing.T) {
|
func TestLocationFull(_t *testing.T) {
|
||||||
|
@ -117,8 +148,7 @@ func TestLocationFull(_t *testing.T) {
|
||||||
// to read all lines.
|
// to read all lines.
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
tail.Stop()
|
t.Cleanup(tail)
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocationFullDontFollow(_t *testing.T) {
|
func TestLocationFullDontFollow(_t *testing.T) {
|
||||||
|
@ -132,8 +162,7 @@ func TestLocationFullDontFollow(_t *testing.T) {
|
||||||
t.AppendFile("test.txt", "more\ndata\n")
|
t.AppendFile("test.txt", "more\ndata\n")
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
|
|
||||||
tail.Stop()
|
t.Cleanup(tail)
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocationEnd(_t *testing.T) {
|
func TestLocationEnd(_t *testing.T) {
|
||||||
|
@ -149,8 +178,7 @@ func TestLocationEnd(_t *testing.T) {
|
||||||
// to read all lines.
|
// to read all lines.
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
tail.Stop()
|
t.Cleanup(tail)
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocationMiddle(_t *testing.T) {
|
func TestLocationMiddle(_t *testing.T) {
|
||||||
|
@ -167,8 +195,7 @@ func TestLocationMiddle(_t *testing.T) {
|
||||||
// to read all lines.
|
// to read all lines.
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
tail.Stop()
|
t.Cleanup(tail)
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func _TestReOpen(_t *testing.T, poll bool) {
|
func _TestReOpen(_t *testing.T, poll bool) {
|
||||||
|
@ -199,7 +226,7 @@ func _TestReOpen(_t *testing.T, poll bool) {
|
||||||
<-time.After(delay)
|
<-time.After(delay)
|
||||||
t.RenameFile("test.txt", "test.txt.rotated")
|
t.RenameFile("test.txt", "test.txt.rotated")
|
||||||
<-time.After(delay)
|
<-time.After(delay)
|
||||||
t.CreateFile("test.txt", "endofworld")
|
t.CreateFile("test.txt", "endofworld\n")
|
||||||
|
|
||||||
// Delete after a reasonable delay, to give tail sufficient time
|
// Delete after a reasonable delay, to give tail sufficient time
|
||||||
// to read all lines.
|
// to read all lines.
|
||||||
|
@ -207,11 +234,7 @@ func _TestReOpen(_t *testing.T, poll bool) {
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
<-time.After(delay)
|
<-time.After(delay)
|
||||||
|
|
||||||
// Do not bother with stopping as it could kill the tomb during
|
t.Cleanup(tail)
|
||||||
// the reading of data written above. Timings can vary based on
|
|
||||||
// test environment.
|
|
||||||
// tail.Stop()
|
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The use of polling file watcher could affect file rotation
|
// The use of polling file watcher could affect file rotation
|
||||||
|
@ -250,11 +273,7 @@ func _TestReSeek(_t *testing.T, poll bool) {
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
|
|
||||||
// Do not bother with stopping as it could kill the tomb during
|
t.Cleanup(tail)
|
||||||
// the reading of data written above. Timings can vary based on
|
|
||||||
// test environment.
|
|
||||||
// tail.Stop()
|
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The use of polling file watcher could affect file rotation
|
// The use of polling file watcher could affect file rotation
|
||||||
|
@ -293,8 +312,7 @@ func TestRateLimiting(_t *testing.T) {
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
t.RemoveFile("test.txt")
|
t.RemoveFile("test.txt")
|
||||||
|
|
||||||
// tail.Stop()
|
t.Cleanup(tail)
|
||||||
tail.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTell(_t *testing.T) {
|
func TestTell(_t *testing.T) {
|
||||||
|
@ -336,11 +354,12 @@ func TestTell(_t *testing.T) {
|
||||||
type TailTest struct {
|
type TailTest struct {
|
||||||
Name string
|
Name string
|
||||||
path string
|
path string
|
||||||
|
done chan struct{}
|
||||||
*testing.T
|
*testing.T
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTailTest(name string, t *testing.T) TailTest {
|
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)
|
err := os.MkdirAll(tt.path, os.ModeTemporary|0700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tt.Fatal(err)
|
tt.Fatal(err)
|
||||||
|
@ -408,7 +427,19 @@ func (t TailTest) StartTail(name string, config Config) *Tail {
|
||||||
return tail
|
return tail
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t TailTest) Cleanup(tail *Tail) {
|
||||||
|
<-time.After(100 * time.Millisecond)
|
||||||
|
tail.Stop()
|
||||||
|
tail.Cleanup()
|
||||||
|
|
||||||
|
// VerifyTailOutput runs in a goroutine so ensure it's finished before ending
|
||||||
|
// the test, otherwise its failures will be ignored.
|
||||||
|
<-t.done
|
||||||
|
}
|
||||||
|
|
||||||
func (t TailTest) VerifyTailOutput(tail *Tail, lines []string) {
|
func (t TailTest) VerifyTailOutput(tail *Tail, lines []string) {
|
||||||
|
defer close(t.done)
|
||||||
|
|
||||||
for idx, line := range lines {
|
for idx, line := range lines {
|
||||||
tailedLine, ok := <-tail.Lines
|
tailedLine, ok := <-tail.Lines
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
Loading…
Reference in New Issue