github.com/DiversionCompany/notify@v0.9.9/notify_test.go (about)

     1  // Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
     2  // Use of this source code is governed by the MIT license that can be
     3  // found in the LICENSE file.
     4  
     5  //go:build darwin || linux || freebsd || dragonfly || netbsd || openbsd || windows || solaris
     6  // +build darwin linux freebsd dragonfly netbsd openbsd windows solaris
     7  
     8  package notify
     9  
    10  import (
    11  	"errors"
    12  	"os"
    13  	"path/filepath"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  func TestNotifyExample(t *testing.T) {
    19  	n := NewNotifyTest(t, "testdata/vfs.txt")
    20  
    21  	ch := NewChans(3)
    22  
    23  	// Watch-points can be set explicitly via Watch/Stop calls...
    24  	n.Watch("src/github.com/rjeczalik/fs", ch[0], Write)
    25  	n.Watch("src/github.com/pblaszczyk/qttu", ch[0], Write)
    26  	n.Watch("src/github.com/pblaszczyk/qttu/...", ch[1], Create)
    27  	n.Watch("src/github.com/rjeczalik/fs/cmd/...", ch[2], Remove)
    28  
    29  	cases := []NCase{
    30  		// i=0
    31  		{
    32  			Event:    write(n.W(), "src/github.com/rjeczalik/fs/fs.go", []byte("XD")),
    33  			Receiver: Chans{ch[0]},
    34  		},
    35  		// TODO(rjeczalik): #62
    36  		// i=1
    37  		// {
    38  		//	Event:    write(n.W(), "src/github.com/pblaszczyk/qttu/README.md", []byte("XD")),
    39  		//	Receiver: Chans{ch[0]},
    40  		// },
    41  		// i=2
    42  		{
    43  			Event:    write(n.W(), "src/github.com/rjeczalik/fs/cmd/gotree/go.go", []byte("XD")),
    44  			Receiver: nil,
    45  		},
    46  		// i=3
    47  		{
    48  			Event:    create(n.W(), "src/github.com/pblaszczyk/qttu/src/.main.cc.swp"),
    49  			Receiver: Chans{ch[1]},
    50  		},
    51  		// i=4
    52  		{
    53  			Event:    create(n.W(), "src/github.com/pblaszczyk/qttu/src/.main.cc.swo"),
    54  			Receiver: Chans{ch[1]},
    55  		},
    56  		// i=5
    57  		{
    58  			Event:    remove(n.W(), "src/github.com/rjeczalik/fs/cmd/gotree/go.go"),
    59  			Receiver: Chans{ch[2]},
    60  		},
    61  	}
    62  
    63  	n.ExpectNotifyEvents(cases, ch)
    64  
    65  	// ...or using Call structures.
    66  	stops := [...]Call{
    67  		// i=0
    68  		{
    69  			F: FuncStop,
    70  			C: ch[0],
    71  		},
    72  		// i=1
    73  		{
    74  			F: FuncStop,
    75  			C: ch[1],
    76  		},
    77  	}
    78  
    79  	n.Call(stops[:]...)
    80  
    81  	cases = []NCase{
    82  		// i=0
    83  		{
    84  			Event:    write(n.W(), "src/github.com/rjeczalik/fs/fs.go", []byte("XD")),
    85  			Receiver: nil,
    86  		},
    87  		// i=1
    88  		{
    89  			Event:    write(n.W(), "src/github.com/pblaszczyk/qttu/README.md", []byte("XD")),
    90  			Receiver: nil,
    91  		},
    92  		// i=2
    93  		{
    94  			Event:    create(n.W(), "src/github.com/pblaszczyk/qttu/src/.main.cc.swr"),
    95  			Receiver: nil,
    96  		},
    97  		// i=3
    98  		{
    99  			Event:    remove(n.W(), "src/github.com/rjeczalik/fs/cmd/gotree/main.go"),
   100  			Receiver: Chans{ch[2]},
   101  		},
   102  	}
   103  
   104  	n.ExpectNotifyEvents(cases, ch)
   105  }
   106  
   107  func TestStop(t *testing.T) {
   108  	t.Skip("TODO(rjeczalik)")
   109  }
   110  
   111  func TestRenameInRoot(t *testing.T) {
   112  	tmpDir := t.TempDir()
   113  
   114  	c := make(chan EventInfo, 100)
   115  	first := filepath.Join(tmpDir, "foo")
   116  	second := filepath.Join(tmpDir, "bar")
   117  	file := filepath.Join(second, "file")
   118  
   119  	mustT(t, os.Mkdir(first, 0777))
   120  
   121  	if err := Watch(tmpDir+"/...", c, All); err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	defer Stop(c)
   125  
   126  	mustT(t, os.Rename(first, second))
   127  	time.Sleep(50 * time.Millisecond) // Need some time to process rename.
   128  	fd, err := os.Create(file)
   129  	mustT(t, err)
   130  	fd.Close()
   131  
   132  	timeout := time.After(time.Second)
   133  	for {
   134  		select {
   135  		case ev := <-c:
   136  			if samefile(t, ev.Path(), file) {
   137  				return
   138  			}
   139  			t.Log(ev.Path())
   140  		case <-timeout:
   141  			t.Fatal("timed out before receiving event")
   142  		}
   143  	}
   144  }
   145  
   146  func TestRecreated(t *testing.T) {
   147  	tmpDir := t.TempDir()
   148  
   149  	dir := filepath.Join(tmpDir, "folder")
   150  	file := filepath.Join(dir, "file")
   151  
   152  	// Start watching
   153  	eventChan := make(chan EventInfo, 1000)
   154  	mustT(t, Watch(tmpDir+"/...", eventChan, All))
   155  	defer Stop(eventChan)
   156  
   157  	recreateFolder := func() {
   158  		// Give the sync some time to process events
   159  		mustT(t, os.RemoveAll(dir))
   160  		mustT(t, os.Mkdir(dir, 0777))
   161  		time.Sleep(100 * time.Millisecond)
   162  
   163  		// Create a file
   164  		mustT(t, os.WriteFile(file, []byte("abc"), 0666))
   165  	}
   166  	timeout := time.After(5 * time.Second)
   167  	checkCreated := func() {
   168  		for {
   169  			select {
   170  			case ev := <-eventChan:
   171  				t.Log(ev.Path(), ev.Event())
   172  				if samefile(t, ev.Path(), file) && ev.Event() == Create {
   173  					return
   174  				}
   175  			case <-timeout:
   176  				t.Fatal("timed out before receiving event")
   177  			}
   178  		}
   179  	}
   180  
   181  	// 1. Create a folder and a file within it
   182  	// This will create a node in the internal tree for the subfolder test/folder
   183  	// Will create a new inotify watch for the folder
   184  	t.Log("######## First ########")
   185  	recreateFolder()
   186  	checkCreated()
   187  
   188  	// 2. Create a folder and a file within it again
   189  	// This will set the events for the subfolder test/folder in the internal tree
   190  	// Will create a new inotify watch for the folder because events differ
   191  	t.Log("######## Second ########")
   192  	recreateFolder()
   193  	checkCreated()
   194  
   195  	// 3. Create a folder and a file within it yet again
   196  	// This time no new inotify watch will be created, because the events
   197  	// and node already exist in the internal tree and all subsequent events
   198  	// are lost, hence there is no event for the created file here anymore
   199  	t.Log("######## Third ########")
   200  	recreateFolder()
   201  	checkCreated()
   202  }
   203  
   204  func mustT(t testing.TB, err error) {
   205  	t.Helper()
   206  	if err != nil {
   207  		t.Fatal(err)
   208  	}
   209  }
   210  
   211  func samefile(t *testing.T, p1, p2 string) bool {
   212  	// The tests sometimes delete files shortly after creating them.
   213  	// That's expected; ignore stat failures.
   214  	fi1, err := os.Stat(p1)
   215  	if errors.Is(err, os.ErrNotExist) {
   216  		return false
   217  	}
   218  	mustT(t, err)
   219  	fi2, err := os.Stat(p2)
   220  	if errors.Is(err, os.ErrNotExist) {
   221  		return false
   222  	}
   223  	mustT(t, err)
   224  	return os.SameFile(fi1, fi2)
   225  }