1 package watcherx
2
3 import (
4 "fmt"
5 "io/ioutil"
6 "os"
7 "path/filepath"
8 "runtime"
9 "testing"
10 "time"
11
12 "github.com/stretchr/testify/assert"
13
14 "github.com/stretchr/testify/require"
15 )
16
17 func TestWatchDirectory(t *testing.T) {
18 t.Run("case=notifies about file creation in directory", func(t *testing.T) {
19 ctx, c, dir, cancel := setup(t)
20 defer cancel()
21
22 _, err := WatchDirectory(ctx, dir, c)
23 require.NoError(t, err)
24 fileName := filepath.Join(dir, "example")
25 f, err := os.Create(fileName)
26 require.NoError(t, err)
27 require.NoError(t, f.Close())
28
29 assertChange(t, <-c, "", fileName)
30 })
31
32 t.Run("case=notifies about file write in directory", func(t *testing.T) {
33 ctx, c, dir, cancel := setup(t)
34 defer cancel()
35
36 fileName := filepath.Join(dir, "example")
37 f, err := os.Create(fileName)
38 require.NoError(t, err)
39 _, err = WatchDirectory(ctx, dir, c)
40 require.NoError(t, err)
41
42 _, err = fmt.Fprintf(f, "content")
43 require.NoError(t, f.Close())
44
45 assertChange(t, <-c, "content", fileName)
46 })
47
48 t.Run("case=nofifies about file delete in directory", func(t *testing.T) {
49 ctx, c, dir, cancel := setup(t)
50 defer cancel()
51
52 fileName := filepath.Join(dir, "example")
53 f, err := os.Create(fileName)
54 require.NoError(t, err)
55 require.NoError(t, f.Close())
56
57 _, err = WatchDirectory(ctx, dir, c)
58 require.NoError(t, err)
59 require.NoError(t, os.Remove(fileName))
60
61 assertRemove(t, <-c, fileName)
62 })
63
64 t.Run("case=notifies about file in child directory", func(t *testing.T) {
65 ctx, c, dir, cancel := setup(t)
66 defer cancel()
67
68 childDir := filepath.Join(dir, "child")
69 require.NoError(t, os.Mkdir(childDir, 0777))
70
71 _, err := WatchDirectory(ctx, dir, c)
72 require.NoError(t, err)
73
74 fileName := filepath.Join(childDir, "example")
75 f, err := os.Create(fileName)
76 require.NoError(t, err)
77 require.NoError(t, f.Close())
78
79 assertChange(t, <-c, "", fileName)
80 })
81
82 t.Run("case=watches new child directory", func(t *testing.T) {
83 ctx, c, dir, cancel := setup(t)
84 defer cancel()
85
86 _, err := WatchDirectory(ctx, dir, c)
87 require.NoError(t, err)
88
89 childDir := filepath.Join(dir, "child")
90 require.NoError(t, os.Mkdir(childDir, 0777))
91 fileName := filepath.Join(childDir, "example")
92
93 time.Sleep(time.Millisecond)
94 f, err := os.Create(fileName)
95 require.NoError(t, err)
96 require.NoError(t, f.Close())
97
98 assertChange(t, <-c, "", fileName)
99 })
100
101 t.Run("case=does not notify on directory deletion", func(t *testing.T) {
102 if runtime.GOOS != "linux" {
103 t.Skip("skipping test because IN_DELETE_SELF is unreliable on windows and macOS")
104 }
105
106 ctx, c, dir, cancel := setup(t)
107 defer cancel()
108
109 childDir := filepath.Join(dir, "child")
110 require.NoError(t, os.Mkdir(childDir, 0777))
111
112 _, err := WatchDirectory(ctx, dir, c)
113 require.NoError(t, err)
114
115 require.NoError(t, os.Remove(childDir))
116
117 select {
118 case e := <-c:
119 t.Logf("got unexpected event %T: %+v", e, e)
120 t.FailNow()
121 case <-time.After(2 * time.Millisecond):
122
123 }
124 })
125
126 t.Run("case=notifies only for files on batch delete", func(t *testing.T) {
127 ctx, c, dir, cancel := setup(t)
128 defer cancel()
129
130 childDir := filepath.Join(dir, "child")
131 subChildDir := filepath.Join(childDir, "subchild")
132 require.NoError(t, os.MkdirAll(subChildDir, 0777))
133 f1 := filepath.Join(subChildDir, "f1")
134 f, err := os.Create(f1)
135 require.NoError(t, err)
136 require.NoError(t, f.Close())
137 f2 := filepath.Join(childDir, "f2")
138 f, err = os.Create(f2)
139 require.NoError(t, err)
140 require.NoError(t, f.Close())
141
142 _, err = WatchDirectory(ctx, dir, c)
143 require.NoError(t, err)
144
145 require.NoError(t, os.RemoveAll(childDir))
146
147 events := []Event{<-c, <-c}
148 if events[0].Source() > events[1].Source() {
149 events[1], events[0] = events[0], events[1]
150 }
151 assertRemove(t, events[0], f2)
152 assertRemove(t, events[1], f1)
153 })
154
155 t.Run("case=sends event when requested", func(t *testing.T) {
156 ctx, c, dir, cancel := setup(t)
157 defer cancel()
158
159
160 c = make(EventChannel, 4)
161
162 files := map[string]string{
163 "a": "foo",
164 "b": "bar",
165 "c": "baz",
166 filepath.Join("d", "a"): "sub dir content",
167 }
168 for fn, fc := range files {
169 fp := filepath.Join(dir, fn)
170 require.NoError(t, os.MkdirAll(filepath.Dir(fp), 0700))
171 require.NoError(t, ioutil.WriteFile(fp, []byte(fc), 0600))
172 }
173
174 d, err := WatchDirectory(ctx, dir, c)
175 require.NoError(t, err)
176 done, err := d.DispatchNow()
177 require.NoError(t, err)
178
179
180 select {
181 case <-time.After(time.Second):
182 t.Log("Waiting for done timed out.")
183 t.FailNow()
184 case eventsSend := <-done:
185 assert.Equal(t, 4, eventsSend)
186 }
187
188
189 assertChange(t, <-c, files["a"], filepath.Join(dir, "a"))
190 assertChange(t, <-c, files["b"], filepath.Join(dir, "b"))
191 assertChange(t, <-c, files["c"], filepath.Join(dir, "c"))
192 assertChange(t, <-c, files[filepath.Join("d", "a")], filepath.Join(dir, "d", "a"))
193 })
194 }
195
View as plain text