]> go.fuhry.dev Git - fsnotify.git/commitdiff
Add some unit tests for inotify_poller
authorPieter Droogendijk <pieter@binky.org.uk>
Sat, 7 Feb 2015 23:05:53 +0000 (00:05 +0100)
committerNathan Youngman <git@nathany.com>
Sun, 8 Feb 2015 20:22:31 +0000 (13:22 -0700)
inotify_poller.go
inotify_poller_test.go [new file with mode: 0644]

index 2f9cb23234c35656b2b38aa67367243b5d0aabed..910ba4ae87ddacc3c895865d236aa8f47a71fd77 100644 (file)
@@ -95,8 +95,6 @@ func (poller *fdPoller) wait() (bool, error) {
                epollhup := false
                epollerr := false
                epollin := false
-               epollpipehup := false
-               epollpipein := false
                for _, event := range ready {
                        if event.Fd == int32(poller.fd) {
                                if event.Events&syscall.EPOLLHUP != 0 {
@@ -117,7 +115,6 @@ func (poller *fdPoller) wait() (bool, error) {
                                if event.Events&syscall.EPOLLHUP != 0 {
                                        // Write pipe descriptor was closed, by us. This means we're closing down the
                                        // watcher, and we should wake up.
-                                       epollpipehup = true
                                }
                                if event.Events&syscall.EPOLLERR != 0 {
                                        // If an error is waiting on the pipe file descriptor.
@@ -125,9 +122,7 @@ func (poller *fdPoller) wait() (bool, error) {
                                        return false, errors.New("Error on the pipe descriptor.")
                                }
                                if event.Events&syscall.EPOLLIN != 0 {
-                                       // This is a regular wakeup.
-                                       epollpipein = true
-                                       // Clear the buffer.
+                                       // This is a regular wakeup, so we have to clear the buffer.
                                        err := poller.clearWake()
                                        if err != nil {
                                                return false, err
@@ -136,16 +131,10 @@ func (poller *fdPoller) wait() (bool, error) {
                        }
                }
 
-               if epollerr {
+               if epollhup || epollerr || epollin {
                        return true, nil
                }
-               if epollhup || epollpipehup || epollpipein {
-                       return false, nil
-               }
-               if epollin {
-                       return true, nil
-               }
-               return false, errors.New("Epoll failed to generate any of the only six possibilities.")
+               return false, nil
        }
 }
 
diff --git a/inotify_poller_test.go b/inotify_poller_test.go
new file mode 100644 (file)
index 0000000..3625eab
--- /dev/null
@@ -0,0 +1,221 @@
+// 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 write 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 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)
+       kill := make(chan bool)
+       defer close(kill)
+       go func() {
+               defer close(oks)
+               for {
+                       ok, err := poller.wait()
+                       if err != nil {
+                               t.Fatalf("poller failed: %v", err)
+                       }
+                       oks <- ok
+                       if !<-kill {
+                               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)
+       kill <- 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")
+       }
+       kill <- 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)
+}