Merge pull request #80 from hpcloud/v2-criteria
Support golang 1.6; move to vendoring.
This commit is contained in:
commit
3b00e857b6
11
.travis.yml
11
.travis.yml
|
@ -4,9 +4,14 @@ script:
|
||||||
- go test -race -v ./...
|
- go test -race -v ./...
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.3.3
|
- 1.4
|
||||||
- 1.4.3
|
- 1.5
|
||||||
- 1.5.2
|
- 1.6
|
||||||
|
- tip
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- go get gopkg.in/fsnotify.v1
|
- go get gopkg.in/fsnotify.v1
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
# API current (gopkg.in/ActiveState/tail)
|
# API current (gopkg.in/ActiveState/tail)
|
||||||
|
|
||||||
|
## April, 2016
|
||||||
|
|
||||||
|
* Migrated to godep, as depman is not longer supported
|
||||||
|
* Introduced golang vendoring feature
|
||||||
|
|
||||||
## July, 2015
|
## July, 2015
|
||||||
|
|
||||||
* Fix inotify watcher leak; remove `Cleanup` (#51)
|
* Fix inotify watcher leak; remove `Cleanup` (#51)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/hpcloud/tail",
|
"ImportPath": "github.com/hpcloud/tail",
|
||||||
"GoVersion": "go1.4.2",
|
"GoVersion": "go1.5.1",
|
||||||
"Deps": [
|
"Deps": [
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/fsnotify.v1",
|
"ImportPath": "gopkg.in/fsnotify.v1",
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
/pkg
|
|
||||||
/bin
|
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !plan9,!solaris
|
|
||||||
|
|
||||||
package fsnotify_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/go-fsnotify/fsnotify"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleNewWatcher() {
|
|
||||||
watcher, err := fsnotify.NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer watcher.Close()
|
|
||||||
|
|
||||||
done := make(chan bool)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case event := <-watcher.Events:
|
|
||||||
log.Println("event:", event)
|
|
||||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
|
||||||
log.Println("modified file:", event.Name)
|
|
||||||
}
|
|
||||||
case err := <-watcher.Errors:
|
|
||||||
log.Println("error:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = watcher.Add("/tmp/foo")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
<-done
|
|
||||||
}
|
|
|
@ -1,228 +0,0 @@
|
||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package fsnotify
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testFd [2]int
|
|
||||||
|
|
||||||
func makeTestFd(t *testing.T) testFd {
|
|
||||||
var tfd testFd
|
|
||||||
errno := syscall.Pipe(tfd[:])
|
|
||||||
if errno != nil {
|
|
||||||
t.Fatalf("Failed to create pipe: %v", errno)
|
|
||||||
}
|
|
||||||
return tfd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tfd testFd) fd() int {
|
|
||||||
return tfd[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tfd testFd) closeWrite(t *testing.T) {
|
|
||||||
errno := syscall.Close(tfd[1])
|
|
||||||
if errno != nil {
|
|
||||||
t.Fatalf("Failed to close write end of pipe: %v", errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tfd testFd) put(t *testing.T) {
|
|
||||||
buf := make([]byte, 10)
|
|
||||||
_, errno := syscall.Write(tfd[1], buf)
|
|
||||||
if errno != nil {
|
|
||||||
t.Fatalf("Failed to write to pipe: %v", errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tfd testFd) get(t *testing.T) {
|
|
||||||
buf := make([]byte, 10)
|
|
||||||
_, errno := syscall.Read(tfd[0], buf)
|
|
||||||
if errno != nil {
|
|
||||||
t.Fatalf("Failed to read from pipe: %v", errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tfd testFd) close() {
|
|
||||||
syscall.Close(tfd[1])
|
|
||||||
syscall.Close(tfd[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
func makePoller(t *testing.T) (testFd, *fdPoller) {
|
|
||||||
tfd := makeTestFd(t)
|
|
||||||
poller, err := newFdPoller(tfd.fd())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create poller: %v", err)
|
|
||||||
}
|
|
||||||
return tfd, poller
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPollerWithBadFd(t *testing.T) {
|
|
||||||
_, err := newFdPoller(-1)
|
|
||||||
if err != syscall.EBADF {
|
|
||||||
t.Fatalf("Expected EBADF, got: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPollerWithData(t *testing.T) {
|
|
||||||
tfd, poller := makePoller(t)
|
|
||||||
defer tfd.close()
|
|
||||||
defer poller.close()
|
|
||||||
|
|
||||||
tfd.put(t)
|
|
||||||
ok, err := poller.wait()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("poller failed: %v", err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("expected poller to return true")
|
|
||||||
}
|
|
||||||
tfd.get(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPollerWithWakeup(t *testing.T) {
|
|
||||||
tfd, poller := makePoller(t)
|
|
||||||
defer tfd.close()
|
|
||||||
defer poller.close()
|
|
||||||
|
|
||||||
err := poller.wake()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("wake failed: %v", err)
|
|
||||||
}
|
|
||||||
ok, err := poller.wait()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("poller failed: %v", err)
|
|
||||||
}
|
|
||||||
if ok {
|
|
||||||
t.Fatalf("expected poller to return false")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPollerWithClose(t *testing.T) {
|
|
||||||
tfd, poller := makePoller(t)
|
|
||||||
defer tfd.close()
|
|
||||||
defer poller.close()
|
|
||||||
|
|
||||||
tfd.closeWrite(t)
|
|
||||||
ok, err := poller.wait()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("poller failed: %v", err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("expected poller to return true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPollerWithWakeupAndData(t *testing.T) {
|
|
||||||
tfd, poller := makePoller(t)
|
|
||||||
defer tfd.close()
|
|
||||||
defer poller.close()
|
|
||||||
|
|
||||||
tfd.put(t)
|
|
||||||
err := poller.wake()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("wake failed: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// both data and wakeup
|
|
||||||
ok, err := poller.wait()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("poller failed: %v", err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("expected poller to return true")
|
|
||||||
}
|
|
||||||
|
|
||||||
// data is still in the buffer, wakeup is cleared
|
|
||||||
ok, err = poller.wait()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("poller failed: %v", err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("expected poller to return true")
|
|
||||||
}
|
|
||||||
|
|
||||||
tfd.get(t)
|
|
||||||
// data is gone, only wakeup now
|
|
||||||
err = poller.wake()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("wake failed: %v", err)
|
|
||||||
}
|
|
||||||
ok, err = poller.wait()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("poller failed: %v", err)
|
|
||||||
}
|
|
||||||
if ok {
|
|
||||||
t.Fatalf("expected poller to return false")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPollerConcurrent(t *testing.T) {
|
|
||||||
tfd, poller := makePoller(t)
|
|
||||||
defer tfd.close()
|
|
||||||
defer poller.close()
|
|
||||||
|
|
||||||
oks := make(chan bool)
|
|
||||||
live := make(chan bool)
|
|
||||||
defer close(live)
|
|
||||||
go func() {
|
|
||||||
defer close(oks)
|
|
||||||
for {
|
|
||||||
ok, err := poller.wait()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("poller failed: %v", err)
|
|
||||||
}
|
|
||||||
oks <- ok
|
|
||||||
if !<-live {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Try a write
|
|
||||||
select {
|
|
||||||
case <-time.After(50 * time.Millisecond):
|
|
||||||
case <-oks:
|
|
||||||
t.Fatalf("poller did not wait")
|
|
||||||
}
|
|
||||||
tfd.put(t)
|
|
||||||
if !<-oks {
|
|
||||||
t.Fatalf("expected true")
|
|
||||||
}
|
|
||||||
tfd.get(t)
|
|
||||||
live <- true
|
|
||||||
|
|
||||||
// Try a wakeup
|
|
||||||
select {
|
|
||||||
case <-time.After(50 * time.Millisecond):
|
|
||||||
case <-oks:
|
|
||||||
t.Fatalf("poller did not wait")
|
|
||||||
}
|
|
||||||
err := poller.wake()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("wake failed: %v", err)
|
|
||||||
}
|
|
||||||
if <-oks {
|
|
||||||
t.Fatalf("expected false")
|
|
||||||
}
|
|
||||||
live <- true
|
|
||||||
|
|
||||||
// Try a close
|
|
||||||
select {
|
|
||||||
case <-time.After(50 * time.Millisecond):
|
|
||||||
case <-oks:
|
|
||||||
t.Fatalf("poller did not wait")
|
|
||||||
}
|
|
||||||
tfd.closeWrite(t)
|
|
||||||
if !<-oks {
|
|
||||||
t.Fatalf("expected true")
|
|
||||||
}
|
|
||||||
tfd.get(t)
|
|
||||||
}
|
|
|
@ -1,292 +0,0 @@
|
||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package fsnotify
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"syscall"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestInotifyCloseRightAway(t *testing.T) {
|
|
||||||
w, err := NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create watcher")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close immediately; it won't even reach the first syscall.Read.
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
// Wait for the close to complete.
|
|
||||||
<-time.After(50 * time.Millisecond)
|
|
||||||
isWatcherReallyClosed(t, w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInotifyCloseSlightlyLater(t *testing.T) {
|
|
||||||
w, err := NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create watcher")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until readEvents has reached syscall.Read, and Close.
|
|
||||||
<-time.After(50 * time.Millisecond)
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
// Wait for the close to complete.
|
|
||||||
<-time.After(50 * time.Millisecond)
|
|
||||||
isWatcherReallyClosed(t, w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInotifyCloseSlightlyLaterWithWatch(t *testing.T) {
|
|
||||||
testDir := tempMkdir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
|
|
||||||
w, err := NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create watcher")
|
|
||||||
}
|
|
||||||
w.Add(testDir)
|
|
||||||
|
|
||||||
// Wait until readEvents has reached syscall.Read, and Close.
|
|
||||||
<-time.After(50 * time.Millisecond)
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
// Wait for the close to complete.
|
|
||||||
<-time.After(50 * time.Millisecond)
|
|
||||||
isWatcherReallyClosed(t, w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInotifyCloseAfterRead(t *testing.T) {
|
|
||||||
testDir := tempMkdir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
|
|
||||||
w, err := NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create watcher")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = w.Add(testDir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to add .")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate an event.
|
|
||||||
os.Create(filepath.Join(testDir, "somethingSOMETHINGsomethingSOMETHING"))
|
|
||||||
|
|
||||||
// Wait for readEvents to read the event, then close the watcher.
|
|
||||||
<-time.After(50 * time.Millisecond)
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
// Wait for the close to complete.
|
|
||||||
<-time.After(50 * time.Millisecond)
|
|
||||||
isWatcherReallyClosed(t, w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isWatcherReallyClosed(t *testing.T, w *Watcher) {
|
|
||||||
select {
|
|
||||||
case err, ok := <-w.Errors:
|
|
||||||
if ok {
|
|
||||||
t.Fatalf("w.Errors is not closed; readEvents is still alive after closing (error: %v)", err)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
t.Fatalf("w.Errors would have blocked; readEvents is still alive!")
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case _, ok := <-w.Events:
|
|
||||||
if ok {
|
|
||||||
t.Fatalf("w.Events is not closed; readEvents is still alive after closing")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
t.Fatalf("w.Events would have blocked; readEvents is still alive!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInotifyCloseCreate(t *testing.T) {
|
|
||||||
testDir := tempMkdir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
|
|
||||||
w, err := NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create watcher: %v", err)
|
|
||||||
}
|
|
||||||
defer w.Close()
|
|
||||||
|
|
||||||
err = w.Add(testDir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to add testDir: %v", err)
|
|
||||||
}
|
|
||||||
h, err := os.Create(filepath.Join(testDir, "testfile"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create file in testdir: %v", err)
|
|
||||||
}
|
|
||||||
h.Close()
|
|
||||||
select {
|
|
||||||
case _ = <-w.Events:
|
|
||||||
case err := <-w.Errors:
|
|
||||||
t.Fatalf("Error from watcher: %v", err)
|
|
||||||
case <-time.After(50 * time.Millisecond):
|
|
||||||
t.Fatalf("Took too long to wait for event")
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, we've received one event, so the goroutine is ready.
|
|
||||||
// It's also blocking on syscall.Read.
|
|
||||||
// Now we try to swap the file descriptor under its nose.
|
|
||||||
w.Close()
|
|
||||||
w, err = NewWatcher()
|
|
||||||
defer w.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create second watcher: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
<-time.After(50 * time.Millisecond)
|
|
||||||
err = w.Add(testDir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error adding testDir again: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInotifyStress(t *testing.T) {
|
|
||||||
testDir := tempMkdir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
testFile := filepath.Join(testDir, "testfile")
|
|
||||||
|
|
||||||
w, err := NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create watcher: %v", err)
|
|
||||||
}
|
|
||||||
defer w.Close()
|
|
||||||
|
|
||||||
killchan := make(chan struct{})
|
|
||||||
defer close(killchan)
|
|
||||||
|
|
||||||
err = w.Add(testDir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to add testDir: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
proc, err := os.FindProcess(os.Getpid())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error finding process: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-time.After(5 * time.Millisecond):
|
|
||||||
err := proc.Signal(syscall.SIGUSR1)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Signal failed: %v", err)
|
|
||||||
}
|
|
||||||
case <-killchan:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-time.After(11 * time.Millisecond):
|
|
||||||
err := w.poller.wake()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Wake failed: %v", err)
|
|
||||||
}
|
|
||||||
case <-killchan:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-killchan:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
handle, err := os.Create(testFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Create failed: %v", err)
|
|
||||||
}
|
|
||||||
handle.Close()
|
|
||||||
time.Sleep(time.Millisecond)
|
|
||||||
err = os.Remove(testFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Remove failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
creates := 0
|
|
||||||
removes := 0
|
|
||||||
after := time.After(5 * time.Second)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-after:
|
|
||||||
if creates-removes > 1 || creates-removes < -1 {
|
|
||||||
t.Fatalf("Creates and removes should not be off by more than one: %d creates, %d removes", creates, removes)
|
|
||||||
}
|
|
||||||
if creates < 50 {
|
|
||||||
t.Fatalf("Expected at least 50 creates, got %d", creates)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case err := <-w.Errors:
|
|
||||||
t.Fatalf("Got an error from watcher: %v", err)
|
|
||||||
case evt := <-w.Events:
|
|
||||||
if evt.Name != testFile {
|
|
||||||
t.Fatalf("Got an event for an unknown file: %s", evt.Name)
|
|
||||||
}
|
|
||||||
if evt.Op == Create {
|
|
||||||
creates++
|
|
||||||
}
|
|
||||||
if evt.Op == Remove {
|
|
||||||
removes++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInotifyRemoveTwice(t *testing.T) {
|
|
||||||
testDir := tempMkdir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
testFile := filepath.Join(testDir, "testfile")
|
|
||||||
|
|
||||||
handle, err := os.Create(testFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Create failed: %v", err)
|
|
||||||
}
|
|
||||||
handle.Close()
|
|
||||||
|
|
||||||
w, err := NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create watcher: %v", err)
|
|
||||||
}
|
|
||||||
defer w.Close()
|
|
||||||
|
|
||||||
err = w.Add(testFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to add testFile: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Remove(testFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to remove testFile: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = w.Remove(testFile)
|
|
||||||
if err != syscall.EINVAL {
|
|
||||||
t.Fatalf("Expected EINVAL from Remove, got: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = w.Remove(testFile)
|
|
||||||
if err == syscall.EINVAL {
|
|
||||||
t.Fatalf("Got EINVAL again, watch was not removed")
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,114 +0,0 @@
|
||||||
package tomb_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"gopkg.in/tomb.v1"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNewTomb(t *testing.T) {
|
|
||||||
tb := &tomb.Tomb{}
|
|
||||||
testState(t, tb, false, false, tomb.ErrStillAlive)
|
|
||||||
|
|
||||||
tb.Done()
|
|
||||||
testState(t, tb, true, true, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKill(t *testing.T) {
|
|
||||||
// a nil reason flags the goroutine as dying
|
|
||||||
tb := &tomb.Tomb{}
|
|
||||||
tb.Kill(nil)
|
|
||||||
testState(t, tb, true, false, nil)
|
|
||||||
|
|
||||||
// a non-nil reason now will override Kill
|
|
||||||
err := errors.New("some error")
|
|
||||||
tb.Kill(err)
|
|
||||||
testState(t, tb, true, false, err)
|
|
||||||
|
|
||||||
// another non-nil reason won't replace the first one
|
|
||||||
tb.Kill(errors.New("ignore me"))
|
|
||||||
testState(t, tb, true, false, err)
|
|
||||||
|
|
||||||
tb.Done()
|
|
||||||
testState(t, tb, true, true, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKillf(t *testing.T) {
|
|
||||||
tb := &tomb.Tomb{}
|
|
||||||
|
|
||||||
err := tb.Killf("BO%s", "OM")
|
|
||||||
if s := err.Error(); s != "BOOM" {
|
|
||||||
t.Fatalf(`Killf("BO%s", "OM"): want "BOOM", got %q`, s)
|
|
||||||
}
|
|
||||||
testState(t, tb, true, false, err)
|
|
||||||
|
|
||||||
// another non-nil reason won't replace the first one
|
|
||||||
tb.Killf("ignore me")
|
|
||||||
testState(t, tb, true, false, err)
|
|
||||||
|
|
||||||
tb.Done()
|
|
||||||
testState(t, tb, true, true, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrDying(t *testing.T) {
|
|
||||||
// ErrDying being used properly, after a clean death.
|
|
||||||
tb := &tomb.Tomb{}
|
|
||||||
tb.Kill(nil)
|
|
||||||
tb.Kill(tomb.ErrDying)
|
|
||||||
testState(t, tb, true, false, nil)
|
|
||||||
|
|
||||||
// ErrDying being used properly, after an errorful death.
|
|
||||||
err := errors.New("some error")
|
|
||||||
tb.Kill(err)
|
|
||||||
tb.Kill(tomb.ErrDying)
|
|
||||||
testState(t, tb, true, false, err)
|
|
||||||
|
|
||||||
// ErrDying being used badly, with an alive tomb.
|
|
||||||
tb = &tomb.Tomb{}
|
|
||||||
defer func() {
|
|
||||||
err := recover()
|
|
||||||
if err != "tomb: Kill with ErrDying while still alive" {
|
|
||||||
t.Fatalf("Wrong panic on Kill(ErrDying): %v", err)
|
|
||||||
}
|
|
||||||
testState(t, tb, false, false, tomb.ErrStillAlive)
|
|
||||||
}()
|
|
||||||
tb.Kill(tomb.ErrDying)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testState(t *testing.T, tb *tomb.Tomb, wantDying, wantDead bool, wantErr error) {
|
|
||||||
select {
|
|
||||||
case <-tb.Dying():
|
|
||||||
if !wantDying {
|
|
||||||
t.Error("<-Dying: should block")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if wantDying {
|
|
||||||
t.Error("<-Dying: should not block")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
seemsDead := false
|
|
||||||
select {
|
|
||||||
case <-tb.Dead():
|
|
||||||
if !wantDead {
|
|
||||||
t.Error("<-Dead: should block")
|
|
||||||
}
|
|
||||||
seemsDead = true
|
|
||||||
default:
|
|
||||||
if wantDead {
|
|
||||||
t.Error("<-Dead: should not block")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := tb.Err(); err != wantErr {
|
|
||||||
t.Errorf("Err: want %#v, got %#v", wantErr, err)
|
|
||||||
}
|
|
||||||
if wantDead && seemsDead {
|
|
||||||
waitErr := tb.Wait()
|
|
||||||
switch {
|
|
||||||
case waitErr == tomb.ErrStillAlive:
|
|
||||||
t.Errorf("Wait should not return ErrStillAlive")
|
|
||||||
case !reflect.DeepEqual(waitErr, wantErr):
|
|
||||||
t.Errorf("Wait: want %#v, got %#v", wantErr, waitErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,8 +13,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"./watch"
|
|
||||||
"github.com/hpcloud/tail/ratelimiter"
|
"github.com/hpcloud/tail/ratelimiter"
|
||||||
|
"github.com/hpcloud/tail/watch"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
0
Godeps/_workspace/src/gopkg.in/tomb.v1/LICENSE → vendor/gopkg.in/tomb.v1/LICENSE
generated
vendored
0
Godeps/_workspace/src/gopkg.in/tomb.v1/LICENSE → vendor/gopkg.in/tomb.v1/LICENSE
generated
vendored
0
Godeps/_workspace/src/gopkg.in/tomb.v1/README.md → vendor/gopkg.in/tomb.v1/README.md
generated
vendored
0
Godeps/_workspace/src/gopkg.in/tomb.v1/README.md → vendor/gopkg.in/tomb.v1/README.md
generated
vendored
Loading…
Reference in New Issue