OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / fsnotify / fsnotify / inotify_test.go
diff --git a/vendor/github.com/fsnotify/fsnotify/inotify_test.go b/vendor/github.com/fsnotify/fsnotify/inotify_test.go
new file mode 100644 (file)
index 0000000..2cc6d93
--- /dev/null
@@ -0,0 +1,449 @@
+// 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 (
+       "fmt"
+       "os"
+       "path/filepath"
+       "strings"
+       "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 unix.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 unix.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 unix.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 unix.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)
+       }
+}
+
+// This test verifies the watcher can keep up with file creations/deletions
+// when under load.
+func TestInotifyStress(t *testing.T) {
+       maxNumToCreate := 1000
+
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+       testFilePrefix := filepath.Join(testDir, "testfile")
+
+       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)
+       }
+
+       doneChan := make(chan struct{})
+       // The buffer ensures that the file generation goroutine is never blocked.
+       errChan := make(chan error, 2*maxNumToCreate)
+
+       go func() {
+               for i := 0; i < maxNumToCreate; i++ {
+                       testFile := fmt.Sprintf("%s%d", testFilePrefix, i)
+
+                       handle, err := os.Create(testFile)
+                       if err != nil {
+                               errChan <- fmt.Errorf("Create failed: %v", err)
+                               continue
+                       }
+
+                       err = handle.Close()
+                       if err != nil {
+                               errChan <- fmt.Errorf("Close failed: %v", err)
+                               continue
+                       }
+               }
+
+               // If we delete a newly created file too quickly, inotify will skip the
+               // create event and only send the delete event.
+               time.Sleep(100 * time.Millisecond)
+
+               for i := 0; i < maxNumToCreate; i++ {
+                       testFile := fmt.Sprintf("%s%d", testFilePrefix, i)
+                       err = os.Remove(testFile)
+                       if err != nil {
+                               errChan <- fmt.Errorf("Remove failed: %v", err)
+                       }
+               }
+
+               close(doneChan)
+       }()
+
+       creates := 0
+       removes := 0
+
+       finished := false
+       after := time.After(10 * time.Second)
+       for !finished {
+               select {
+               case <-after:
+                       t.Fatalf("Not done")
+               case <-doneChan:
+                       finished = true
+               case err := <-errChan:
+                       t.Fatalf("Got an error from file creator goroutine: %v", err)
+               case err := <-w.Errors:
+                       t.Fatalf("Got an error from watcher: %v", err)
+               case evt := <-w.Events:
+                       if !strings.HasPrefix(evt.Name, testFilePrefix) {
+                               t.Fatalf("Got an event for an unknown file: %s", evt.Name)
+                       }
+                       if evt.Op == Create {
+                               creates++
+                       }
+                       if evt.Op == Remove {
+                               removes++
+                       }
+               }
+       }
+
+       // Drain remaining events from channels
+       count := 0
+       for count < 10 {
+               select {
+               case err := <-errChan:
+                       t.Fatalf("Got an error from file creator goroutine: %v", err)
+               case err := <-w.Errors:
+                       t.Fatalf("Got an error from watcher: %v", err)
+               case evt := <-w.Events:
+                       if !strings.HasPrefix(evt.Name, testFilePrefix) {
+                               t.Fatalf("Got an event for an unknown file: %s", evt.Name)
+                       }
+                       if evt.Op == Create {
+                               creates++
+                       }
+                       if evt.Op == Remove {
+                               removes++
+                       }
+                       count = 0
+               default:
+                       count++
+                       // Give the watcher chances to fill the channels.
+                       time.Sleep(time.Millisecond)
+               }
+       }
+
+       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)
+       }
+}
+
+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 = w.Remove(testFile)
+       if err != nil {
+               t.Fatalf("wanted successful remove but got:", err)
+       }
+
+       err = w.Remove(testFile)
+       if err == nil {
+               t.Fatalf("no error on removing invalid file")
+       }
+
+       w.mu.Lock()
+       defer w.mu.Unlock()
+       if len(w.watches) != 0 {
+               t.Fatalf("Expected watches len is 0, but got: %d, %v", len(w.watches), w.watches)
+       }
+       if len(w.paths) != 0 {
+               t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths)
+       }
+}
+
+func TestInotifyInnerMapLength(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)
+       }
+       go func() {
+               for err := range w.Errors {
+                       t.Fatalf("error received: %s", err)
+               }
+       }()
+
+       err = os.Remove(testFile)
+       if err != nil {
+               t.Fatalf("Failed to remove testFile: %v", err)
+       }
+       _ = <-w.Events                      // consume Remove event
+       <-time.After(50 * time.Millisecond) // wait IN_IGNORE propagated
+
+       w.mu.Lock()
+       defer w.mu.Unlock()
+       if len(w.watches) != 0 {
+               t.Fatalf("Expected watches len is 0, but got: %d, %v", len(w.watches), w.watches)
+       }
+       if len(w.paths) != 0 {
+               t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths)
+       }
+}
+
+func TestInotifyOverflow(t *testing.T) {
+       // We need to generate many more events than the
+       // fs.inotify.max_queued_events sysctl setting.
+       // We use multiple goroutines (one per directory)
+       // to speed up file creation.
+       numDirs := 128
+       numFiles := 1024
+
+       testDir := tempMkdir(t)
+       defer os.RemoveAll(testDir)
+
+       w, err := NewWatcher()
+       if err != nil {
+               t.Fatalf("Failed to create watcher: %v", err)
+       }
+       defer w.Close()
+
+       for dn := 0; dn < numDirs; dn++ {
+               testSubdir := fmt.Sprintf("%s/%d", testDir, dn)
+
+               err := os.Mkdir(testSubdir, 0777)
+               if err != nil {
+                       t.Fatalf("Cannot create subdir: %v", err)
+               }
+
+               err = w.Add(testSubdir)
+               if err != nil {
+                       t.Fatalf("Failed to add subdir: %v", err)
+               }
+       }
+
+       errChan := make(chan error, numDirs*numFiles)
+
+       for dn := 0; dn < numDirs; dn++ {
+               testSubdir := fmt.Sprintf("%s/%d", testDir, dn)
+
+               go func() {
+                       for fn := 0; fn < numFiles; fn++ {
+                               testFile := fmt.Sprintf("%s/%d", testSubdir, fn)
+
+                               handle, err := os.Create(testFile)
+                               if err != nil {
+                                       errChan <- fmt.Errorf("Create failed: %v", err)
+                                       continue
+                               }
+
+                               err = handle.Close()
+                               if err != nil {
+                                       errChan <- fmt.Errorf("Close failed: %v", err)
+                                       continue
+                               }
+                       }
+               }()
+       }
+
+       creates := 0
+       overflows := 0
+
+       after := time.After(10 * time.Second)
+       for overflows == 0 && creates < numDirs*numFiles {
+               select {
+               case <-after:
+                       t.Fatalf("Not done")
+               case err := <-errChan:
+                       t.Fatalf("Got an error from file creator goroutine: %v", err)
+               case err := <-w.Errors:
+                       if err == ErrEventOverflow {
+                               overflows++
+                       } else {
+                               t.Fatalf("Got an error from watcher: %v", err)
+                       }
+               case evt := <-w.Events:
+                       if !strings.HasPrefix(evt.Name, testDir) {
+                               t.Fatalf("Got an event for an unknown file: %s", evt.Name)
+                       }
+                       if evt.Op == Create {
+                               creates++
+                       }
+               }
+       }
+
+       if creates == numDirs*numFiles {
+               t.Fatalf("Could not trigger overflow")
+       }
+
+       if overflows == 0 {
+               t.Fatalf("No overflow and not enough creates (expected %d, got %d)",
+                       numDirs*numFiles, creates)
+       }
+}