From: Pieter Droogendijk Date: Sat, 7 Feb 2015 23:05:53 +0000 (+0100) Subject: Add some unit tests for inotify_poller X-Git-Tag: v1.7.2~231 X-Git-Url: https://go.fuhry.dev/?a=commitdiff_plain;h=81658371c02a81cff0a702a56f155fbf05f343ce;p=fsnotify.git Add some unit tests for inotify_poller --- diff --git a/inotify_poller.go b/inotify_poller.go index 2f9cb23..910ba4a 100644 --- a/inotify_poller.go +++ b/inotify_poller.go @@ -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 index 0000000..3625eab --- /dev/null +++ b/inotify_poller_test.go @@ -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) +}