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.
5 // +build !plan9,!solaris
26 func (c *counter) increment() {
27 atomic.AddInt32(&c.val, 1)
30 func (c *counter) value() int32 {
31 return atomic.LoadInt32(&c.val)
34 func (c *counter) reset() {
35 atomic.StoreInt32(&c.val, 0)
38 // tempMkdir makes a temporary directory
39 func tempMkdir(t *testing.T) string {
40 dir, err := ioutil.TempDir("", "fsnotify")
42 t.Fatalf("failed to create test directory: %s", err)
47 // tempMkFile makes a temporary file.
48 func tempMkFile(t *testing.T, dir string) string {
49 f, err := ioutil.TempFile(dir, "fsnotify")
51 t.Fatalf("failed to create test file: %v", err)
57 // newWatcher initializes an fsnotify Watcher instance.
58 func newWatcher(t *testing.T) *Watcher {
59 watcher, err := NewWatcher()
61 t.Fatalf("NewWatcher() failed: %s", err)
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)
73 func TestFsnotifyMultipleOperations(t *testing.T) {
74 watcher := newWatcher(t)
76 // Receive errors on the error channel on a separate goroutine
78 for err := range watcher.Errors {
79 t.Fatalf("error received: %s", err)
83 // Create directory to watch
84 testDir := tempMkdir(t)
85 defer os.RemoveAll(testDir)
87 // Create directory that's not watched
88 testDirToMoveFiles := tempMkdir(t)
89 defer os.RemoveAll(testDirToMoveFiles)
91 testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
92 testFileRenamed := filepath.Join(testDirToMoveFiles, "TestFsnotifySeqRename.testfile")
94 addWatch(t, watcher, testDir)
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)
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()
108 if event.Op&Write == Write {
109 modifyReceived.increment()
111 if event.Op&Create == Create {
112 createReceived.increment()
114 if event.Op&Rename == Rename {
115 renameReceived.increment()
118 t.Logf("unexpected event received: %s", event)
125 // This should add at least one event to the fsnotify event queue
127 f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
129 t.Fatalf("creating test file failed: %s", err)
133 time.Sleep(time.Millisecond)
134 f.WriteString("data")
138 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
140 if err := testRename(testFile, testFileRenamed); err != nil {
141 t.Fatalf("rename failed: %s", err)
144 // Modify the file outside of the watched dir
145 f, err = os.Open(testFileRenamed)
147 t.Fatalf("open test renamed file failed: %s", err)
149 f.WriteString("data")
153 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
155 // Recreate the file that was moved
156 f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
158 t.Fatalf("creating test file failed: %s", err)
161 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
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()
167 t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
169 mReceived := modifyReceived.value()
171 t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
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)
179 // Try closing the fsnotify instance
180 t.Log("calling Close()")
182 t.Log("waiting for the event channel to become closed...")
185 t.Log("event channel closed")
186 case <-time.After(2 * time.Second):
187 t.Fatal("event stream was not closed after 2 seconds")
191 func TestFsnotifyMultipleCreates(t *testing.T) {
192 watcher := newWatcher(t)
194 // Receive errors on the error channel on a separate goroutine
196 for err := range watcher.Errors {
197 t.Fatalf("error received: %s", err)
201 // Create directory to watch
202 testDir := tempMkdir(t)
203 defer os.RemoveAll(testDir)
205 testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
207 addWatch(t, watcher, testDir)
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)
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()
221 if event.Op&Create == Create {
222 createReceived.increment()
224 if event.Op&Write == Write {
225 modifyReceived.increment()
228 t.Logf("unexpected event received: %s", event)
235 // This should add at least one event to the fsnotify event queue
237 f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
239 t.Fatalf("creating test file failed: %s", err)
243 time.Sleep(time.Millisecond)
244 f.WriteString("data")
248 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
252 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
255 f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
257 t.Fatalf("creating test file failed: %s", err)
260 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
263 f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
265 t.Fatalf("creating test file failed: %s", err)
269 time.Sleep(time.Millisecond)
270 f.WriteString("data")
274 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
277 f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
279 t.Fatalf("creating test file failed: %s", err)
283 time.Sleep(time.Millisecond)
284 f.WriteString("data")
288 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
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()
294 t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
296 mReceived := modifyReceived.value()
298 t.Fatalf("incorrect number of modify events received after 500 ms (%d vs atleast %d)", mReceived, 3)
300 dReceived := deleteReceived.value()
302 t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", dReceived, 1)
305 // Try closing the fsnotify instance
306 t.Log("calling Close()")
308 t.Log("waiting for the event channel to become closed...")
311 t.Log("event channel closed")
312 case <-time.After(2 * time.Second):
313 t.Fatal("event stream was not closed after 2 seconds")
317 func TestFsnotifyDirOnly(t *testing.T) {
318 watcher := newWatcher(t)
320 // Create directory to watch
321 testDir := tempMkdir(t)
322 defer os.RemoveAll(testDir)
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")
329 f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
331 t.Fatalf("creating test file failed: %s", err)
337 addWatch(t, watcher, testDir)
339 // Receive errors on the error channel on a separate goroutine
341 for err := range watcher.Errors {
342 t.Fatalf("error received: %s", err)
346 testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
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)
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()
360 if event.Op&Write == Write {
361 modifyReceived.increment()
363 if event.Op&Create == Create {
364 createReceived.increment()
367 t.Logf("unexpected event received: %s", event)
374 // This should add at least one event to the fsnotify event queue
376 f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
378 t.Fatalf("creating test file failed: %s", err)
382 time.Sleep(time.Millisecond)
383 f.WriteString("data")
387 time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
390 os.Remove(testFileAlreadyExists)
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()
396 t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 1)
398 mReceived := modifyReceived.value()
400 t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
402 dReceived := deleteReceived.value()
404 t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
407 // Try closing the fsnotify instance
408 t.Log("calling Close()")
410 t.Log("waiting for the event channel to become closed...")
413 t.Log("event channel closed")
414 case <-time.After(2 * time.Second):
415 t.Fatal("event stream was not closed after 2 seconds")
419 func TestFsnotifyDeleteWatchedDir(t *testing.T) {
420 watcher := newWatcher(t)
421 defer watcher.Close()
423 // Create directory to watch
424 testDir := tempMkdir(t)
425 defer os.RemoveAll(testDir)
427 // Create a file before watching directory
428 testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
431 f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
433 t.Fatalf("creating test file failed: %s", err)
439 addWatch(t, watcher, testDir)
441 // Add a watch for testFile
442 addWatch(t, watcher, testFileAlreadyExists)
444 // Receive errors on the error channel on a separate goroutine
446 for err := range watcher.Errors {
447 t.Fatalf("error received: %s", err)
451 // Receive events on the event channel on a separate goroutine
452 eventstream := watcher.Events
453 var deleteReceived counter
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()
463 t.Logf("unexpected event received: %s", event)
468 os.RemoveAll(testDir)
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()
474 t.Fatalf("did not receive at least %d delete events, received %d after 500 ms", 2, dReceived)
478 func TestFsnotifySubDir(t *testing.T) {
479 watcher := newWatcher(t)
481 // Create directory to watch
482 testDir := tempMkdir(t)
483 defer os.RemoveAll(testDir)
485 testFile1 := filepath.Join(testDir, "TestFsnotifyFile1.testfile")
486 testSubDir := filepath.Join(testDir, "sub")
487 testSubDirFile := filepath.Join(testDir, "sub/TestFsnotifyFile1.testfile")
489 // Receive errors on the error channel on a separate goroutine
491 for err := range watcher.Errors {
492 t.Fatalf("error received: %s", err)
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)
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()
508 if event.Op&Remove == Remove {
509 deleteReceived.increment()
512 t.Logf("unexpected event received: %s", event)
518 addWatch(t, watcher, testDir)
520 // Create sub-directory
521 if err := os.Mkdir(testSubDir, 0777); err != nil {
522 t.Fatalf("failed to create test sub-directory: %s", err)
527 f, err := os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
529 t.Fatalf("creating test file failed: %s", err)
534 // Create a file (Should not see this! we are not watching subdir)
536 fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
538 t.Fatalf("creating test file failed: %s", err)
543 time.Sleep(200 * time.Millisecond)
545 // Make sure receive deletes for both file and sub-directory
546 os.RemoveAll(testSubDir)
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()
553 t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
555 dReceived := deleteReceived.value()
557 t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
560 // Try closing the fsnotify instance
561 t.Log("calling Close()")
563 t.Log("waiting for the event channel to become closed...")
566 t.Log("event channel closed")
567 case <-time.After(2 * time.Second):
568 t.Fatal("event stream was not closed after 2 seconds")
572 func TestFsnotifyRename(t *testing.T) {
573 watcher := newWatcher(t)
575 // Create directory to watch
576 testDir := tempMkdir(t)
577 defer os.RemoveAll(testDir)
579 addWatch(t, watcher, testDir)
581 // Receive errors on the error channel on a separate goroutine
583 for err := range watcher.Errors {
584 t.Fatalf("error received: %s", err)
588 testFile := filepath.Join(testDir, "TestFsnotifyEvents.testfile")
589 testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
591 // Receive events on the event channel on a separate goroutine
592 eventstream := watcher.Events
593 var renameReceived counter
594 done := make(chan bool)
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()
602 t.Logf("event received: %s", event)
604 t.Logf("unexpected event received: %s", event)
611 // This should add at least one event to the fsnotify event queue
613 f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
615 t.Fatalf("creating test file failed: %s", err)
619 f.WriteString("data")
623 // Add a watch for testFile
624 addWatch(t, watcher, testFile)
626 if err := testRename(testFile, testFileRenamed); err != nil {
627 t.Fatalf("rename failed: %s", err)
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")
636 // Try closing the fsnotify instance
637 t.Log("calling Close()")
639 t.Log("waiting for the event channel to become closed...")
642 t.Log("event channel closed")
643 case <-time.After(2 * time.Second):
644 t.Fatal("event stream was not closed after 2 seconds")
647 os.Remove(testFileRenamed)
650 func TestFsnotifyRenameToCreate(t *testing.T) {
651 watcher := newWatcher(t)
653 // Create directory to watch
654 testDir := tempMkdir(t)
655 defer os.RemoveAll(testDir)
657 // Create directory to get file
658 testDirFrom := tempMkdir(t)
659 defer os.RemoveAll(testDirFrom)
661 addWatch(t, watcher, testDir)
663 // Receive errors on the error channel on a separate goroutine
665 for err := range watcher.Errors {
666 t.Fatalf("error received: %s", err)
670 testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
671 testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
673 // Receive events on the event channel on a separate goroutine
674 eventstream := watcher.Events
675 var createReceived counter
676 done := make(chan bool)
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()
684 t.Logf("event received: %s", event)
686 t.Logf("unexpected event received: %s", event)
693 // This should add at least one event to the fsnotify event queue
695 f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
697 t.Fatalf("creating test file failed: %s", err)
702 if err := testRename(testFile, testFileRenamed); err != nil {
703 t.Fatalf("rename failed: %s", err)
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")
712 // Try closing the fsnotify instance
713 t.Log("calling Close()")
715 t.Log("waiting for the event channel to become closed...")
718 t.Log("event channel closed")
719 case <-time.After(2 * time.Second):
720 t.Fatal("event stream was not closed after 2 seconds")
723 os.Remove(testFileRenamed)
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)
732 watcher := newWatcher(t)
734 // Create directory to watch
735 testDir := tempMkdir(t)
736 defer os.RemoveAll(testDir)
738 // Create directory to get file
739 testDirFrom := tempMkdir(t)
740 defer os.RemoveAll(testDirFrom)
742 testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
743 testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
747 fr, err := os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666)
749 t.Fatalf("creating test file failed: %s", err)
754 addWatch(t, watcher, testDir)
756 // Receive errors on the error channel on a separate goroutine
758 for err := range watcher.Errors {
759 t.Fatalf("error received: %s", err)
763 // Receive events on the event channel on a separate goroutine
764 eventstream := watcher.Events
765 var eventReceived counter
766 done := make(chan bool)
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)
774 t.Logf("unexpected event received: %s", event)
781 // This should add at least one event to the fsnotify event queue
783 f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
785 t.Fatalf("creating test file failed: %s", err)
790 if err := testRename(testFile, testFileRenamed); err != nil {
791 t.Fatalf("rename failed: %s", err)
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")
800 // Try closing the fsnotify instance
801 t.Log("calling Close()")
803 t.Log("waiting for the event channel to become closed...")
806 t.Log("event channel closed")
807 case <-time.After(2 * time.Second):
808 t.Fatal("event stream was not closed after 2 seconds")
811 os.Remove(testFileRenamed)
814 func TestRemovalOfWatch(t *testing.T) {
815 // Create directory to watch
816 testDir := tempMkdir(t)
817 defer os.RemoveAll(testDir)
819 // Create a file before watching directory
820 testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
823 f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
825 t.Fatalf("creating test file failed: %s", err)
831 watcher := newWatcher(t)
832 defer watcher.Close()
834 addWatch(t, watcher, testDir)
835 if err := watcher.Remove(testDir); err != nil {
836 t.Fatalf("Could not remove the watch: %v\n", err)
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.")
848 time.Sleep(200 * time.Millisecond)
849 // Modify the file outside of the watched dir
850 f, err := os.Open(testFileAlreadyExists)
852 t.Fatalf("Open test file failed: %s", err)
854 f.WriteString("data")
857 if err := os.Chmod(testFileAlreadyExists, 0700); err != nil {
858 t.Fatalf("chmod failed: %s", err)
860 time.Sleep(400 * time.Millisecond)
863 func TestFsnotifyAttrib(t *testing.T) {
864 if runtime.GOOS == "windows" {
865 t.Skip("attributes don't work on Windows.")
868 watcher := newWatcher(t)
870 // Create directory to watch
871 testDir := tempMkdir(t)
872 defer os.RemoveAll(testDir)
874 // Receive errors on the error channel on a separate goroutine
876 for err := range watcher.Errors {
877 t.Fatalf("error received: %s", err)
881 testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
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
888 var modifyReceived counter
889 var attribReceived counter
890 done := make(chan bool)
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()
898 if event.Op&Chmod == Chmod {
899 attribReceived.increment()
901 t.Logf("event received: %s", event)
903 t.Logf("unexpected event received: %s", event)
910 // This should add at least one event to the fsnotify event queue
912 f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
914 t.Fatalf("creating test file failed: %s", err)
918 f.WriteString("data")
922 // Add a watch for testFile
923 addWatch(t, watcher, testFile)
925 if err := os.Chmod(testFile, 0700); err != nil {
926 t.Fatalf("chmod failed: %s", err)
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")
935 if attribReceived.value() == 0 {
936 t.Fatal("fsnotify attribute events have not received after 500 ms")
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()
944 f, err = os.OpenFile(testFile, os.O_WRONLY, 0)
946 t.Fatalf("reopening test file failed: %s", err)
949 f.WriteString("more data")
953 time.Sleep(500 * time.Millisecond)
955 if modifyReceived.value() != 1 {
956 t.Fatal("didn't receive a modify event after changing test file contents")
959 if attribReceived.value() != 0 {
960 t.Fatal("did receive an unexpected attrib event after changing test file contents")
963 modifyReceived.reset()
964 attribReceived.reset()
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)
972 time.Sleep(500 * time.Millisecond)
974 if attribReceived.value() != 1 {
975 t.Fatal("didn't receive an attribute change after 500ms")
978 // Try closing the fsnotify instance
979 t.Log("calling Close()")
981 t.Log("waiting for the event channel to become closed...")
984 t.Log("event channel closed")
985 case <-time.After(1e9):
986 t.Fatal("event stream was not closed after 1 second")
992 func TestFsnotifyClose(t *testing.T) {
993 watcher := newWatcher(t)
999 atomic.StoreInt32(&done, 1)
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")
1007 testDir := tempMkdir(t)
1008 defer os.RemoveAll(testDir)
1010 if err := watcher.Add(testDir); err == nil {
1011 t.Fatal("expected error on Watch() after Close(), got nil")
1015 func TestFsnotifyFakeSymlink(t *testing.T) {
1016 if runtime.GOOS == "windows" {
1017 t.Skip("symlinks don't work on Windows.")
1020 watcher := newWatcher(t)
1022 // Create directory to watch
1023 testDir := tempMkdir(t)
1024 defer os.RemoveAll(testDir)
1026 var errorsReceived counter
1027 // Receive errors on the error channel on a separate goroutine
1029 for errors := range watcher.Errors {
1030 t.Logf("Received error: %s", errors)
1031 errorsReceived.increment()
1035 // Count the CREATE events received
1036 var createEventsReceived, otherEventsReceived counter
1038 for ev := range watcher.Events {
1039 t.Logf("event received: %s", ev)
1040 if ev.Op&Create == Create {
1041 createEventsReceived.increment()
1043 otherEventsReceived.increment()
1048 addWatch(t, watcher, testDir)
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)
1053 t.Logf("Created bogus symlink")
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)
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.")
1062 if otherEventsReceived.value() > 0 {
1063 t.Fatal("fsnotify other events received on the broken link")
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")
1070 if createEventsReceived.value() > 1 {
1071 t.Fatal("fsnotify more create events received than expected")
1074 // Try closing the fsnotify instance
1075 t.Log("calling Close()")
1079 func TestCyclicSymlink(t *testing.T) {
1080 if runtime.GOOS == "windows" {
1081 t.Skip("symlinks don't work on Windows.")
1084 watcher := newWatcher(t)
1086 testDir := tempMkdir(t)
1087 defer os.RemoveAll(testDir)
1089 link := path.Join(testDir, "link")
1090 if err := os.Symlink(".", link); err != nil {
1091 t.Fatalf("could not make symlink: %v", err)
1093 addWatch(t, watcher, testDir)
1095 var createEventsReceived counter
1097 for ev := range watcher.Events {
1098 if ev.Op&Create == Create {
1099 createEventsReceived.increment()
1104 if err := os.Remove(link); err != nil {
1105 t.Fatalf("Error removing link: %v", err)
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.
1112 if err := ioutil.WriteFile(link, []byte("foo"), 0700); err != nil {
1113 t.Fatalf("could not make symlink: %v", err)
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)
1119 if got := createEventsReceived.value(); got == 0 {
1120 t.Errorf("want at least 1 create event got %v", got)
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")
1134 // Create directory to watch
1135 testDir := tempMkdir(t)
1136 defer os.RemoveAll(testDir)
1138 // Create a file before watching directory
1139 testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
1142 f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
1144 t.Fatalf("creating test file failed: %s", err)
1150 watcher := newWatcher(t)
1151 defer watcher.Close()
1153 addWatch(t, watcher, testDir)
1155 // Test that RemoveWatch can be invoked concurrently, with no data races.
1156 removed1 := make(chan struct{})
1158 defer close(removed1)
1159 watcher.Remove(testDir)
1161 removed2 := make(chan struct{})
1164 watcher.Remove(testDir)
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)
1175 watcher := newWatcher(t)
1176 if err := watcher.Add(testDir); err != nil {
1177 t.Fatalf("Expected no error on Add, got %v", err)
1179 err := watcher.Close()
1181 t.Fatalf("Expected no error on Close, got %v.", err)
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)
1192 tempFiles := make([]string, 0, fileN)
1193 for i := 0; i < fileN; i++ {
1194 tempFiles = append(tempFiles, tempMkFile(t, testDir))
1196 watcher := newWatcher(t)
1197 if err := watcher.Add(testDir); err != nil {
1198 t.Fatalf("Expected no error on Add, got %v", err)
1200 startC, stopC := make(chan struct{}), make(chan struct{})
1201 errC := make(chan error)
1205 case <-watcher.Errors:
1206 case <-watcher.Events:
1214 for _, fileName := range tempFiles {
1220 errC <- watcher.Close()
1224 if err := <-errC; err != nil {
1225 t.Fatalf("Expected no error on Close, got %v.", err)
1229 func testRename(file1, file2 string) error {
1230 switch runtime.GOOS {
1231 case "windows", "plan9":
1232 return os.Rename(file1, file2)
1234 cmd := exec.Command("mv", file1, file2)