github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/fsnotify/fsnotify_test.go (about)

     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/filepath"
    14  	"runtime"
    15  	"sync/atomic"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  // An atomic counter
    21  type counter struct {
    22  	val int32
    23  }
    24  
    25  func (c *counter) increment() {
    26  	atomic.AddInt32(&c.val, 1)
    27  }
    28  
    29  func (c *counter) value() int32 {
    30  	return atomic.LoadInt32(&c.val)
    31  }
    32  
    33  func (c *counter) reset() {
    34  	atomic.StoreInt32(&c.val, 0)
    35  }
    36  
    37  // tempMkdir makes a temporary directory
    38  func tempMkdir(t *testing.T) string {
    39  	dir, err := ioutil.TempDir("", "fsnotify")
    40  	if err != nil {
    41  		t.Fatalf("failed to create test directory: %s", err)
    42  	}
    43  	return dir
    44  }
    45  
    46  // newWatcher initializes an fsnotify Watcher instance.
    47  func newWatcher(t *testing.T) *Watcher {
    48  	watcher, err := NewWatcher()
    49  	if err != nil {
    50  		t.Fatalf("NewWatcher() failed: %s", err)
    51  	}
    52  	return watcher
    53  }
    54  
    55  // addWatch adds a watch for a directory
    56  func addWatch(t *testing.T, watcher *Watcher, dir string) {
    57  	if err := watcher.Watch(dir); err != nil {
    58  		t.Fatalf("watcher.Watch(%q) failed: %s", dir, err)
    59  	}
    60  }
    61  
    62  func TestFsnotifyMultipleOperations(t *testing.T) {
    63  	watcher := newWatcher(t)
    64  
    65  	// Receive errors on the error channel on a separate goroutine
    66  	go func() {
    67  		for err := range watcher.Error {
    68  			t.Fatalf("error received: %s", err)
    69  		}
    70  	}()
    71  
    72  	// Create directory to watch
    73  	testDir := tempMkdir(t)
    74  	defer os.RemoveAll(testDir)
    75  
    76  	// Create directory that's not watched
    77  	testDirToMoveFiles := tempMkdir(t)
    78  	defer os.RemoveAll(testDirToMoveFiles)
    79  
    80  	testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
    81  	testFileRenamed := filepath.Join(testDirToMoveFiles, "TestFsnotifySeqRename.testfile")
    82  
    83  	addWatch(t, watcher, testDir)
    84  
    85  	// Receive events on the event channel on a separate goroutine
    86  	eventstream := watcher.Event
    87  	var createReceived, modifyReceived, deleteReceived, renameReceived counter
    88  	done := make(chan bool)
    89  	go func() {
    90  		for event := range eventstream {
    91  			// Only count relevant events
    92  			if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
    93  				t.Logf("event received: %s", event)
    94  				if event.IsDelete() {
    95  					deleteReceived.increment()
    96  				}
    97  				if event.IsModify() {
    98  					modifyReceived.increment()
    99  				}
   100  				if event.IsCreate() {
   101  					createReceived.increment()
   102  				}
   103  				if event.IsRename() {
   104  					renameReceived.increment()
   105  				}
   106  			} else {
   107  				t.Logf("unexpected event received: %s", event)
   108  			}
   109  		}
   110  		done <- true
   111  	}()
   112  
   113  	// Create a file
   114  	// This should add at least one event to the fsnotify event queue
   115  	var f *os.File
   116  	f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   117  	if err != nil {
   118  		t.Fatalf("creating test file failed: %s", err)
   119  	}
   120  	f.Sync()
   121  
   122  	time.Sleep(time.Millisecond)
   123  	f.WriteString("data")
   124  	f.Sync()
   125  	f.Close()
   126  
   127  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   128  
   129  	if err := testRename(testFile, testFileRenamed); err != nil {
   130  		t.Fatalf("rename failed: %s", err)
   131  	}
   132  
   133  	// Modify the file outside of the watched dir
   134  	f, err = os.Open(testFileRenamed)
   135  	if err != nil {
   136  		t.Fatalf("open test renamed file failed: %s", err)
   137  	}
   138  	f.WriteString("data")
   139  	f.Sync()
   140  	f.Close()
   141  
   142  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   143  
   144  	// Recreate the file that was moved
   145  	f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   146  	if err != nil {
   147  		t.Fatalf("creating test file failed: %s", err)
   148  	}
   149  	f.Close()
   150  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   151  
   152  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   153  	time.Sleep(500 * time.Millisecond)
   154  	cReceived := createReceived.value()
   155  	if cReceived != 2 {
   156  		t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
   157  	}
   158  	mReceived := modifyReceived.value()
   159  	if mReceived != 1 {
   160  		t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
   161  	}
   162  	dReceived := deleteReceived.value()
   163  	rReceived := renameReceived.value()
   164  	if dReceived+rReceived != 1 {
   165  		t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", rReceived+dReceived, 1)
   166  	}
   167  
   168  	// Try closing the fsnotify instance
   169  	t.Log("calling Close()")
   170  	watcher.Close()
   171  	t.Log("waiting for the event channel to become closed...")
   172  	select {
   173  	case <-done:
   174  		t.Log("event channel closed")
   175  	case <-time.After(2 * time.Second):
   176  		t.Fatal("event stream was not closed after 2 seconds")
   177  	}
   178  }
   179  
   180  func TestFsnotifyMultipleCreates(t *testing.T) {
   181  	watcher := newWatcher(t)
   182  
   183  	// Receive errors on the error channel on a separate goroutine
   184  	go func() {
   185  		for err := range watcher.Error {
   186  			t.Fatalf("error received: %s", err)
   187  		}
   188  	}()
   189  
   190  	// Create directory to watch
   191  	testDir := tempMkdir(t)
   192  	defer os.RemoveAll(testDir)
   193  
   194  	testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
   195  
   196  	addWatch(t, watcher, testDir)
   197  
   198  	// Receive events on the event channel on a separate goroutine
   199  	eventstream := watcher.Event
   200  	var createReceived, modifyReceived, deleteReceived counter
   201  	done := make(chan bool)
   202  	go func() {
   203  		for event := range eventstream {
   204  			// Only count relevant events
   205  			if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
   206  				t.Logf("event received: %s", event)
   207  				if event.IsDelete() {
   208  					deleteReceived.increment()
   209  				}
   210  				if event.IsCreate() {
   211  					createReceived.increment()
   212  				}
   213  				if event.IsModify() {
   214  					modifyReceived.increment()
   215  				}
   216  			} else {
   217  				t.Logf("unexpected event received: %s", event)
   218  			}
   219  		}
   220  		done <- true
   221  	}()
   222  
   223  	// Create a file
   224  	// This should add at least one event to the fsnotify event queue
   225  	var f *os.File
   226  	f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   227  	if err != nil {
   228  		t.Fatalf("creating test file failed: %s", err)
   229  	}
   230  	f.Sync()
   231  
   232  	time.Sleep(time.Millisecond)
   233  	f.WriteString("data")
   234  	f.Sync()
   235  	f.Close()
   236  
   237  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   238  
   239  	os.Remove(testFile)
   240  
   241  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   242  
   243  	// Recreate the file
   244  	f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   245  	if err != nil {
   246  		t.Fatalf("creating test file failed: %s", err)
   247  	}
   248  	f.Close()
   249  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   250  
   251  	// Modify
   252  	f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
   253  	if err != nil {
   254  		t.Fatalf("creating test file failed: %s", err)
   255  	}
   256  	f.Sync()
   257  
   258  	time.Sleep(time.Millisecond)
   259  	f.WriteString("data")
   260  	f.Sync()
   261  	f.Close()
   262  
   263  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   264  
   265  	// Modify
   266  	f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
   267  	if err != nil {
   268  		t.Fatalf("creating test file failed: %s", err)
   269  	}
   270  	f.Sync()
   271  
   272  	time.Sleep(time.Millisecond)
   273  	f.WriteString("data")
   274  	f.Sync()
   275  	f.Close()
   276  
   277  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   278  
   279  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   280  	time.Sleep(500 * time.Millisecond)
   281  	cReceived := createReceived.value()
   282  	if cReceived != 2 {
   283  		t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
   284  	}
   285  	mReceived := modifyReceived.value()
   286  	if mReceived < 3 {
   287  		t.Fatalf("incorrect number of modify events received after 500 ms (%d vs atleast %d)", mReceived, 3)
   288  	}
   289  	dReceived := deleteReceived.value()
   290  	if dReceived != 1 {
   291  		t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", dReceived, 1)
   292  	}
   293  
   294  	// Try closing the fsnotify instance
   295  	t.Log("calling Close()")
   296  	watcher.Close()
   297  	t.Log("waiting for the event channel to become closed...")
   298  	select {
   299  	case <-done:
   300  		t.Log("event channel closed")
   301  	case <-time.After(2 * time.Second):
   302  		t.Fatal("event stream was not closed after 2 seconds")
   303  	}
   304  }
   305  
   306  func TestFsnotifyDirOnly(t *testing.T) {
   307  	watcher := newWatcher(t)
   308  
   309  	// Create directory to watch
   310  	testDir := tempMkdir(t)
   311  	defer os.RemoveAll(testDir)
   312  
   313  	// Create a file before watching directory
   314  	// This should NOT add any events to the fsnotify event queue
   315  	testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
   316  	{
   317  		var f *os.File
   318  		f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
   319  		if err != nil {
   320  			t.Fatalf("creating test file failed: %s", err)
   321  		}
   322  		f.Sync()
   323  		f.Close()
   324  	}
   325  
   326  	addWatch(t, watcher, testDir)
   327  
   328  	// Receive errors on the error channel on a separate goroutine
   329  	go func() {
   330  		for err := range watcher.Error {
   331  			t.Fatalf("error received: %s", err)
   332  		}
   333  	}()
   334  
   335  	testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
   336  
   337  	// Receive events on the event channel on a separate goroutine
   338  	eventstream := watcher.Event
   339  	var createReceived, modifyReceived, deleteReceived counter
   340  	done := make(chan bool)
   341  	go func() {
   342  		for event := range eventstream {
   343  			// Only count relevant events
   344  			if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileAlreadyExists) {
   345  				t.Logf("event received: %s", event)
   346  				if event.IsDelete() {
   347  					deleteReceived.increment()
   348  				}
   349  				if event.IsModify() {
   350  					modifyReceived.increment()
   351  				}
   352  				if event.IsCreate() {
   353  					createReceived.increment()
   354  				}
   355  			} else {
   356  				t.Logf("unexpected event received: %s", event)
   357  			}
   358  		}
   359  		done <- true
   360  	}()
   361  
   362  	// Create a file
   363  	// This should add at least one event to the fsnotify event queue
   364  	var f *os.File
   365  	f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   366  	if err != nil {
   367  		t.Fatalf("creating test file failed: %s", err)
   368  	}
   369  	f.Sync()
   370  
   371  	time.Sleep(time.Millisecond)
   372  	f.WriteString("data")
   373  	f.Sync()
   374  	f.Close()
   375  
   376  	time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
   377  
   378  	os.Remove(testFile)
   379  	os.Remove(testFileAlreadyExists)
   380  
   381  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   382  	time.Sleep(500 * time.Millisecond)
   383  	cReceived := createReceived.value()
   384  	if cReceived != 1 {
   385  		t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 1)
   386  	}
   387  	mReceived := modifyReceived.value()
   388  	if mReceived != 1 {
   389  		t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
   390  	}
   391  	dReceived := deleteReceived.value()
   392  	if dReceived != 2 {
   393  		t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
   394  	}
   395  
   396  	// Try closing the fsnotify instance
   397  	t.Log("calling Close()")
   398  	watcher.Close()
   399  	t.Log("waiting for the event channel to become closed...")
   400  	select {
   401  	case <-done:
   402  		t.Log("event channel closed")
   403  	case <-time.After(2 * time.Second):
   404  		t.Fatal("event stream was not closed after 2 seconds")
   405  	}
   406  }
   407  
   408  func TestFsnotifyDeleteWatchedDir(t *testing.T) {
   409  	watcher := newWatcher(t)
   410  	defer watcher.Close()
   411  
   412  	// Create directory to watch
   413  	testDir := tempMkdir(t)
   414  	defer os.RemoveAll(testDir)
   415  
   416  	// Create a file before watching directory
   417  	testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
   418  	{
   419  		var f *os.File
   420  		f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
   421  		if err != nil {
   422  			t.Fatalf("creating test file failed: %s", err)
   423  		}
   424  		f.Sync()
   425  		f.Close()
   426  	}
   427  
   428  	addWatch(t, watcher, testDir)
   429  
   430  	// Add a watch for testFile
   431  	addWatch(t, watcher, testFileAlreadyExists)
   432  
   433  	// Receive errors on the error channel on a separate goroutine
   434  	go func() {
   435  		for err := range watcher.Error {
   436  			t.Fatalf("error received: %s", err)
   437  		}
   438  	}()
   439  
   440  	// Receive events on the event channel on a separate goroutine
   441  	eventstream := watcher.Event
   442  	var deleteReceived counter
   443  	go func() {
   444  		for event := range eventstream {
   445  			// Only count relevant events
   446  			if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFileAlreadyExists) {
   447  				t.Logf("event received: %s", event)
   448  				if event.IsDelete() {
   449  					deleteReceived.increment()
   450  				}
   451  			} else {
   452  				t.Logf("unexpected event received: %s", event)
   453  			}
   454  		}
   455  	}()
   456  
   457  	os.RemoveAll(testDir)
   458  
   459  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   460  	time.Sleep(500 * time.Millisecond)
   461  	dReceived := deleteReceived.value()
   462  	if dReceived < 2 {
   463  		t.Fatalf("did not receive at least %d delete events, received %d after 500 ms", 2, dReceived)
   464  	}
   465  }
   466  
   467  func TestFsnotifySubDir(t *testing.T) {
   468  	watcher := newWatcher(t)
   469  
   470  	// Create directory to watch
   471  	testDir := tempMkdir(t)
   472  	defer os.RemoveAll(testDir)
   473  
   474  	testFile1 := filepath.Join(testDir, "TestFsnotifyFile1.testfile")
   475  	testSubDir := filepath.Join(testDir, "sub")
   476  	testSubDirFile := filepath.Join(testDir, "sub/TestFsnotifyFile1.testfile")
   477  
   478  	// Receive errors on the error channel on a separate goroutine
   479  	go func() {
   480  		for err := range watcher.Error {
   481  			t.Fatalf("error received: %s", err)
   482  		}
   483  	}()
   484  
   485  	// Receive events on the event channel on a separate goroutine
   486  	eventstream := watcher.Event
   487  	var createReceived, deleteReceived counter
   488  	done := make(chan bool)
   489  	go func() {
   490  		for event := range eventstream {
   491  			// Only count relevant events
   492  			if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testSubDir) || event.Name == filepath.Clean(testFile1) {
   493  				t.Logf("event received: %s", event)
   494  				if event.IsCreate() {
   495  					createReceived.increment()
   496  				}
   497  				if event.IsDelete() {
   498  					deleteReceived.increment()
   499  				}
   500  			} else {
   501  				t.Logf("unexpected event received: %s", event)
   502  			}
   503  		}
   504  		done <- true
   505  	}()
   506  
   507  	addWatch(t, watcher, testDir)
   508  
   509  	// Create sub-directory
   510  	if err := os.Mkdir(testSubDir, 0777); err != nil {
   511  		t.Fatalf("failed to create test sub-directory: %s", err)
   512  	}
   513  
   514  	// Create a file
   515  	var f *os.File
   516  	f, err := os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
   517  	if err != nil {
   518  		t.Fatalf("creating test file failed: %s", err)
   519  	}
   520  	f.Sync()
   521  	f.Close()
   522  
   523  	// Create a file (Should not see this! we are not watching subdir)
   524  	var fs *os.File
   525  	fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
   526  	if err != nil {
   527  		t.Fatalf("creating test file failed: %s", err)
   528  	}
   529  	fs.Sync()
   530  	fs.Close()
   531  
   532  	time.Sleep(200 * time.Millisecond)
   533  
   534  	// Make sure receive deletes for both file and sub-directory
   535  	os.RemoveAll(testSubDir)
   536  	os.Remove(testFile1)
   537  
   538  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   539  	time.Sleep(500 * time.Millisecond)
   540  	cReceived := createReceived.value()
   541  	if cReceived != 2 {
   542  		t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
   543  	}
   544  	dReceived := deleteReceived.value()
   545  	if dReceived != 2 {
   546  		t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
   547  	}
   548  
   549  	// Try closing the fsnotify instance
   550  	t.Log("calling Close()")
   551  	watcher.Close()
   552  	t.Log("waiting for the event channel to become closed...")
   553  	select {
   554  	case <-done:
   555  		t.Log("event channel closed")
   556  	case <-time.After(2 * time.Second):
   557  		t.Fatal("event stream was not closed after 2 seconds")
   558  	}
   559  }
   560  
   561  func TestFsnotifyRename(t *testing.T) {
   562  	watcher := newWatcher(t)
   563  
   564  	// Create directory to watch
   565  	testDir := tempMkdir(t)
   566  	defer os.RemoveAll(testDir)
   567  
   568  	addWatch(t, watcher, testDir)
   569  
   570  	// Receive errors on the error channel on a separate goroutine
   571  	go func() {
   572  		for err := range watcher.Error {
   573  			t.Fatalf("error received: %s", err)
   574  		}
   575  	}()
   576  
   577  	testFile := filepath.Join(testDir, "TestFsnotifyEvents.testfile")
   578  	testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
   579  
   580  	// Receive events on the event channel on a separate goroutine
   581  	eventstream := watcher.Event
   582  	var renameReceived counter
   583  	done := make(chan bool)
   584  	go func() {
   585  		for event := range eventstream {
   586  			// Only count relevant events
   587  			if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
   588  				if event.IsRename() {
   589  					renameReceived.increment()
   590  				}
   591  				t.Logf("event received: %s", event)
   592  			} else {
   593  				t.Logf("unexpected event received: %s", event)
   594  			}
   595  		}
   596  		done <- true
   597  	}()
   598  
   599  	// Create a file
   600  	// This should add at least one event to the fsnotify event queue
   601  	var f *os.File
   602  	f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   603  	if err != nil {
   604  		t.Fatalf("creating test file failed: %s", err)
   605  	}
   606  	f.Sync()
   607  
   608  	f.WriteString("data")
   609  	f.Sync()
   610  	f.Close()
   611  
   612  	// Add a watch for testFile
   613  	addWatch(t, watcher, testFile)
   614  
   615  	if err := testRename(testFile, testFileRenamed); err != nil {
   616  		t.Fatalf("rename failed: %s", err)
   617  	}
   618  
   619  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   620  	time.Sleep(500 * time.Millisecond)
   621  	if renameReceived.value() == 0 {
   622  		t.Fatal("fsnotify rename events have not been received after 500 ms")
   623  	}
   624  
   625  	// Try closing the fsnotify instance
   626  	t.Log("calling Close()")
   627  	watcher.Close()
   628  	t.Log("waiting for the event channel to become closed...")
   629  	select {
   630  	case <-done:
   631  		t.Log("event channel closed")
   632  	case <-time.After(2 * time.Second):
   633  		t.Fatal("event stream was not closed after 2 seconds")
   634  	}
   635  
   636  	os.Remove(testFileRenamed)
   637  }
   638  
   639  func TestFsnotifyRenameToCreate(t *testing.T) {
   640  	watcher := newWatcher(t)
   641  
   642  	// Create directory to watch
   643  	testDir := tempMkdir(t)
   644  	defer os.RemoveAll(testDir)
   645  
   646  	// Create directory to get file
   647  	testDirFrom := tempMkdir(t)
   648  	defer os.RemoveAll(testDirFrom)
   649  
   650  	addWatch(t, watcher, testDir)
   651  
   652  	// Receive errors on the error channel on a separate goroutine
   653  	go func() {
   654  		for err := range watcher.Error {
   655  			t.Fatalf("error received: %s", err)
   656  		}
   657  	}()
   658  
   659  	testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
   660  	testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
   661  
   662  	// Receive events on the event channel on a separate goroutine
   663  	eventstream := watcher.Event
   664  	var createReceived counter
   665  	done := make(chan bool)
   666  	go func() {
   667  		for event := range eventstream {
   668  			// Only count relevant events
   669  			if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
   670  				if event.IsCreate() {
   671  					createReceived.increment()
   672  				}
   673  				t.Logf("event received: %s", event)
   674  			} else {
   675  				t.Logf("unexpected event received: %s", event)
   676  			}
   677  		}
   678  		done <- true
   679  	}()
   680  
   681  	// Create a file
   682  	// This should add at least one event to the fsnotify event queue
   683  	var f *os.File
   684  	f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   685  	if err != nil {
   686  		t.Fatalf("creating test file failed: %s", err)
   687  	}
   688  	f.Sync()
   689  	f.Close()
   690  
   691  	if err := testRename(testFile, testFileRenamed); err != nil {
   692  		t.Fatalf("rename failed: %s", err)
   693  	}
   694  
   695  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   696  	time.Sleep(500 * time.Millisecond)
   697  	if createReceived.value() == 0 {
   698  		t.Fatal("fsnotify create events have not been received after 500 ms")
   699  	}
   700  
   701  	// Try closing the fsnotify instance
   702  	t.Log("calling Close()")
   703  	watcher.Close()
   704  	t.Log("waiting for the event channel to become closed...")
   705  	select {
   706  	case <-done:
   707  		t.Log("event channel closed")
   708  	case <-time.After(2 * time.Second):
   709  		t.Fatal("event stream was not closed after 2 seconds")
   710  	}
   711  
   712  	os.Remove(testFileRenamed)
   713  }
   714  
   715  func TestFsnotifyRenameToOverwrite(t *testing.T) {
   716  	switch runtime.GOOS {
   717  	case "plan9", "windows":
   718  		t.Skipf("skipping test on %q (os.Rename over existing file does not create event).", runtime.GOOS)
   719  	}
   720  
   721  	watcher := newWatcher(t)
   722  
   723  	// Create directory to watch
   724  	testDir := tempMkdir(t)
   725  	defer os.RemoveAll(testDir)
   726  
   727  	// Create directory to get file
   728  	testDirFrom := tempMkdir(t)
   729  	defer os.RemoveAll(testDirFrom)
   730  
   731  	testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
   732  	testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
   733  
   734  	// Create a file
   735  	var fr *os.File
   736  	fr, err := os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666)
   737  	if err != nil {
   738  		t.Fatalf("creating test file failed: %s", err)
   739  	}
   740  	fr.Sync()
   741  	fr.Close()
   742  
   743  	addWatch(t, watcher, testDir)
   744  
   745  	// Receive errors on the error channel on a separate goroutine
   746  	go func() {
   747  		for err := range watcher.Error {
   748  			t.Fatalf("error received: %s", err)
   749  		}
   750  	}()
   751  
   752  	// Receive events on the event channel on a separate goroutine
   753  	eventstream := watcher.Event
   754  	var eventReceived counter
   755  	done := make(chan bool)
   756  	go func() {
   757  		for event := range eventstream {
   758  			// Only count relevant events
   759  			if event.Name == filepath.Clean(testFileRenamed) {
   760  				eventReceived.increment()
   761  				t.Logf("event received: %s", event)
   762  			} else {
   763  				t.Logf("unexpected event received: %s", event)
   764  			}
   765  		}
   766  		done <- true
   767  	}()
   768  
   769  	// Create a file
   770  	// This should add at least one event to the fsnotify event queue
   771  	var f *os.File
   772  	f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   773  	if err != nil {
   774  		t.Fatalf("creating test file failed: %s", err)
   775  	}
   776  	f.Sync()
   777  	f.Close()
   778  
   779  	if err := testRename(testFile, testFileRenamed); err != nil {
   780  		t.Fatalf("rename failed: %s", err)
   781  	}
   782  
   783  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   784  	time.Sleep(500 * time.Millisecond)
   785  	if eventReceived.value() == 0 {
   786  		t.Fatal("fsnotify events have not been received after 500 ms")
   787  	}
   788  
   789  	// Try closing the fsnotify instance
   790  	t.Log("calling Close()")
   791  	watcher.Close()
   792  	t.Log("waiting for the event channel to become closed...")
   793  	select {
   794  	case <-done:
   795  		t.Log("event channel closed")
   796  	case <-time.After(2 * time.Second):
   797  		t.Fatal("event stream was not closed after 2 seconds")
   798  	}
   799  
   800  	os.Remove(testFileRenamed)
   801  }
   802  
   803  func TestRemovalOfWatch(t *testing.T) {
   804  	// Create directory to watch
   805  	testDir := tempMkdir(t)
   806  	defer os.RemoveAll(testDir)
   807  
   808  	// Create a file before watching directory
   809  	testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
   810  	{
   811  		var f *os.File
   812  		f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
   813  		if err != nil {
   814  			t.Fatalf("creating test file failed: %s", err)
   815  		}
   816  		f.Sync()
   817  		f.Close()
   818  	}
   819  
   820  	watcher := newWatcher(t)
   821  	defer watcher.Close()
   822  
   823  	addWatch(t, watcher, testDir)
   824  	if err := watcher.RemoveWatch(testDir); err != nil {
   825  		t.Fatalf("Could not remove the watch: %v\n", err)
   826  	}
   827  
   828  	go func() {
   829  		select {
   830  		case ev := <-watcher.Event:
   831  			t.Fatalf("We received event: %v\n", ev)
   832  		case <-time.After(500 * time.Millisecond):
   833  			t.Log("No event received, as expected.")
   834  		}
   835  	}()
   836  
   837  	time.Sleep(200 * time.Millisecond)
   838  	// Modify the file outside of the watched dir
   839  	f, err := os.Open(testFileAlreadyExists)
   840  	if err != nil {
   841  		t.Fatalf("Open test file failed: %s", err)
   842  	}
   843  	f.WriteString("data")
   844  	f.Sync()
   845  	f.Close()
   846  	if err := os.Chmod(testFileAlreadyExists, 0700); err != nil {
   847  		t.Fatalf("chmod failed: %s", err)
   848  	}
   849  	time.Sleep(400 * time.Millisecond)
   850  }
   851  
   852  func TestFsnotifyAttrib(t *testing.T) {
   853  	if runtime.GOOS == "windows" {
   854  		t.Skip("attributes don't work on Windows.")
   855  	}
   856  
   857  	watcher := newWatcher(t)
   858  
   859  	// Create directory to watch
   860  	testDir := tempMkdir(t)
   861  	defer os.RemoveAll(testDir)
   862  
   863  	// Receive errors on the error channel on a separate goroutine
   864  	go func() {
   865  		for err := range watcher.Error {
   866  			t.Fatalf("error received: %s", err)
   867  		}
   868  	}()
   869  
   870  	testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
   871  
   872  	// Receive events on the event channel on a separate goroutine
   873  	eventstream := watcher.Event
   874  	// The modifyReceived counter counts IsModify events that are not IsAttrib,
   875  	// and the attribReceived counts IsAttrib events (which are also IsModify as
   876  	// a consequence).
   877  	var modifyReceived counter
   878  	var attribReceived counter
   879  	done := make(chan bool)
   880  	go func() {
   881  		for event := range eventstream {
   882  			// Only count relevant events
   883  			if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
   884  				if event.IsModify() {
   885  					modifyReceived.increment()
   886  				}
   887  				if event.IsAttrib() {
   888  					attribReceived.increment()
   889  				}
   890  				t.Logf("event received: %s", event)
   891  			} else {
   892  				t.Logf("unexpected event received: %s", event)
   893  			}
   894  		}
   895  		done <- true
   896  	}()
   897  
   898  	// Create a file
   899  	// This should add at least one event to the fsnotify event queue
   900  	var f *os.File
   901  	f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
   902  	if err != nil {
   903  		t.Fatalf("creating test file failed: %s", err)
   904  	}
   905  	f.Sync()
   906  
   907  	f.WriteString("data")
   908  	f.Sync()
   909  	f.Close()
   910  
   911  	// Add a watch for testFile
   912  	addWatch(t, watcher, testFile)
   913  
   914  	if err := os.Chmod(testFile, 0700); err != nil {
   915  		t.Fatalf("chmod failed: %s", err)
   916  	}
   917  
   918  	// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
   919  	// Creating/writing a file changes also the mtime, so IsAttrib should be set to true here
   920  	time.Sleep(500 * time.Millisecond)
   921  	if modifyReceived.value() == 0 {
   922  		t.Fatal("fsnotify modify events have not received after 500 ms")
   923  	}
   924  	if attribReceived.value() == 0 {
   925  		t.Fatal("fsnotify attribute events have not received after 500 ms")
   926  	}
   927  
   928  	// Modifying the contents of the file does not set the attrib flag (although eg. the mtime
   929  	// might have been modified).
   930  	modifyReceived.reset()
   931  	attribReceived.reset()
   932  
   933  	f, err = os.OpenFile(testFile, os.O_WRONLY, 0)
   934  	if err != nil {
   935  		t.Fatalf("reopening test file failed: %s", err)
   936  	}
   937  
   938  	f.WriteString("more data")
   939  	f.Sync()
   940  	f.Close()
   941  
   942  	time.Sleep(500 * time.Millisecond)
   943  
   944  	if modifyReceived.value() != 1 {
   945  		t.Fatal("didn't receive a modify event after changing test file contents")
   946  	}
   947  
   948  	if attribReceived.value() != 0 {
   949  		t.Fatal("did receive an unexpected attrib event after changing test file contents")
   950  	}
   951  
   952  	modifyReceived.reset()
   953  	attribReceived.reset()
   954  
   955  	// Doing a chmod on the file should trigger an event with the "attrib" flag set (the contents
   956  	// of the file are not changed though)
   957  	if err := os.Chmod(testFile, 0600); err != nil {
   958  		t.Fatalf("chmod failed: %s", err)
   959  	}
   960  
   961  	time.Sleep(500 * time.Millisecond)
   962  
   963  	if attribReceived.value() != 1 {
   964  		t.Fatal("didn't receive an attribute change after 500ms")
   965  	}
   966  
   967  	// Try closing the fsnotify instance
   968  	t.Log("calling Close()")
   969  	watcher.Close()
   970  	t.Log("waiting for the event channel to become closed...")
   971  	select {
   972  	case <-done:
   973  		t.Log("event channel closed")
   974  	case <-time.After(1e9):
   975  		t.Fatal("event stream was not closed after 1 second")
   976  	}
   977  
   978  	os.Remove(testFile)
   979  }
   980  
   981  func TestFsnotifyClose(t *testing.T) {
   982  	watcher := newWatcher(t)
   983  	watcher.Close()
   984  
   985  	var done int32
   986  	go func() {
   987  		watcher.Close()
   988  		atomic.StoreInt32(&done, 1)
   989  	}()
   990  
   991  	time.Sleep(50e6) // 50 ms
   992  	if atomic.LoadInt32(&done) == 0 {
   993  		t.Fatal("double Close() test failed: second Close() call didn't return")
   994  	}
   995  
   996  	testDir := tempMkdir(t)
   997  	defer os.RemoveAll(testDir)
   998  
   999  	if err := watcher.Watch(testDir); err == nil {
  1000  		t.Fatal("expected error on Watch() after Close(), got nil")
  1001  	}
  1002  }
  1003  
  1004  func testRename(file1, file2 string) error {
  1005  	switch runtime.GOOS {
  1006  	case "windows", "plan9":
  1007  		return os.Rename(file1, file2)
  1008  	default:
  1009  		cmd := exec.Command("mv", file1, file2)
  1010  		return cmd.Run()
  1011  	}
  1012  }