1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
//go:build linux
package fsnotify
import (
"errors"
"os"
"strconv"
"strings"
"sync"
"testing"
"time"
)
func TestRemoveState(t *testing.T) {
var (
tmp = t.TempDir()
dir = join(tmp, "dir")
file = join(dir, "file")
)
mkdir(t, dir)
touch(t, file)
w := newWatcher(t, tmp)
addWatch(t, w, tmp)
addWatch(t, w, file)
check := func(want int) {
t.Helper()
if w.b.(*inotify).watches.len() != want {
t.Error(w.b.(*inotify).watches)
}
}
check(2)
// Shouldn't change internal state.
if err := w.Add("/path-doesnt-exist"); err == nil {
t.Fatal(err)
}
check(2)
if err := w.Remove(file); err != nil {
t.Fatal(err)
}
check(1)
if err := w.Remove(tmp); err != nil {
t.Fatal(err)
}
check(0)
}
// Ensure that the correct error is returned on overflows.
func TestInotifyOverflow(t *testing.T) {
t.Parallel()
tmp := t.TempDir()
w := newWatcher(t)
defer w.Close()
// We need to generate many more events than the
// fs.inotify.max_queued_events sysctl setting.
numDirs, numFiles := 128, 1024
// All events need to be in the inotify queue before pulling events off it
// to trigger this error.
var wg sync.WaitGroup
for i := 0; i < numDirs; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
dir := join(tmp, strconv.Itoa(i))
mkdir(t, dir, noWait)
addWatch(t, w, dir)
createFiles(t, dir, "", numFiles, 10*time.Second)
}(i)
}
wg.Wait()
var (
creates = 0
overflows = 0
)
for overflows == 0 && creates < numDirs*numFiles {
select {
case <-time.After(10 * time.Second):
t.Fatalf("Not done")
case err := <-w.Errors:
if !errors.Is(err, ErrEventOverflow) {
t.Fatalf("unexpected error from watcher: %v", err)
}
overflows++
case e := <-w.Events:
if !strings.HasPrefix(e.Name, tmp) {
t.Fatalf("Event for unknown file: %s", e.Name)
}
if e.Op == Create {
creates++
}
}
}
if creates == numDirs*numFiles {
t.Fatalf("could not trigger overflow")
}
if overflows == 0 {
t.Fatalf("no overflow and not enough CREATE events (expected %d, got %d)",
numDirs*numFiles, creates)
}
}
// Test inotify's "we don't send REMOVE until all file descriptors are removed"
// behaviour.
func TestInotifyDeleteOpenFile(t *testing.T) {
t.Parallel()
tmp := t.TempDir()
file := join(tmp, "file")
touch(t, file)
fp, err := os.Open(file)
if err != nil {
t.Fatalf("Create failed: %v", err)
}
defer fp.Close()
w := newCollector(t, file)
w.collect(t)
rm(t, file)
waitForEvents()
e := w.events(t)
cmpEvents(t, tmp, e, newEvents(t, `chmod /file`))
fp.Close()
e = w.stop(t)
cmpEvents(t, tmp, e, newEvents(t, `remove /file`))
}
|