OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / fsnotify / fsnotify / inotify_test.go
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // +build linux
6
7 package fsnotify
8
9 import (
10         "fmt"
11         "os"
12         "path/filepath"
13         "strings"
14         "testing"
15         "time"
16 )
17
18 func TestInotifyCloseRightAway(t *testing.T) {
19         w, err := NewWatcher()
20         if err != nil {
21                 t.Fatalf("Failed to create watcher")
22         }
23
24         // Close immediately; it won't even reach the first unix.Read.
25         w.Close()
26
27         // Wait for the close to complete.
28         <-time.After(50 * time.Millisecond)
29         isWatcherReallyClosed(t, w)
30 }
31
32 func TestInotifyCloseSlightlyLater(t *testing.T) {
33         w, err := NewWatcher()
34         if err != nil {
35                 t.Fatalf("Failed to create watcher")
36         }
37
38         // Wait until readEvents has reached unix.Read, and Close.
39         <-time.After(50 * time.Millisecond)
40         w.Close()
41
42         // Wait for the close to complete.
43         <-time.After(50 * time.Millisecond)
44         isWatcherReallyClosed(t, w)
45 }
46
47 func TestInotifyCloseSlightlyLaterWithWatch(t *testing.T) {
48         testDir := tempMkdir(t)
49         defer os.RemoveAll(testDir)
50
51         w, err := NewWatcher()
52         if err != nil {
53                 t.Fatalf("Failed to create watcher")
54         }
55         w.Add(testDir)
56
57         // Wait until readEvents has reached unix.Read, and Close.
58         <-time.After(50 * time.Millisecond)
59         w.Close()
60
61         // Wait for the close to complete.
62         <-time.After(50 * time.Millisecond)
63         isWatcherReallyClosed(t, w)
64 }
65
66 func TestInotifyCloseAfterRead(t *testing.T) {
67         testDir := tempMkdir(t)
68         defer os.RemoveAll(testDir)
69
70         w, err := NewWatcher()
71         if err != nil {
72                 t.Fatalf("Failed to create watcher")
73         }
74
75         err = w.Add(testDir)
76         if err != nil {
77                 t.Fatalf("Failed to add .")
78         }
79
80         // Generate an event.
81         os.Create(filepath.Join(testDir, "somethingSOMETHINGsomethingSOMETHING"))
82
83         // Wait for readEvents to read the event, then close the watcher.
84         <-time.After(50 * time.Millisecond)
85         w.Close()
86
87         // Wait for the close to complete.
88         <-time.After(50 * time.Millisecond)
89         isWatcherReallyClosed(t, w)
90 }
91
92 func isWatcherReallyClosed(t *testing.T, w *Watcher) {
93         select {
94         case err, ok := <-w.Errors:
95                 if ok {
96                         t.Fatalf("w.Errors is not closed; readEvents is still alive after closing (error: %v)", err)
97                 }
98         default:
99                 t.Fatalf("w.Errors would have blocked; readEvents is still alive!")
100         }
101
102         select {
103         case _, ok := <-w.Events:
104                 if ok {
105                         t.Fatalf("w.Events is not closed; readEvents is still alive after closing")
106                 }
107         default:
108                 t.Fatalf("w.Events would have blocked; readEvents is still alive!")
109         }
110 }
111
112 func TestInotifyCloseCreate(t *testing.T) {
113         testDir := tempMkdir(t)
114         defer os.RemoveAll(testDir)
115
116         w, err := NewWatcher()
117         if err != nil {
118                 t.Fatalf("Failed to create watcher: %v", err)
119         }
120         defer w.Close()
121
122         err = w.Add(testDir)
123         if err != nil {
124                 t.Fatalf("Failed to add testDir: %v", err)
125         }
126         h, err := os.Create(filepath.Join(testDir, "testfile"))
127         if err != nil {
128                 t.Fatalf("Failed to create file in testdir: %v", err)
129         }
130         h.Close()
131         select {
132         case _ = <-w.Events:
133         case err := <-w.Errors:
134                 t.Fatalf("Error from watcher: %v", err)
135         case <-time.After(50 * time.Millisecond):
136                 t.Fatalf("Took too long to wait for event")
137         }
138
139         // At this point, we've received one event, so the goroutine is ready.
140         // It's also blocking on unix.Read.
141         // Now we try to swap the file descriptor under its nose.
142         w.Close()
143         w, err = NewWatcher()
144         defer w.Close()
145         if err != nil {
146                 t.Fatalf("Failed to create second watcher: %v", err)
147         }
148
149         <-time.After(50 * time.Millisecond)
150         err = w.Add(testDir)
151         if err != nil {
152                 t.Fatalf("Error adding testDir again: %v", err)
153         }
154 }
155
156 // This test verifies the watcher can keep up with file creations/deletions
157 // when under load.
158 func TestInotifyStress(t *testing.T) {
159         maxNumToCreate := 1000
160
161         testDir := tempMkdir(t)
162         defer os.RemoveAll(testDir)
163         testFilePrefix := filepath.Join(testDir, "testfile")
164
165         w, err := NewWatcher()
166         if err != nil {
167                 t.Fatalf("Failed to create watcher: %v", err)
168         }
169         defer w.Close()
170
171         err = w.Add(testDir)
172         if err != nil {
173                 t.Fatalf("Failed to add testDir: %v", err)
174         }
175
176         doneChan := make(chan struct{})
177         // The buffer ensures that the file generation goroutine is never blocked.
178         errChan := make(chan error, 2*maxNumToCreate)
179
180         go func() {
181                 for i := 0; i < maxNumToCreate; i++ {
182                         testFile := fmt.Sprintf("%s%d", testFilePrefix, i)
183
184                         handle, err := os.Create(testFile)
185                         if err != nil {
186                                 errChan <- fmt.Errorf("Create failed: %v", err)
187                                 continue
188                         }
189
190                         err = handle.Close()
191                         if err != nil {
192                                 errChan <- fmt.Errorf("Close failed: %v", err)
193                                 continue
194                         }
195                 }
196
197                 // If we delete a newly created file too quickly, inotify will skip the
198                 // create event and only send the delete event.
199                 time.Sleep(100 * time.Millisecond)
200
201                 for i := 0; i < maxNumToCreate; i++ {
202                         testFile := fmt.Sprintf("%s%d", testFilePrefix, i)
203                         err = os.Remove(testFile)
204                         if err != nil {
205                                 errChan <- fmt.Errorf("Remove failed: %v", err)
206                         }
207                 }
208
209                 close(doneChan)
210         }()
211
212         creates := 0
213         removes := 0
214
215         finished := false
216         after := time.After(10 * time.Second)
217         for !finished {
218                 select {
219                 case <-after:
220                         t.Fatalf("Not done")
221                 case <-doneChan:
222                         finished = true
223                 case err := <-errChan:
224                         t.Fatalf("Got an error from file creator goroutine: %v", err)
225                 case err := <-w.Errors:
226                         t.Fatalf("Got an error from watcher: %v", err)
227                 case evt := <-w.Events:
228                         if !strings.HasPrefix(evt.Name, testFilePrefix) {
229                                 t.Fatalf("Got an event for an unknown file: %s", evt.Name)
230                         }
231                         if evt.Op == Create {
232                                 creates++
233                         }
234                         if evt.Op == Remove {
235                                 removes++
236                         }
237                 }
238         }
239
240         // Drain remaining events from channels
241         count := 0
242         for count < 10 {
243                 select {
244                 case err := <-errChan:
245                         t.Fatalf("Got an error from file creator goroutine: %v", err)
246                 case err := <-w.Errors:
247                         t.Fatalf("Got an error from watcher: %v", err)
248                 case evt := <-w.Events:
249                         if !strings.HasPrefix(evt.Name, testFilePrefix) {
250                                 t.Fatalf("Got an event for an unknown file: %s", evt.Name)
251                         }
252                         if evt.Op == Create {
253                                 creates++
254                         }
255                         if evt.Op == Remove {
256                                 removes++
257                         }
258                         count = 0
259                 default:
260                         count++
261                         // Give the watcher chances to fill the channels.
262                         time.Sleep(time.Millisecond)
263                 }
264         }
265
266         if creates-removes > 1 || creates-removes < -1 {
267                 t.Fatalf("Creates and removes should not be off by more than one: %d creates, %d removes", creates, removes)
268         }
269         if creates < 50 {
270                 t.Fatalf("Expected at least 50 creates, got %d", creates)
271         }
272 }
273
274 func TestInotifyRemoveTwice(t *testing.T) {
275         testDir := tempMkdir(t)
276         defer os.RemoveAll(testDir)
277         testFile := filepath.Join(testDir, "testfile")
278
279         handle, err := os.Create(testFile)
280         if err != nil {
281                 t.Fatalf("Create failed: %v", err)
282         }
283         handle.Close()
284
285         w, err := NewWatcher()
286         if err != nil {
287                 t.Fatalf("Failed to create watcher: %v", err)
288         }
289         defer w.Close()
290
291         err = w.Add(testFile)
292         if err != nil {
293                 t.Fatalf("Failed to add testFile: %v", err)
294         }
295
296         err = w.Remove(testFile)
297         if err != nil {
298                 t.Fatalf("wanted successful remove but got:", err)
299         }
300
301         err = w.Remove(testFile)
302         if err == nil {
303                 t.Fatalf("no error on removing invalid file")
304         }
305
306         w.mu.Lock()
307         defer w.mu.Unlock()
308         if len(w.watches) != 0 {
309                 t.Fatalf("Expected watches len is 0, but got: %d, %v", len(w.watches), w.watches)
310         }
311         if len(w.paths) != 0 {
312                 t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths)
313         }
314 }
315
316 func TestInotifyInnerMapLength(t *testing.T) {
317         testDir := tempMkdir(t)
318         defer os.RemoveAll(testDir)
319         testFile := filepath.Join(testDir, "testfile")
320
321         handle, err := os.Create(testFile)
322         if err != nil {
323                 t.Fatalf("Create failed: %v", err)
324         }
325         handle.Close()
326
327         w, err := NewWatcher()
328         if err != nil {
329                 t.Fatalf("Failed to create watcher: %v", err)
330         }
331         defer w.Close()
332
333         err = w.Add(testFile)
334         if err != nil {
335                 t.Fatalf("Failed to add testFile: %v", err)
336         }
337         go func() {
338                 for err := range w.Errors {
339                         t.Fatalf("error received: %s", err)
340                 }
341         }()
342
343         err = os.Remove(testFile)
344         if err != nil {
345                 t.Fatalf("Failed to remove testFile: %v", err)
346         }
347         _ = <-w.Events                      // consume Remove event
348         <-time.After(50 * time.Millisecond) // wait IN_IGNORE propagated
349
350         w.mu.Lock()
351         defer w.mu.Unlock()
352         if len(w.watches) != 0 {
353                 t.Fatalf("Expected watches len is 0, but got: %d, %v", len(w.watches), w.watches)
354         }
355         if len(w.paths) != 0 {
356                 t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths)
357         }
358 }
359
360 func TestInotifyOverflow(t *testing.T) {
361         // We need to generate many more events than the
362         // fs.inotify.max_queued_events sysctl setting.
363         // We use multiple goroutines (one per directory)
364         // to speed up file creation.
365         numDirs := 128
366         numFiles := 1024
367
368         testDir := tempMkdir(t)
369         defer os.RemoveAll(testDir)
370
371         w, err := NewWatcher()
372         if err != nil {
373                 t.Fatalf("Failed to create watcher: %v", err)
374         }
375         defer w.Close()
376
377         for dn := 0; dn < numDirs; dn++ {
378                 testSubdir := fmt.Sprintf("%s/%d", testDir, dn)
379
380                 err := os.Mkdir(testSubdir, 0777)
381                 if err != nil {
382                         t.Fatalf("Cannot create subdir: %v", err)
383                 }
384
385                 err = w.Add(testSubdir)
386                 if err != nil {
387                         t.Fatalf("Failed to add subdir: %v", err)
388                 }
389         }
390
391         errChan := make(chan error, numDirs*numFiles)
392
393         for dn := 0; dn < numDirs; dn++ {
394                 testSubdir := fmt.Sprintf("%s/%d", testDir, dn)
395
396                 go func() {
397                         for fn := 0; fn < numFiles; fn++ {
398                                 testFile := fmt.Sprintf("%s/%d", testSubdir, fn)
399
400                                 handle, err := os.Create(testFile)
401                                 if err != nil {
402                                         errChan <- fmt.Errorf("Create failed: %v", err)
403                                         continue
404                                 }
405
406                                 err = handle.Close()
407                                 if err != nil {
408                                         errChan <- fmt.Errorf("Close failed: %v", err)
409                                         continue
410                                 }
411                         }
412                 }()
413         }
414
415         creates := 0
416         overflows := 0
417
418         after := time.After(10 * time.Second)
419         for overflows == 0 && creates < numDirs*numFiles {
420                 select {
421                 case <-after:
422                         t.Fatalf("Not done")
423                 case err := <-errChan:
424                         t.Fatalf("Got an error from file creator goroutine: %v", err)
425                 case err := <-w.Errors:
426                         if err == ErrEventOverflow {
427                                 overflows++
428                         } else {
429                                 t.Fatalf("Got an error from watcher: %v", err)
430                         }
431                 case evt := <-w.Events:
432                         if !strings.HasPrefix(evt.Name, testDir) {
433                                 t.Fatalf("Got an event for an unknown file: %s", evt.Name)
434                         }
435                         if evt.Op == Create {
436                                 creates++
437                         }
438                 }
439         }
440
441         if creates == numDirs*numFiles {
442                 t.Fatalf("Could not trigger overflow")
443         }
444
445         if overflows == 0 {
446                 t.Fatalf("No overflow and not enough creates (expected %d, got %d)",
447                         numDirs*numFiles, creates)
448         }
449 }