istio

Форк
0
/
filewatcher_test.go 
343 строки · 7.9 Кб
1
// Copyright Istio Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package filewatcher
16

17
import (
18
	"errors"
19
	"fmt"
20
	"os"
21
	"os/exec"
22
	"path"
23
	"runtime"
24
	"sync"
25
	"testing"
26

27
	"github.com/fsnotify/fsnotify"
28
	. "github.com/onsi/gomega"
29
)
30

31
func newWatchFile(t *testing.T) string {
32
	g := NewGomegaWithT(t)
33

34
	watchDir := t.TempDir()
35
	watchFile := path.Join(watchDir, "test.conf")
36
	err := os.WriteFile(watchFile, []byte("foo: bar\n"), 0o640)
37
	g.Expect(err).NotTo(HaveOccurred())
38

39
	return watchFile
40
}
41

42
func newWatchFileThatDoesNotExist(t *testing.T) string {
43
	watchDir := t.TempDir()
44

45
	watchFile := path.Join(watchDir, "test.conf")
46

47
	return watchFile
48
}
49

50
// newTwoWatchFile returns with two watch files that exist in the same base dir.
51
func newTwoWatchFile(t *testing.T) (string, string) {
52
	g := NewGomegaWithT(t)
53

54
	watchDir := t.TempDir()
55

56
	watchFile1 := path.Join(watchDir, "test1.conf")
57
	err := os.WriteFile(watchFile1, []byte("foo: bar\n"), 0o640)
58
	g.Expect(err).NotTo(HaveOccurred())
59

60
	watchFile2 := path.Join(watchDir, "test2.conf")
61
	err = os.WriteFile(watchFile2, []byte("foo: baz\n"), 0o640)
62
	g.Expect(err).NotTo(HaveOccurred())
63

64
	return watchFile1, watchFile2
65
}
66

67
// newSymlinkedWatchFile simulates the behavior of k8s configmap/secret.
68
// Path structure looks like:
69
//
70
//	<watchDir>/test.conf
71
//	             ^
72
//	             |
73
//
74
// <watchDir>/data/test.conf
75
//
76
//	^
77
//	|
78
//
79
// <watchDir>/data1/test.conf
80
func newSymlinkedWatchFile(t *testing.T) (string, string) {
81
	g := NewGomegaWithT(t)
82

83
	watchDir := t.TempDir()
84

85
	dataDir1 := path.Join(watchDir, "data1")
86
	err := os.Mkdir(dataDir1, 0o777)
87
	g.Expect(err).NotTo(HaveOccurred())
88

89
	realTestFile := path.Join(dataDir1, "test.conf")
90
	t.Logf("Real test file location: %s\n", realTestFile)
91
	err = os.WriteFile(realTestFile, []byte("foo: bar\n"), 0o640)
92
	g.Expect(err).NotTo(HaveOccurred())
93

94
	// Now, symlink the tmp `data1` dir to `data` in the baseDir
95
	os.Symlink(dataDir1, path.Join(watchDir, "data"))
96
	// And link the `<watchdir>/datadir/test.conf` to `<watchdir>/test.conf`
97
	watchFile := path.Join(watchDir, "test.conf")
98
	os.Symlink(path.Join(watchDir, "data", "test.conf"), watchFile)
99
	fmt.Printf("Watch file location: %s\n", path.Join(watchDir, "test.conf"))
100
	return watchDir, watchFile
101
}
102

103
func TestWatchFile(t *testing.T) {
104
	t.Run("file content changed", func(t *testing.T) {
105
		g := NewGomegaWithT(t)
106

107
		// Given a file being watched
108
		watchFile := newWatchFile(t)
109
		_, err := os.Stat(watchFile)
110
		g.Expect(err).NotTo(HaveOccurred())
111

112
		w := NewWatcher()
113
		w.Add(watchFile)
114
		events := w.Events(watchFile)
115

116
		wg := sync.WaitGroup{}
117
		wg.Add(1)
118
		go func() {
119
			<-events
120
			wg.Done()
121
		}()
122

123
		// Overwriting the file and waiting its event to be received.
124
		err = os.WriteFile(watchFile, []byte("foo: baz\n"), 0o640)
125
		g.Expect(err).NotTo(HaveOccurred())
126
		wg.Wait()
127

128
		_ = w.Close()
129
	})
130

131
	t.Run("link to real file changed (for k8s configmap/secret path)", func(t *testing.T) {
132
		// skip if not executed on Linux
133
		if runtime.GOOS != "linux" {
134
			t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...")
135
		}
136
		g := NewGomegaWithT(t)
137

138
		watchDir, watchFile := newSymlinkedWatchFile(t)
139

140
		w := NewWatcher()
141
		w.Add(watchFile)
142
		events := w.Events(watchFile)
143

144
		wg := sync.WaitGroup{}
145
		wg.Add(1)
146
		go func() {
147
			<-events
148
			wg.Done()
149
		}()
150

151
		// Link to another `test.conf` file
152
		dataDir2 := path.Join(watchDir, "data2")
153
		err := os.Mkdir(dataDir2, 0o777)
154
		g.Expect(err).NotTo(HaveOccurred())
155

156
		watchFile2 := path.Join(dataDir2, "test.conf")
157
		err = os.WriteFile(watchFile2, []byte("foo: baz\n"), 0o640)
158
		g.Expect(err).NotTo(HaveOccurred())
159

160
		// change the symlink using the `ln -sfn` command
161
		err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run()
162
		g.Expect(err).NotTo(HaveOccurred())
163

164
		// Wait its event to be received.
165
		wg.Wait()
166

167
		_ = w.Close()
168
	})
169

170
	t.Run("file added later", func(t *testing.T) {
171
		g := NewGomegaWithT(t)
172

173
		// Given a file being watched
174
		watchFile := newWatchFileThatDoesNotExist(t)
175

176
		w := NewWatcher()
177
		w.Add(watchFile)
178
		events := w.Events(watchFile)
179

180
		wg := sync.WaitGroup{}
181
		wg.Add(1)
182
		go func() {
183
			<-events
184
			wg.Done()
185
		}()
186

187
		// Overwriting the file and waiting its event to be received.
188
		err := os.WriteFile(watchFile, []byte("foo: baz\n"), 0o640)
189
		g.Expect(err).NotTo(HaveOccurred())
190
		wg.Wait()
191

192
		_ = w.Close()
193
	})
194
}
195

196
func TestWatcherLifecycle(t *testing.T) {
197
	g := NewGomegaWithT(t)
198

199
	watchFile1, watchFile2 := newTwoWatchFile(t)
200

201
	w := NewWatcher()
202

203
	// Validate Add behavior
204
	err := w.Add(watchFile1)
205
	g.Expect(err).NotTo(HaveOccurred())
206
	err = w.Add(watchFile2)
207
	g.Expect(err).NotTo(HaveOccurred())
208

209
	// Validate events and errors channel are fulfilled.
210
	events1 := w.Events(watchFile1)
211
	g.Expect(events1).NotTo(BeNil())
212
	events2 := w.Events(watchFile2)
213
	g.Expect(events2).NotTo(BeNil())
214

215
	errors1 := w.Errors(watchFile1)
216
	g.Expect(errors1).NotTo(BeNil())
217
	errors2 := w.Errors(watchFile2)
218
	g.Expect(errors2).NotTo(BeNil())
219

220
	// Validate Remove behavior
221
	err = w.Remove(watchFile1)
222
	g.Expect(err).NotTo(HaveOccurred())
223
	events1 = w.Events(watchFile1)
224
	g.Expect(events1).To(BeNil())
225
	errors1 = w.Errors(watchFile1)
226
	g.Expect(errors1).To(BeNil())
227
	events2 = w.Events(watchFile2)
228
	g.Expect(events2).NotTo(BeNil())
229
	errors2 = w.Errors(watchFile2)
230
	g.Expect(errors2).NotTo(BeNil())
231

232
	fmt.Printf("2\n")
233
	// Validate Close behavior
234
	err = w.Close()
235
	g.Expect(err).NotTo(HaveOccurred())
236
	events1 = w.Events(watchFile1)
237
	g.Expect(events1).To(BeNil())
238
	errors1 = w.Errors(watchFile1)
239
	g.Expect(errors1).To(BeNil())
240
	events2 = w.Events(watchFile2)
241
	g.Expect(events2).To(BeNil())
242
	errors2 = w.Errors(watchFile2)
243
	g.Expect(errors2).To(BeNil())
244
}
245

246
func TestErrors(t *testing.T) {
247
	w := NewWatcher()
248

249
	if ch := w.Errors("XYZ"); ch != nil {
250
		t.Error("Expected no channel")
251
	}
252

253
	if ch := w.Events("XYZ"); ch != nil {
254
		t.Error("Expected no channel")
255
	}
256

257
	name := newWatchFile(t)
258
	_ = w.Add(name)
259
	_ = w.Remove(name)
260

261
	if ch := w.Errors("XYZ"); ch != nil {
262
		t.Error("Expected no channel")
263
	}
264

265
	if ch := w.Events(name); ch != nil {
266
		t.Error("Expected no channel")
267
	}
268

269
	_ = w.Close()
270

271
	if err := w.Add(name); err == nil {
272
		t.Error("Expecting error")
273
	}
274

275
	if err := w.Remove(name); err == nil {
276
		t.Error("Expecting error")
277
	}
278

279
	if ch := w.Errors(name); ch != nil {
280
		t.Error("Expecting nil")
281
	}
282

283
	if ch := w.Events(name); ch != nil {
284
		t.Error("Expecting nil")
285
	}
286
}
287

288
func TestBadWatcher(t *testing.T) {
289
	w := NewWatcher()
290
	w.(*fileWatcher).funcs.newWatcher = func() (*fsnotify.Watcher, error) {
291
		return nil, errors.New("FOOBAR")
292
	}
293

294
	name := newWatchFile(t)
295
	if err := w.Add(name); err == nil {
296
		t.Errorf("Expecting error, got nil")
297
	}
298
	if err := w.Close(); err != nil {
299
		t.Errorf("Expecting nil, got %v", err)
300
	}
301
}
302

303
func TestBadAddWatcher(t *testing.T) {
304
	w := NewWatcher()
305
	w.(*fileWatcher).funcs.addWatcherPath = func(*fsnotify.Watcher, string) error {
306
		return errors.New("FOOBAR")
307
	}
308

309
	name := newWatchFile(t)
310
	if err := w.Add(name); err == nil {
311
		t.Errorf("Expecting error, got nil")
312
	}
313
	if err := w.Close(); err != nil {
314
		t.Errorf("Expecting nil, got %v", err)
315
	}
316
}
317

318
func TestDuplicateAdd(t *testing.T) {
319
	w := NewWatcher()
320

321
	name := newWatchFile(t)
322

323
	if err := w.Add(name); err != nil {
324
		t.Errorf("Expecting nil, got %v", err)
325
	}
326

327
	if err := w.Add(name); err == nil {
328
		t.Errorf("Expecting error, got nil")
329
	}
330

331
	_ = w.Close()
332
}
333

334
func TestBogusRemove(t *testing.T) {
335
	w := NewWatcher()
336

337
	name := newWatchFile(t)
338
	if err := w.Remove(name); err == nil {
339
		t.Errorf("Expecting error, got nil")
340
	}
341

342
	_ = w.Close()
343
}
344

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.