| // 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 ( |
| "testing" |
| "time" |
| |
| "golang.org/x/sys/unix" |
| ) |
| |
| type testFd [2]int |
| |
| func makeTestFd(t *testing.T) testFd { |
| var tfd testFd |
| errno := unix.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 := unix.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 := unix.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 := unix.Read(tfd[0], buf) |
| if errno != nil { |
| t.Fatalf("Failed to read from pipe: %v", errno) |
| } |
| } |
| |
| func (tfd testFd) close() { |
| unix.Close(tfd[1]) |
| unix.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 != unix.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) |
| } |