| // Copyright 2010 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package fsnotify |
| |
| import ( |
| "os" |
| "path/filepath" |
| "runtime" |
| "sync/atomic" |
| "testing" |
| "time" |
| ) |
| |
| // An atomic counter |
| type counter struct { |
| val int32 |
| } |
| |
| func (c *counter) increment() { |
| cas := atomic.CompareAndSwapInt32 |
| old := atomic.LoadInt32(&c.val) |
| for swp := cas(&c.val, old, old+1); !swp; swp = cas(&c.val, old, old+1) { |
| old = atomic.LoadInt32(&c.val) |
| } |
| } |
| |
| func (c *counter) value() int32 { |
| return atomic.LoadInt32(&c.val) |
| } |
| |
| func TestFsnotifyMultipleOperations(t *testing.T) { |
| // Create an fsnotify watcher instance and initialize it |
| watcher, err := NewWatcher() |
| if err != nil { |
| t.Fatalf("NewWatcher() failed: %s", err) |
| } |
| |
| // Receive errors on the error channel on a separate goroutine |
| go func() { |
| for err := range watcher.Error { |
| t.Fatalf("error received: %s", err) |
| } |
| }() |
| |
| const testDir string = "_test" |
| const testDirToMoveFiles string = "_test2" |
| |
| // Create directory to watch |
| if err := os.Mkdir(testDir, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDir) |
| |
| // Create directory to that's not watched |
| if err := os.Mkdir(testDirToMoveFiles, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDirToMoveFiles) |
| |
| const testFile string = "_test/TestFsnotifySeq.testfile" |
| const testFileRenamed string = "_test2/TestFsnotifySeqRename.testfile" |
| |
| // Add a watch for testDir |
| err = watcher.Watch(testDir) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| // Receive events on the event channel on a separate goroutine |
| eventstream := watcher.Event |
| var createReceived, modifyReceived, deleteReceived, renameReceived counter |
| done := make(chan bool) |
| go func() { |
| for event := range eventstream { |
| // Only count relevant events |
| if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) { |
| t.Logf("event received: %s", event) |
| if event.IsDelete() { |
| deleteReceived.increment() |
| } |
| if event.IsModify() { |
| modifyReceived.increment() |
| } |
| if event.IsCreate() { |
| createReceived.increment() |
| } |
| if event.IsRename() { |
| renameReceived.increment() |
| } |
| } else { |
| t.Logf("unexpected event received: %s", event) |
| } |
| } |
| done <- true |
| }() |
| |
| // Create a file |
| // This should add at least one event to the fsnotify event queue |
| var f *os.File |
| f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| |
| time.Sleep(time.Millisecond) |
| f.WriteString("data") |
| f.Sync() |
| f.Close() |
| |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| err = os.Rename(testFile, testFileRenamed) |
| if err != nil { |
| t.Fatalf("rename failed: %s", err) |
| } |
| |
| // Modify the file outside of the watched dir |
| f, err = os.Open(testFileRenamed) |
| if err != nil { |
| t.Fatalf("open test renamed file failed: %s", err) |
| } |
| f.WriteString("data") |
| f.Sync() |
| f.Close() |
| |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| // Recreate the file that was moved |
| f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Close() |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| // We expect this event to be received almost immediately, but let's wait 500 ms to be sure |
| time.Sleep(500 * time.Millisecond) |
| cReceived := createReceived.value() |
| if cReceived != 2 { |
| t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2) |
| } |
| mReceived := modifyReceived.value() |
| if mReceived != 1 { |
| t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1) |
| } |
| dReceived := deleteReceived.value() |
| rReceived := renameReceived.value() |
| if dReceived+rReceived != 1 { |
| t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", rReceived+dReceived, 1) |
| } |
| |
| // Try closing the fsnotify instance |
| t.Log("calling Close()") |
| watcher.Close() |
| t.Log("waiting for the event channel to become closed...") |
| select { |
| case <-done: |
| t.Log("event channel closed") |
| case <-time.After(2 * time.Second): |
| t.Fatal("event stream was not closed after 2 seconds") |
| } |
| } |
| |
| func TestFsnotifyMultipleCreates(t *testing.T) { |
| // Create an fsnotify watcher instance and initialize it |
| watcher, err := NewWatcher() |
| if err != nil { |
| t.Fatalf("NewWatcher() failed: %s", err) |
| } |
| |
| // Receive errors on the error channel on a separate goroutine |
| go func() { |
| for err := range watcher.Error { |
| t.Fatalf("error received: %s", err) |
| } |
| }() |
| |
| const testDir string = "_test" |
| |
| // Create directory to watch |
| if err := os.Mkdir(testDir, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDir) |
| |
| const testFile string = "_test/TestFsnotifySeq.testfile" |
| |
| // Add a watch for testDir |
| err = watcher.Watch(testDir) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| // Receive events on the event channel on a separate goroutine |
| eventstream := watcher.Event |
| var createReceived, modifyReceived, deleteReceived counter |
| done := make(chan bool) |
| go func() { |
| for event := range eventstream { |
| // Only count relevant events |
| if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) { |
| t.Logf("event received: %s", event) |
| if event.IsDelete() { |
| deleteReceived.increment() |
| } |
| if event.IsCreate() { |
| createReceived.increment() |
| } |
| if event.IsModify() { |
| modifyReceived.increment() |
| } |
| } else { |
| t.Logf("unexpected event received: %s", event) |
| } |
| } |
| done <- true |
| }() |
| |
| // Create a file |
| // This should add at least one event to the fsnotify event queue |
| var f *os.File |
| f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| |
| time.Sleep(time.Millisecond) |
| f.WriteString("data") |
| f.Sync() |
| f.Close() |
| |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| os.Remove(testFile) |
| |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| // Recreate the file |
| f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Close() |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| // Modify |
| f, err = os.OpenFile(testFile, os.O_WRONLY, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| |
| time.Sleep(time.Millisecond) |
| f.WriteString("data") |
| f.Sync() |
| f.Close() |
| |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| // Modify |
| f, err = os.OpenFile(testFile, os.O_WRONLY, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| |
| time.Sleep(time.Millisecond) |
| f.WriteString("data") |
| f.Sync() |
| f.Close() |
| |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| // We expect this event to be received almost immediately, but let's wait 500 ms to be sure |
| time.Sleep(500 * time.Millisecond) |
| cReceived := createReceived.value() |
| if cReceived != 2 { |
| t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2) |
| } |
| mReceived := modifyReceived.value() |
| if mReceived != 3 { |
| t.Fatalf("incorrect number of modify events received after 500 ms (%d vs atleast %d)", mReceived, 3) |
| } |
| dReceived := deleteReceived.value() |
| if dReceived != 1 { |
| t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", dReceived, 1) |
| } |
| |
| // Try closing the fsnotify instance |
| t.Log("calling Close()") |
| watcher.Close() |
| t.Log("waiting for the event channel to become closed...") |
| select { |
| case <-done: |
| t.Log("event channel closed") |
| case <-time.After(2 * time.Second): |
| t.Fatal("event stream was not closed after 2 seconds") |
| } |
| } |
| |
| func TestFsnotifyDirOnly(t *testing.T) { |
| // Create an fsnotify watcher instance and initialize it |
| watcher, err := NewWatcher() |
| if err != nil { |
| t.Fatalf("NewWatcher() failed: %s", err) |
| } |
| |
| const testDir string = "_test" |
| |
| // Create directory to watch |
| if err := os.Mkdir(testDir, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDir) |
| |
| // Create a file before watching directory |
| // This should NOT add any events to the fsnotify event queue |
| const testFileAlreadyExists string = "_test/TestFsnotifyEventsExisting.testfile" |
| { |
| var f *os.File |
| f, err = os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| f.Close() |
| } |
| |
| // Add a watch for testDir |
| err = watcher.Watch(testDir) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| |
| // Receive errors on the error channel on a separate goroutine |
| go func() { |
| for err := range watcher.Error { |
| t.Fatalf("error received: %s", err) |
| } |
| }() |
| |
| const testFile string = "_test/TestFsnotifyDirOnly.testfile" |
| |
| // Receive events on the event channel on a separate goroutine |
| eventstream := watcher.Event |
| var createReceived, modifyReceived, deleteReceived counter |
| done := make(chan bool) |
| go func() { |
| for event := range eventstream { |
| // Only count relevant events |
| if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileAlreadyExists) { |
| t.Logf("event received: %s", event) |
| if event.IsDelete() { |
| deleteReceived.increment() |
| } |
| if event.IsModify() { |
| modifyReceived.increment() |
| } |
| if event.IsCreate() { |
| createReceived.increment() |
| } |
| } else { |
| t.Logf("unexpected event received: %s", event) |
| } |
| } |
| done <- true |
| }() |
| |
| // Create a file |
| // This should add at least one event to the fsnotify event queue |
| var f *os.File |
| f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| |
| time.Sleep(time.Millisecond) |
| f.WriteString("data") |
| f.Sync() |
| f.Close() |
| |
| time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete |
| |
| os.Remove(testFile) |
| os.Remove(testFileAlreadyExists) |
| |
| // We expect this event to be received almost immediately, but let's wait 500 ms to be sure |
| time.Sleep(500 * time.Millisecond) |
| cReceived := createReceived.value() |
| if cReceived != 1 { |
| t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 1) |
| } |
| mReceived := modifyReceived.value() |
| if mReceived != 1 { |
| t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1) |
| } |
| dReceived := deleteReceived.value() |
| if dReceived != 2 { |
| t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2) |
| } |
| |
| // Try closing the fsnotify instance |
| t.Log("calling Close()") |
| watcher.Close() |
| t.Log("waiting for the event channel to become closed...") |
| select { |
| case <-done: |
| t.Log("event channel closed") |
| case <-time.After(2 * time.Second): |
| t.Fatal("event stream was not closed after 2 seconds") |
| } |
| } |
| |
| func TestFsnotifyDeleteWatchedDir(t *testing.T) { |
| // Create an fsnotify watcher instance and initialize it |
| watcher, err := NewWatcher() |
| if err != nil { |
| t.Fatalf("NewWatcher() failed: %s", err) |
| } |
| defer watcher.Close() |
| |
| const testDir string = "_test" |
| |
| // Create directory to watch |
| if err := os.Mkdir(testDir, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| |
| // Create a file before watching directory |
| const testFileAlreadyExists string = "_test/TestFsnotifyEventsExisting.testfile" |
| { |
| var f *os.File |
| f, err = os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| f.Close() |
| } |
| |
| // Add a watch for testDir |
| err = watcher.Watch(testDir) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| |
| // Add a watch for testFile |
| err = watcher.Watch(testFileAlreadyExists) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| |
| // Receive errors on the error channel on a separate goroutine |
| go func() { |
| for err := range watcher.Error { |
| t.Fatalf("error received: %s", err) |
| } |
| }() |
| |
| // Receive events on the event channel on a separate goroutine |
| eventstream := watcher.Event |
| var deleteReceived counter |
| go func() { |
| for event := range eventstream { |
| // Only count relevant events |
| if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFileAlreadyExists) { |
| t.Logf("event received: %s", event) |
| if event.IsDelete() { |
| deleteReceived.increment() |
| } |
| } else { |
| t.Logf("unexpected event received: %s", event) |
| } |
| } |
| }() |
| |
| os.RemoveAll(testDir) |
| |
| // We expect this event to be received almost immediately, but let's wait 500 ms to be sure |
| time.Sleep(500 * time.Millisecond) |
| dReceived := deleteReceived.value() |
| if dReceived < 2 { |
| t.Fatalf("did not receive at least %d delete events, received %d after 500 ms", 2, dReceived) |
| } |
| } |
| |
| func TestFsnotifySubDir(t *testing.T) { |
| t.Skip("fails on OS X at least") |
| |
| // Create an fsnotify watcher instance and initialize it |
| watcher, err := NewWatcher() |
| if err != nil { |
| t.Fatalf("NewWatcher() failed: %s", err) |
| } |
| |
| const testDir string = "_test" |
| const testFile1 string = "_test/TestFsnotifyFile1.testfile" |
| const testSubDir string = "_test/sub" |
| const testSubDirFile string = "_test/sub/TestFsnotifyFile1.testfile" |
| |
| // Create directory to watch |
| if err := os.Mkdir(testDir, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDir) |
| |
| // Receive errors on the error channel on a separate goroutine |
| go func() { |
| for err := range watcher.Error { |
| t.Fatalf("error received: %s", err) |
| } |
| }() |
| |
| // Receive events on the event channel on a separate goroutine |
| eventstream := watcher.Event |
| var createReceived, deleteReceived counter |
| done := make(chan bool) |
| go func() { |
| for event := range eventstream { |
| // Only count relevant events |
| if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testSubDir) || event.Name == filepath.Clean(testFile1) { |
| t.Logf("event received: %s", event) |
| if event.IsCreate() { |
| createReceived.increment() |
| } |
| if event.IsDelete() { |
| deleteReceived.increment() |
| } |
| } else { |
| t.Logf("unexpected event received: %s", event) |
| } |
| } |
| done <- true |
| }() |
| |
| // Add a watch for testDir |
| err = watcher.Watch(testDir) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| |
| // Create sub-directory |
| if err := os.Mkdir(testSubDir, 0777); err != nil { |
| t.Fatalf("Failed to create test sub-directory: %s", err) |
| } |
| |
| // Create a file |
| var f *os.File |
| f, err = os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| f.Close() |
| |
| // Create a file (Should not see this! we are not watching subdir) |
| var fs *os.File |
| fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| fs.Sync() |
| fs.Close() |
| |
| // Make sure receive deletes for both file and sub-directory |
| os.RemoveAll(testSubDir) |
| os.Remove(testFile1) |
| |
| // We expect this event to be received almost immediately, but let's wait 500 ms to be sure |
| time.Sleep(500 * time.Millisecond) |
| cReceived := createReceived.value() |
| if cReceived != 2 { |
| t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2) |
| } |
| dReceived := deleteReceived.value() |
| if dReceived != 2 { |
| t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2) |
| } |
| |
| // Try closing the fsnotify instance |
| t.Log("calling Close()") |
| watcher.Close() |
| t.Log("waiting for the event channel to become closed...") |
| select { |
| case <-done: |
| t.Log("event channel closed") |
| case <-time.After(2 * time.Second): |
| t.Fatal("event stream was not closed after 2 seconds") |
| } |
| } |
| |
| func TestFsnotifyRename(t *testing.T) { |
| // Create an fsnotify watcher instance and initialize it |
| watcher, err := NewWatcher() |
| if err != nil { |
| t.Fatalf("NewWatcher() failed: %s", err) |
| } |
| |
| const testDir string = "_test" |
| |
| // Create directory to watch |
| if err := os.Mkdir(testDir, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDir) |
| |
| // Add a watch for testDir |
| err = watcher.Watch(testDir) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| |
| // Receive errors on the error channel on a separate goroutine |
| go func() { |
| for err := range watcher.Error { |
| t.Fatalf("error received: %s", err) |
| } |
| }() |
| |
| const testFile string = "_test/TestFsnotifyEvents.testfile" |
| const testFileRenamed string = "_test/TestFsnotifyEvents.testfileRenamed" |
| |
| // Receive events on the event channel on a separate goroutine |
| eventstream := watcher.Event |
| var renameReceived counter |
| done := make(chan bool) |
| go func() { |
| for event := range eventstream { |
| // Only count relevant events |
| if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) { |
| if event.IsRename() { |
| renameReceived.increment() |
| } |
| t.Logf("event received: %s", event) |
| } else { |
| t.Logf("unexpected event received: %s", event) |
| } |
| } |
| done <- true |
| }() |
| |
| // Create a file |
| // This should add at least one event to the fsnotify event queue |
| var f *os.File |
| f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| |
| f.WriteString("data") |
| f.Sync() |
| f.Close() |
| |
| // Add a watch for testFile |
| err = watcher.Watch(testFile) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| |
| err = os.Rename(testFile, testFileRenamed) |
| if err != nil { |
| t.Fatalf("rename failed: %s", err) |
| } |
| |
| // We expect this event to be received almost immediately, but let's wait 500 ms to be sure |
| time.Sleep(500 * time.Millisecond) |
| if renameReceived.value() == 0 { |
| t.Fatal("fsnotify rename events have not been received after 500 ms") |
| } |
| |
| // Try closing the fsnotify instance |
| t.Log("calling Close()") |
| watcher.Close() |
| t.Log("waiting for the event channel to become closed...") |
| select { |
| case <-done: |
| t.Log("event channel closed") |
| case <-time.After(2 * time.Second): |
| t.Fatal("event stream was not closed after 2 seconds") |
| } |
| |
| os.Remove(testFileRenamed) |
| } |
| |
| func TestFsnotifyRenameToCreate(t *testing.T) { |
| // Create an fsnotify watcher instance and initialize it |
| watcher, err := NewWatcher() |
| if err != nil { |
| t.Fatalf("NewWatcher() failed: %s", err) |
| } |
| |
| const testDir string = "_test" |
| const testDirFrom string = "_testfrom" |
| |
| // Create directory to watch |
| if err := os.Mkdir(testDir, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDir) |
| |
| // Create directory to get file |
| if err := os.Mkdir(testDirFrom, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDirFrom) |
| |
| // Add a watch for testDir |
| err = watcher.Watch(testDir) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| |
| // Receive errors on the error channel on a separate goroutine |
| go func() { |
| for err := range watcher.Error { |
| t.Fatalf("error received: %s", err) |
| } |
| }() |
| |
| const testFile string = "_testfrom/TestFsnotifyEvents.testfile" |
| const testFileRenamed string = "_test/TestFsnotifyEvents.testfileRenamed" |
| |
| // Receive events on the event channel on a separate goroutine |
| eventstream := watcher.Event |
| var createReceived counter |
| done := make(chan bool) |
| go func() { |
| for event := range eventstream { |
| // Only count relevant events |
| if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) { |
| if event.IsCreate() { |
| createReceived.increment() |
| } |
| t.Logf("event received: %s", event) |
| } else { |
| t.Logf("unexpected event received: %s", event) |
| } |
| } |
| done <- true |
| }() |
| |
| // Create a file |
| // This should add at least one event to the fsnotify event queue |
| var f *os.File |
| f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| f.Close() |
| |
| err = os.Rename(testFile, testFileRenamed) |
| if err != nil { |
| t.Fatalf("rename failed: %s", err) |
| } |
| |
| // We expect this event to be received almost immediately, but let's wait 500 ms to be sure |
| time.Sleep(500 * time.Millisecond) |
| if createReceived.value() == 0 { |
| t.Fatal("fsnotify create events have not been received after 500 ms") |
| } |
| |
| // Try closing the fsnotify instance |
| t.Log("calling Close()") |
| watcher.Close() |
| t.Log("waiting for the event channel to become closed...") |
| select { |
| case <-done: |
| t.Log("event channel closed") |
| case <-time.After(2 * time.Second): |
| t.Fatal("event stream was not closed after 2 seconds") |
| } |
| |
| os.Remove(testFileRenamed) |
| } |
| |
| func TestFsnotifyRenameToOverwrite(t *testing.T) { |
| switch runtime.GOOS { |
| case "plan9", "windows": |
| t.Skipf("skipping test on %q (os.Rename over existing file does not create event).", runtime.GOOS) |
| } |
| // Create an fsnotify watcher instance and initialize it |
| watcher, err := NewWatcher() |
| if err != nil { |
| t.Fatalf("NewWatcher() failed: %s", err) |
| } |
| |
| const testDir string = "_test" |
| const testDirFrom string = "_testfrom" |
| |
| const testFile string = "_testfrom/TestFsnotifyEvents.testfile" |
| const testFileRenamed string = "_test/TestFsnotifyEvents.testfileRenamed" |
| |
| // Create directory to watch |
| if err := os.Mkdir(testDir, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDir) |
| |
| // Create directory to get file |
| if err := os.Mkdir(testDirFrom, 0777); err != nil { |
| t.Fatalf("Failed to create test directory: %s", err) |
| } |
| defer os.RemoveAll(testDirFrom) |
| |
| // Create a file |
| var fr *os.File |
| fr, err = os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| fr.Sync() |
| fr.Close() |
| |
| // Add a watch for testDir |
| err = watcher.Watch(testDir) |
| if err != nil { |
| t.Fatalf("Watcher.Watch() failed: %s", err) |
| } |
| |
| // Receive errors on the error channel on a separate goroutine |
| go func() { |
| for err := range watcher.Error { |
| t.Fatalf("error received: %s", err) |
| } |
| }() |
| |
| // Receive events on the event channel on a separate goroutine |
| eventstream := watcher.Event |
| var eventReceived counter |
| done := make(chan bool) |
| go func() { |
| for event := range eventstream { |
| // Only count relevant events |
| if event.Name == filepath.Clean(testFileRenamed) { |
| eventReceived.increment() |
| t.Logf("event received: %s", event) |
| } else { |
| t.Logf("unexpected event received: %s", event) |
| } |
| } |
| done <- true |
| }() |
| |
| // Create a file |
| // This should add at least one event to the fsnotify event queue |
| var f *os.File |
| f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) |
| if err != nil { |
| t.Fatalf("creating test file failed: %s", err) |
| } |
| f.Sync() |
| f.Close() |
| |
| err = os.Rename(testFile, testFileRenamed) |
| if err != nil { |
| t.Fatalf("rename failed: %s", err) |
| } |
| |
| // We expect this event to be received almost immediately, but let's wait 500 ms to be sure |
| time.Sleep(500 * time.Millisecond) |
| if eventReceived.value() == 0 { |
| t.Fatal("fsnotify events have not been received after 500 ms") |
| } |
| |
| // Try closing the fsnotify instance |
| t.Log("calling Close()") |
| watcher.Close() |
| t.Log("waiting for the event channel to become closed...") |
| select { |
| case <-done: |
| t.Log("event channel closed") |
| case <-time.After(2 * time.Second): |
| t.Fatal("event stream was not closed after 2 seconds") |
| } |
| |
| os.Remove(testFileRenamed) |
| } |
| |
| func TestFsnotifyClose(t *testing.T) { |
| watcher, _ := NewWatcher() |
| watcher.Close() |
| |
| var done int32 |
| go func() { |
| watcher.Close() |
| atomic.StoreInt32(&done, 1) |
| }() |
| |
| time.Sleep(50e6) // 50 ms |
| if atomic.LoadInt32(&done) == 0 { |
| t.Fatal("double Close() test failed: second Close() call didn't return") |
| } |
| |
| err := watcher.Watch("_test") |
| if err == nil { |
| t.Fatal("expected error on Watch() after Close(), got nil") |
| } |
| } |