OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / fsnotify / fsnotify / integration_test.go
1 // Copyright 2010 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 !plan9,!solaris
6
7 package fsnotify
8
9 import (
10         "io/ioutil"
11         "os"
12         "os/exec"
13         "path"
14         "path/filepath"
15         "runtime"
16         "sync/atomic"
17         "testing"
18         "time"
19 )
20
21 // An atomic counter
22 type counter struct {
23         val int32
24 }
25
26 func (c *counter) increment() {
27         atomic.AddInt32(&c.val, 1)
28 }
29
30 func (c *counter) value() int32 {
31         return atomic.LoadInt32(&c.val)
32 }
33
34 func (c *counter) reset() {
35         atomic.StoreInt32(&c.val, 0)
36 }
37
38 // tempMkdir makes a temporary directory
39 func tempMkdir(t *testing.T) string {
40         dir, err := ioutil.TempDir("", "fsnotify")
41         if err != nil {
42                 t.Fatalf("failed to create test directory: %s", err)
43         }
44         return dir
45 }
46
47 // tempMkFile makes a temporary file.
48 func tempMkFile(t *testing.T, dir string) string {
49         f, err := ioutil.TempFile(dir, "fsnotify")
50         if err != nil {
51                 t.Fatalf("failed to create test file: %v", err)
52         }
53         defer f.Close()
54         return f.Name()
55 }
56
57 // newWatcher initializes an fsnotify Watcher instance.
58 func newWatcher(t *testing.T) *Watcher {
59         watcher, err := NewWatcher()
60         if err != nil {
61                 t.Fatalf("NewWatcher() failed: %s", err)
62         }
63         return watcher
64 }
65
66 // addWatch adds a watch for a directory
67 func addWatch(t *testing.T, watcher *Watcher, dir string) {
68         if err := watcher.Add(dir); err != nil {
69                 t.Fatalf("watcher.Add(%q) failed: %s", dir, err)
70         }
71 }
72
73 func TestFsnotifyMultipleOperations(t *testing.T) {
74         watcher := newWatcher(t)
75
76         // Receive errors on the error channel on a separate goroutine
77         go func() {
78                 for err := range watcher.Errors {
79                         t.Fatalf("error received: %s", err)
80                 }
81         }()
82
83         // Create directory to watch
84         testDir := tempMkdir(t)
85         defer os.RemoveAll(testDir)
86
87         // Create directory that's not watched
88         testDirToMoveFiles := tempMkdir(t)
89         defer os.RemoveAll(testDirToMoveFiles)
90
91         testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
92         testFileRenamed := filepath.Join(testDirToMoveFiles, "TestFsnotifySeqRename.testfile")
93
94         addWatch(t, watcher, testDir)
95
96         // Receive events on the event channel on a separate goroutine
97         eventstream := watcher.Events
98         var createReceived, modifyReceived, deleteReceived, renameReceived counter
99         done := make(chan bool)
100         go func() {
101                 for event := range eventstream {
102                         // Only count relevant events
103                         if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
104                                 t.Logf("event received: %s", event)
105                                 if event.Op&Remove == Remove {
106                                         deleteReceived.increment()
107                                 }
108                                 if event.Op&Write == Write {
109                                         modifyReceived.increment()
110                                 }
111                                 if event.Op&Create == Create {
112                                         createReceived.increment()
113                                 }
114                                 if event.Op&Rename == Rename {
115                                         renameReceived.increment()
116                                 }
117                         } else {
118                                 t.Logf("unexpected event received: %s", event)
119                         }
120                 }
121                 done <- true
122         }()
123
124         // Create a file
125         // This should add at least one event to the fsnotify event queue
126         var f *os.File
127         f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
128         if err != nil {
129                 t.Fatalf("creating test file failed: %s", err)
130         }
131         f.Sync()
132
133         time.Sleep(time.Millisecond)
134         f.WriteString("data")
135         f.Sync()
136         f.Close()
137
138         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
139
140         if err := testRename(testFile, testFileRenamed); err != nil {
141                 t.Fatalf("rename failed: %s", err)
142         }
143
144         // Modify the file outside of the watched dir
145         f, err = os.Open(testFileRenamed)
146         if err != nil {
147                 t.Fatalf("open test renamed file failed: %s", err)
148         }
149         f.WriteString("data")
150         f.Sync()
151         f.Close()
152
153         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
154
155         // Recreate the file that was moved
156         f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
157         if err != nil {
158                 t.Fatalf("creating test file failed: %s", err)
159         }
160         f.Close()
161         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
162
163         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
164         time.Sleep(500 * time.Millisecond)
165         cReceived := createReceived.value()
166         if cReceived != 2 {
167                 t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
168         }
169         mReceived := modifyReceived.value()
170         if mReceived != 1 {
171                 t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
172         }
173         dReceived := deleteReceived.value()
174         rReceived := renameReceived.value()
175         if dReceived+rReceived != 1 {
176                 t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", rReceived+dReceived, 1)
177         }
178
179         // Try closing the fsnotify instance
180         t.Log("calling Close()")
181         watcher.Close()
182         t.Log("waiting for the event channel to become closed...")
183         select {
184         case <-done:
185                 t.Log("event channel closed")
186         case <-time.After(2 * time.Second):
187                 t.Fatal("event stream was not closed after 2 seconds")
188         }
189 }
190
191 func TestFsnotifyMultipleCreates(t *testing.T) {
192         watcher := newWatcher(t)
193
194         // Receive errors on the error channel on a separate goroutine
195         go func() {
196                 for err := range watcher.Errors {
197                         t.Fatalf("error received: %s", err)
198                 }
199         }()
200
201         // Create directory to watch
202         testDir := tempMkdir(t)
203         defer os.RemoveAll(testDir)
204
205         testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
206
207         addWatch(t, watcher, testDir)
208
209         // Receive events on the event channel on a separate goroutine
210         eventstream := watcher.Events
211         var createReceived, modifyReceived, deleteReceived counter
212         done := make(chan bool)
213         go func() {
214                 for event := range eventstream {
215                         // Only count relevant events
216                         if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
217                                 t.Logf("event received: %s", event)
218                                 if event.Op&Remove == Remove {
219                                         deleteReceived.increment()
220                                 }
221                                 if event.Op&Create == Create {
222                                         createReceived.increment()
223                                 }
224                                 if event.Op&Write == Write {
225                                         modifyReceived.increment()
226                                 }
227                         } else {
228                                 t.Logf("unexpected event received: %s", event)
229                         }
230                 }
231                 done <- true
232         }()
233
234         // Create a file
235         // This should add at least one event to the fsnotify event queue
236         var f *os.File
237         f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
238         if err != nil {
239                 t.Fatalf("creating test file failed: %s", err)
240         }
241         f.Sync()
242
243         time.Sleep(time.Millisecond)
244         f.WriteString("data")
245         f.Sync()
246         f.Close()
247
248         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
249
250         os.Remove(testFile)
251
252         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
253
254         // Recreate the file
255         f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
256         if err != nil {
257                 t.Fatalf("creating test file failed: %s", err)
258         }
259         f.Close()
260         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
261
262         // Modify
263         f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
264         if err != nil {
265                 t.Fatalf("creating test file failed: %s", err)
266         }
267         f.Sync()
268
269         time.Sleep(time.Millisecond)
270         f.WriteString("data")
271         f.Sync()
272         f.Close()
273
274         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
275
276         // Modify
277         f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
278         if err != nil {
279                 t.Fatalf("creating test file failed: %s", err)
280         }
281         f.Sync()
282
283         time.Sleep(time.Millisecond)
284         f.WriteString("data")
285         f.Sync()
286         f.Close()
287
288         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
289
290         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
291         time.Sleep(500 * time.Millisecond)
292         cReceived := createReceived.value()
293         if cReceived != 2 {
294                 t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
295         }
296         mReceived := modifyReceived.value()
297         if mReceived < 3 {
298                 t.Fatalf("incorrect number of modify events received after 500 ms (%d vs atleast %d)", mReceived, 3)
299         }
300         dReceived := deleteReceived.value()
301         if dReceived != 1 {
302                 t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", dReceived, 1)
303         }
304
305         // Try closing the fsnotify instance
306         t.Log("calling Close()")
307         watcher.Close()
308         t.Log("waiting for the event channel to become closed...")
309         select {
310         case <-done:
311                 t.Log("event channel closed")
312         case <-time.After(2 * time.Second):
313                 t.Fatal("event stream was not closed after 2 seconds")
314         }
315 }
316
317 func TestFsnotifyDirOnly(t *testing.T) {
318         watcher := newWatcher(t)
319
320         // Create directory to watch
321         testDir := tempMkdir(t)
322         defer os.RemoveAll(testDir)
323
324         // Create a file before watching directory
325         // This should NOT add any events to the fsnotify event queue
326         testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
327         {
328                 var f *os.File
329                 f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
330                 if err != nil {
331                         t.Fatalf("creating test file failed: %s", err)
332                 }
333                 f.Sync()
334                 f.Close()
335         }
336
337         addWatch(t, watcher, testDir)
338
339         // Receive errors on the error channel on a separate goroutine
340         go func() {
341                 for err := range watcher.Errors {
342                         t.Fatalf("error received: %s", err)
343                 }
344         }()
345
346         testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
347
348         // Receive events on the event channel on a separate goroutine
349         eventstream := watcher.Events
350         var createReceived, modifyReceived, deleteReceived counter
351         done := make(chan bool)
352         go func() {
353                 for event := range eventstream {
354                         // Only count relevant events
355                         if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileAlreadyExists) {
356                                 t.Logf("event received: %s", event)
357                                 if event.Op&Remove == Remove {
358                                         deleteReceived.increment()
359                                 }
360                                 if event.Op&Write == Write {
361                                         modifyReceived.increment()
362                                 }
363                                 if event.Op&Create == Create {
364                                         createReceived.increment()
365                                 }
366                         } else {
367                                 t.Logf("unexpected event received: %s", event)
368                         }
369                 }
370                 done <- true
371         }()
372
373         // Create a file
374         // This should add at least one event to the fsnotify event queue
375         var f *os.File
376         f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
377         if err != nil {
378                 t.Fatalf("creating test file failed: %s", err)
379         }
380         f.Sync()
381
382         time.Sleep(time.Millisecond)
383         f.WriteString("data")
384         f.Sync()
385         f.Close()
386
387         time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
388
389         os.Remove(testFile)
390         os.Remove(testFileAlreadyExists)
391
392         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
393         time.Sleep(500 * time.Millisecond)
394         cReceived := createReceived.value()
395         if cReceived != 1 {
396                 t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 1)
397         }
398         mReceived := modifyReceived.value()
399         if mReceived != 1 {
400                 t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
401         }
402         dReceived := deleteReceived.value()
403         if dReceived != 2 {
404                 t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
405         }
406
407         // Try closing the fsnotify instance
408         t.Log("calling Close()")
409         watcher.Close()
410         t.Log("waiting for the event channel to become closed...")
411         select {
412         case <-done:
413                 t.Log("event channel closed")
414         case <-time.After(2 * time.Second):
415                 t.Fatal("event stream was not closed after 2 seconds")
416         }
417 }
418
419 func TestFsnotifyDeleteWatchedDir(t *testing.T) {
420         watcher := newWatcher(t)
421         defer watcher.Close()
422
423         // Create directory to watch
424         testDir := tempMkdir(t)
425         defer os.RemoveAll(testDir)
426
427         // Create a file before watching directory
428         testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
429         {
430                 var f *os.File
431                 f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
432                 if err != nil {
433                         t.Fatalf("creating test file failed: %s", err)
434                 }
435                 f.Sync()
436                 f.Close()
437         }
438
439         addWatch(t, watcher, testDir)
440
441         // Add a watch for testFile
442         addWatch(t, watcher, testFileAlreadyExists)
443
444         // Receive errors on the error channel on a separate goroutine
445         go func() {
446                 for err := range watcher.Errors {
447                         t.Fatalf("error received: %s", err)
448                 }
449         }()
450
451         // Receive events on the event channel on a separate goroutine
452         eventstream := watcher.Events
453         var deleteReceived counter
454         go func() {
455                 for event := range eventstream {
456                         // Only count relevant events
457                         if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFileAlreadyExists) {
458                                 t.Logf("event received: %s", event)
459                                 if event.Op&Remove == Remove {
460                                         deleteReceived.increment()
461                                 }
462                         } else {
463                                 t.Logf("unexpected event received: %s", event)
464                         }
465                 }
466         }()
467
468         os.RemoveAll(testDir)
469
470         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
471         time.Sleep(500 * time.Millisecond)
472         dReceived := deleteReceived.value()
473         if dReceived < 2 {
474                 t.Fatalf("did not receive at least %d delete events, received %d after 500 ms", 2, dReceived)
475         }
476 }
477
478 func TestFsnotifySubDir(t *testing.T) {
479         watcher := newWatcher(t)
480
481         // Create directory to watch
482         testDir := tempMkdir(t)
483         defer os.RemoveAll(testDir)
484
485         testFile1 := filepath.Join(testDir, "TestFsnotifyFile1.testfile")
486         testSubDir := filepath.Join(testDir, "sub")
487         testSubDirFile := filepath.Join(testDir, "sub/TestFsnotifyFile1.testfile")
488
489         // Receive errors on the error channel on a separate goroutine
490         go func() {
491                 for err := range watcher.Errors {
492                         t.Fatalf("error received: %s", err)
493                 }
494         }()
495
496         // Receive events on the event channel on a separate goroutine
497         eventstream := watcher.Events
498         var createReceived, deleteReceived counter
499         done := make(chan bool)
500         go func() {
501                 for event := range eventstream {
502                         // Only count relevant events
503                         if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testSubDir) || event.Name == filepath.Clean(testFile1) {
504                                 t.Logf("event received: %s", event)
505                                 if event.Op&Create == Create {
506                                         createReceived.increment()
507                                 }
508                                 if event.Op&Remove == Remove {
509                                         deleteReceived.increment()
510                                 }
511                         } else {
512                                 t.Logf("unexpected event received: %s", event)
513                         }
514                 }
515                 done <- true
516         }()
517
518         addWatch(t, watcher, testDir)
519
520         // Create sub-directory
521         if err := os.Mkdir(testSubDir, 0777); err != nil {
522                 t.Fatalf("failed to create test sub-directory: %s", err)
523         }
524
525         // Create a file
526         var f *os.File
527         f, err := os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
528         if err != nil {
529                 t.Fatalf("creating test file failed: %s", err)
530         }
531         f.Sync()
532         f.Close()
533
534         // Create a file (Should not see this! we are not watching subdir)
535         var fs *os.File
536         fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
537         if err != nil {
538                 t.Fatalf("creating test file failed: %s", err)
539         }
540         fs.Sync()
541         fs.Close()
542
543         time.Sleep(200 * time.Millisecond)
544
545         // Make sure receive deletes for both file and sub-directory
546         os.RemoveAll(testSubDir)
547         os.Remove(testFile1)
548
549         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
550         time.Sleep(500 * time.Millisecond)
551         cReceived := createReceived.value()
552         if cReceived != 2 {
553                 t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
554         }
555         dReceived := deleteReceived.value()
556         if dReceived != 2 {
557                 t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
558         }
559
560         // Try closing the fsnotify instance
561         t.Log("calling Close()")
562         watcher.Close()
563         t.Log("waiting for the event channel to become closed...")
564         select {
565         case <-done:
566                 t.Log("event channel closed")
567         case <-time.After(2 * time.Second):
568                 t.Fatal("event stream was not closed after 2 seconds")
569         }
570 }
571
572 func TestFsnotifyRename(t *testing.T) {
573         watcher := newWatcher(t)
574
575         // Create directory to watch
576         testDir := tempMkdir(t)
577         defer os.RemoveAll(testDir)
578
579         addWatch(t, watcher, testDir)
580
581         // Receive errors on the error channel on a separate goroutine
582         go func() {
583                 for err := range watcher.Errors {
584                         t.Fatalf("error received: %s", err)
585                 }
586         }()
587
588         testFile := filepath.Join(testDir, "TestFsnotifyEvents.testfile")
589         testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
590
591         // Receive events on the event channel on a separate goroutine
592         eventstream := watcher.Events
593         var renameReceived counter
594         done := make(chan bool)
595         go func() {
596                 for event := range eventstream {
597                         // Only count relevant events
598                         if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
599                                 if event.Op&Rename == Rename {
600                                         renameReceived.increment()
601                                 }
602                                 t.Logf("event received: %s", event)
603                         } else {
604                                 t.Logf("unexpected event received: %s", event)
605                         }
606                 }
607                 done <- true
608         }()
609
610         // Create a file
611         // This should add at least one event to the fsnotify event queue
612         var f *os.File
613         f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
614         if err != nil {
615                 t.Fatalf("creating test file failed: %s", err)
616         }
617         f.Sync()
618
619         f.WriteString("data")
620         f.Sync()
621         f.Close()
622
623         // Add a watch for testFile
624         addWatch(t, watcher, testFile)
625
626         if err := testRename(testFile, testFileRenamed); err != nil {
627                 t.Fatalf("rename failed: %s", err)
628         }
629
630         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
631         time.Sleep(500 * time.Millisecond)
632         if renameReceived.value() == 0 {
633                 t.Fatal("fsnotify rename events have not been received after 500 ms")
634         }
635
636         // Try closing the fsnotify instance
637         t.Log("calling Close()")
638         watcher.Close()
639         t.Log("waiting for the event channel to become closed...")
640         select {
641         case <-done:
642                 t.Log("event channel closed")
643         case <-time.After(2 * time.Second):
644                 t.Fatal("event stream was not closed after 2 seconds")
645         }
646
647         os.Remove(testFileRenamed)
648 }
649
650 func TestFsnotifyRenameToCreate(t *testing.T) {
651         watcher := newWatcher(t)
652
653         // Create directory to watch
654         testDir := tempMkdir(t)
655         defer os.RemoveAll(testDir)
656
657         // Create directory to get file
658         testDirFrom := tempMkdir(t)
659         defer os.RemoveAll(testDirFrom)
660
661         addWatch(t, watcher, testDir)
662
663         // Receive errors on the error channel on a separate goroutine
664         go func() {
665                 for err := range watcher.Errors {
666                         t.Fatalf("error received: %s", err)
667                 }
668         }()
669
670         testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
671         testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
672
673         // Receive events on the event channel on a separate goroutine
674         eventstream := watcher.Events
675         var createReceived counter
676         done := make(chan bool)
677         go func() {
678                 for event := range eventstream {
679                         // Only count relevant events
680                         if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
681                                 if event.Op&Create == Create {
682                                         createReceived.increment()
683                                 }
684                                 t.Logf("event received: %s", event)
685                         } else {
686                                 t.Logf("unexpected event received: %s", event)
687                         }
688                 }
689                 done <- true
690         }()
691
692         // Create a file
693         // This should add at least one event to the fsnotify event queue
694         var f *os.File
695         f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
696         if err != nil {
697                 t.Fatalf("creating test file failed: %s", err)
698         }
699         f.Sync()
700         f.Close()
701
702         if err := testRename(testFile, testFileRenamed); err != nil {
703                 t.Fatalf("rename failed: %s", err)
704         }
705
706         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
707         time.Sleep(500 * time.Millisecond)
708         if createReceived.value() == 0 {
709                 t.Fatal("fsnotify create events have not been received after 500 ms")
710         }
711
712         // Try closing the fsnotify instance
713         t.Log("calling Close()")
714         watcher.Close()
715         t.Log("waiting for the event channel to become closed...")
716         select {
717         case <-done:
718                 t.Log("event channel closed")
719         case <-time.After(2 * time.Second):
720                 t.Fatal("event stream was not closed after 2 seconds")
721         }
722
723         os.Remove(testFileRenamed)
724 }
725
726 func TestFsnotifyRenameToOverwrite(t *testing.T) {
727         switch runtime.GOOS {
728         case "plan9", "windows":
729                 t.Skipf("skipping test on %q (os.Rename over existing file does not create event).", runtime.GOOS)
730         }
731
732         watcher := newWatcher(t)
733
734         // Create directory to watch
735         testDir := tempMkdir(t)
736         defer os.RemoveAll(testDir)
737
738         // Create directory to get file
739         testDirFrom := tempMkdir(t)
740         defer os.RemoveAll(testDirFrom)
741
742         testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
743         testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
744
745         // Create a file
746         var fr *os.File
747         fr, err := os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666)
748         if err != nil {
749                 t.Fatalf("creating test file failed: %s", err)
750         }
751         fr.Sync()
752         fr.Close()
753
754         addWatch(t, watcher, testDir)
755
756         // Receive errors on the error channel on a separate goroutine
757         go func() {
758                 for err := range watcher.Errors {
759                         t.Fatalf("error received: %s", err)
760                 }
761         }()
762
763         // Receive events on the event channel on a separate goroutine
764         eventstream := watcher.Events
765         var eventReceived counter
766         done := make(chan bool)
767         go func() {
768                 for event := range eventstream {
769                         // Only count relevant events
770                         if event.Name == filepath.Clean(testFileRenamed) {
771                                 eventReceived.increment()
772                                 t.Logf("event received: %s", event)
773                         } else {
774                                 t.Logf("unexpected event received: %s", event)
775                         }
776                 }
777                 done <- true
778         }()
779
780         // Create a file
781         // This should add at least one event to the fsnotify event queue
782         var f *os.File
783         f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
784         if err != nil {
785                 t.Fatalf("creating test file failed: %s", err)
786         }
787         f.Sync()
788         f.Close()
789
790         if err := testRename(testFile, testFileRenamed); err != nil {
791                 t.Fatalf("rename failed: %s", err)
792         }
793
794         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
795         time.Sleep(500 * time.Millisecond)
796         if eventReceived.value() == 0 {
797                 t.Fatal("fsnotify events have not been received after 500 ms")
798         }
799
800         // Try closing the fsnotify instance
801         t.Log("calling Close()")
802         watcher.Close()
803         t.Log("waiting for the event channel to become closed...")
804         select {
805         case <-done:
806                 t.Log("event channel closed")
807         case <-time.After(2 * time.Second):
808                 t.Fatal("event stream was not closed after 2 seconds")
809         }
810
811         os.Remove(testFileRenamed)
812 }
813
814 func TestRemovalOfWatch(t *testing.T) {
815         // Create directory to watch
816         testDir := tempMkdir(t)
817         defer os.RemoveAll(testDir)
818
819         // Create a file before watching directory
820         testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
821         {
822                 var f *os.File
823                 f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
824                 if err != nil {
825                         t.Fatalf("creating test file failed: %s", err)
826                 }
827                 f.Sync()
828                 f.Close()
829         }
830
831         watcher := newWatcher(t)
832         defer watcher.Close()
833
834         addWatch(t, watcher, testDir)
835         if err := watcher.Remove(testDir); err != nil {
836                 t.Fatalf("Could not remove the watch: %v\n", err)
837         }
838
839         go func() {
840                 select {
841                 case ev := <-watcher.Events:
842                         t.Fatalf("We received event: %v\n", ev)
843                 case <-time.After(500 * time.Millisecond):
844                         t.Log("No event received, as expected.")
845                 }
846         }()
847
848         time.Sleep(200 * time.Millisecond)
849         // Modify the file outside of the watched dir
850         f, err := os.Open(testFileAlreadyExists)
851         if err != nil {
852                 t.Fatalf("Open test file failed: %s", err)
853         }
854         f.WriteString("data")
855         f.Sync()
856         f.Close()
857         if err := os.Chmod(testFileAlreadyExists, 0700); err != nil {
858                 t.Fatalf("chmod failed: %s", err)
859         }
860         time.Sleep(400 * time.Millisecond)
861 }
862
863 func TestFsnotifyAttrib(t *testing.T) {
864         if runtime.GOOS == "windows" {
865                 t.Skip("attributes don't work on Windows.")
866         }
867
868         watcher := newWatcher(t)
869
870         // Create directory to watch
871         testDir := tempMkdir(t)
872         defer os.RemoveAll(testDir)
873
874         // Receive errors on the error channel on a separate goroutine
875         go func() {
876                 for err := range watcher.Errors {
877                         t.Fatalf("error received: %s", err)
878                 }
879         }()
880
881         testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
882
883         // Receive events on the event channel on a separate goroutine
884         eventstream := watcher.Events
885         // The modifyReceived counter counts IsModify events that are not IsAttrib,
886         // and the attribReceived counts IsAttrib events (which are also IsModify as
887         // a consequence).
888         var modifyReceived counter
889         var attribReceived counter
890         done := make(chan bool)
891         go func() {
892                 for event := range eventstream {
893                         // Only count relevant events
894                         if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
895                                 if event.Op&Write == Write {
896                                         modifyReceived.increment()
897                                 }
898                                 if event.Op&Chmod == Chmod {
899                                         attribReceived.increment()
900                                 }
901                                 t.Logf("event received: %s", event)
902                         } else {
903                                 t.Logf("unexpected event received: %s", event)
904                         }
905                 }
906                 done <- true
907         }()
908
909         // Create a file
910         // This should add at least one event to the fsnotify event queue
911         var f *os.File
912         f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
913         if err != nil {
914                 t.Fatalf("creating test file failed: %s", err)
915         }
916         f.Sync()
917
918         f.WriteString("data")
919         f.Sync()
920         f.Close()
921
922         // Add a watch for testFile
923         addWatch(t, watcher, testFile)
924
925         if err := os.Chmod(testFile, 0700); err != nil {
926                 t.Fatalf("chmod failed: %s", err)
927         }
928
929         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
930         // Creating/writing a file changes also the mtime, so IsAttrib should be set to true here
931         time.Sleep(500 * time.Millisecond)
932         if modifyReceived.value() != 0 {
933                 t.Fatal("received an unexpected modify event when creating a test file")
934         }
935         if attribReceived.value() == 0 {
936                 t.Fatal("fsnotify attribute events have not received after 500 ms")
937         }
938
939         // Modifying the contents of the file does not set the attrib flag (although eg. the mtime
940         // might have been modified).
941         modifyReceived.reset()
942         attribReceived.reset()
943
944         f, err = os.OpenFile(testFile, os.O_WRONLY, 0)
945         if err != nil {
946                 t.Fatalf("reopening test file failed: %s", err)
947         }
948
949         f.WriteString("more data")
950         f.Sync()
951         f.Close()
952
953         time.Sleep(500 * time.Millisecond)
954
955         if modifyReceived.value() != 1 {
956                 t.Fatal("didn't receive a modify event after changing test file contents")
957         }
958
959         if attribReceived.value() != 0 {
960                 t.Fatal("did receive an unexpected attrib event after changing test file contents")
961         }
962
963         modifyReceived.reset()
964         attribReceived.reset()
965
966         // Doing a chmod on the file should trigger an event with the "attrib" flag set (the contents
967         // of the file are not changed though)
968         if err := os.Chmod(testFile, 0600); err != nil {
969                 t.Fatalf("chmod failed: %s", err)
970         }
971
972         time.Sleep(500 * time.Millisecond)
973
974         if attribReceived.value() != 1 {
975                 t.Fatal("didn't receive an attribute change after 500ms")
976         }
977
978         // Try closing the fsnotify instance
979         t.Log("calling Close()")
980         watcher.Close()
981         t.Log("waiting for the event channel to become closed...")
982         select {
983         case <-done:
984                 t.Log("event channel closed")
985         case <-time.After(1e9):
986                 t.Fatal("event stream was not closed after 1 second")
987         }
988
989         os.Remove(testFile)
990 }
991
992 func TestFsnotifyClose(t *testing.T) {
993         watcher := newWatcher(t)
994         watcher.Close()
995
996         var done int32
997         go func() {
998                 watcher.Close()
999                 atomic.StoreInt32(&done, 1)
1000         }()
1001
1002         time.Sleep(50e6) // 50 ms
1003         if atomic.LoadInt32(&done) == 0 {
1004                 t.Fatal("double Close() test failed: second Close() call didn't return")
1005         }
1006
1007         testDir := tempMkdir(t)
1008         defer os.RemoveAll(testDir)
1009
1010         if err := watcher.Add(testDir); err == nil {
1011                 t.Fatal("expected error on Watch() after Close(), got nil")
1012         }
1013 }
1014
1015 func TestFsnotifyFakeSymlink(t *testing.T) {
1016         if runtime.GOOS == "windows" {
1017                 t.Skip("symlinks don't work on Windows.")
1018         }
1019
1020         watcher := newWatcher(t)
1021
1022         // Create directory to watch
1023         testDir := tempMkdir(t)
1024         defer os.RemoveAll(testDir)
1025
1026         var errorsReceived counter
1027         // Receive errors on the error channel on a separate goroutine
1028         go func() {
1029                 for errors := range watcher.Errors {
1030                         t.Logf("Received error: %s", errors)
1031                         errorsReceived.increment()
1032                 }
1033         }()
1034
1035         // Count the CREATE events received
1036         var createEventsReceived, otherEventsReceived counter
1037         go func() {
1038                 for ev := range watcher.Events {
1039                         t.Logf("event received: %s", ev)
1040                         if ev.Op&Create == Create {
1041                                 createEventsReceived.increment()
1042                         } else {
1043                                 otherEventsReceived.increment()
1044                         }
1045                 }
1046         }()
1047
1048         addWatch(t, watcher, testDir)
1049
1050         if err := os.Symlink(filepath.Join(testDir, "zzz"), filepath.Join(testDir, "zzznew")); err != nil {
1051                 t.Fatalf("Failed to create bogus symlink: %s", err)
1052         }
1053         t.Logf("Created bogus symlink")
1054
1055         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
1056         time.Sleep(500 * time.Millisecond)
1057
1058         // Should not be error, just no events for broken links (watching nothing)
1059         if errorsReceived.value() > 0 {
1060                 t.Fatal("fsnotify errors have been received.")
1061         }
1062         if otherEventsReceived.value() > 0 {
1063                 t.Fatal("fsnotify other events received on the broken link")
1064         }
1065
1066         // Except for 1 create event (for the link itself)
1067         if createEventsReceived.value() == 0 {
1068                 t.Fatal("fsnotify create events were not received after 500 ms")
1069         }
1070         if createEventsReceived.value() > 1 {
1071                 t.Fatal("fsnotify more create events received than expected")
1072         }
1073
1074         // Try closing the fsnotify instance
1075         t.Log("calling Close()")
1076         watcher.Close()
1077 }
1078
1079 func TestCyclicSymlink(t *testing.T) {
1080         if runtime.GOOS == "windows" {
1081                 t.Skip("symlinks don't work on Windows.")
1082         }
1083
1084         watcher := newWatcher(t)
1085
1086         testDir := tempMkdir(t)
1087         defer os.RemoveAll(testDir)
1088
1089         link := path.Join(testDir, "link")
1090         if err := os.Symlink(".", link); err != nil {
1091                 t.Fatalf("could not make symlink: %v", err)
1092         }
1093         addWatch(t, watcher, testDir)
1094
1095         var createEventsReceived counter
1096         go func() {
1097                 for ev := range watcher.Events {
1098                         if ev.Op&Create == Create {
1099                                 createEventsReceived.increment()
1100                         }
1101                 }
1102         }()
1103
1104         if err := os.Remove(link); err != nil {
1105                 t.Fatalf("Error removing link: %v", err)
1106         }
1107
1108         // It would be nice to be able to expect a delete event here, but kqueue has
1109         // no way for us to get events on symlinks themselves, because opening them
1110         // opens an fd to the file to which they point.
1111
1112         if err := ioutil.WriteFile(link, []byte("foo"), 0700); err != nil {
1113                 t.Fatalf("could not make symlink: %v", err)
1114         }
1115
1116         // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
1117         time.Sleep(500 * time.Millisecond)
1118
1119         if got := createEventsReceived.value(); got == 0 {
1120                 t.Errorf("want at least 1 create event got %v", got)
1121         }
1122
1123         watcher.Close()
1124 }
1125
1126 // TestConcurrentRemovalOfWatch tests that concurrent calls to RemoveWatch do not race.
1127 // See https://codereview.appspot.com/103300045/
1128 // go test -test.run=TestConcurrentRemovalOfWatch -test.cpu=1,1,1,1,1 -race
1129 func TestConcurrentRemovalOfWatch(t *testing.T) {
1130         if runtime.GOOS != "darwin" {
1131                 t.Skip("regression test for race only present on darwin")
1132         }
1133
1134         // Create directory to watch
1135         testDir := tempMkdir(t)
1136         defer os.RemoveAll(testDir)
1137
1138         // Create a file before watching directory
1139         testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
1140         {
1141                 var f *os.File
1142                 f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
1143                 if err != nil {
1144                         t.Fatalf("creating test file failed: %s", err)
1145                 }
1146                 f.Sync()
1147                 f.Close()
1148         }
1149
1150         watcher := newWatcher(t)
1151         defer watcher.Close()
1152
1153         addWatch(t, watcher, testDir)
1154
1155         // Test that RemoveWatch can be invoked concurrently, with no data races.
1156         removed1 := make(chan struct{})
1157         go func() {
1158                 defer close(removed1)
1159                 watcher.Remove(testDir)
1160         }()
1161         removed2 := make(chan struct{})
1162         go func() {
1163                 close(removed2)
1164                 watcher.Remove(testDir)
1165         }()
1166         <-removed1
1167         <-removed2
1168 }
1169
1170 func TestClose(t *testing.T) {
1171         // Regression test for #59 bad file descriptor from Close
1172         testDir := tempMkdir(t)
1173         defer os.RemoveAll(testDir)
1174
1175         watcher := newWatcher(t)
1176         if err := watcher.Add(testDir); err != nil {
1177                 t.Fatalf("Expected no error on Add, got %v", err)
1178         }
1179         err := watcher.Close()
1180         if err != nil {
1181                 t.Fatalf("Expected no error on Close, got %v.", err)
1182         }
1183 }
1184
1185 // TestRemoveWithClose tests if one can handle Remove events and, at the same
1186 // time, close Watcher object without any data races.
1187 func TestRemoveWithClose(t *testing.T) {
1188         testDir := tempMkdir(t)
1189         defer os.RemoveAll(testDir)
1190
1191         const fileN = 200
1192         tempFiles := make([]string, 0, fileN)
1193         for i := 0; i < fileN; i++ {
1194                 tempFiles = append(tempFiles, tempMkFile(t, testDir))
1195         }
1196         watcher := newWatcher(t)
1197         if err := watcher.Add(testDir); err != nil {
1198                 t.Fatalf("Expected no error on Add, got %v", err)
1199         }
1200         startC, stopC := make(chan struct{}), make(chan struct{})
1201         errC := make(chan error)
1202         go func() {
1203                 for {
1204                         select {
1205                         case <-watcher.Errors:
1206                         case <-watcher.Events:
1207                         case <-stopC:
1208                                 return
1209                         }
1210                 }
1211         }()
1212         go func() {
1213                 <-startC
1214                 for _, fileName := range tempFiles {
1215                         os.Remove(fileName)
1216                 }
1217         }()
1218         go func() {
1219                 <-startC
1220                 errC <- watcher.Close()
1221         }()
1222         close(startC)
1223         defer close(stopC)
1224         if err := <-errC; err != nil {
1225                 t.Fatalf("Expected no error on Close, got %v.", err)
1226         }
1227 }
1228
1229 func testRename(file1, file2 string) error {
1230         switch runtime.GOOS {
1231         case "windows", "plan9":
1232                 return os.Rename(file1, file2)
1233         default:
1234                 cmd := exec.Command("mv", file1, file2)
1235                 return cmd.Run()
1236         }
1237 }