Skip to content

Commit fd52e3c

Browse files
authored
Fix flaky file watcher test (#258)
* Fix falky file watcher test The test method `waitForRead` was sometimes signaling due to accumulated reads, even it was inteded to wait for a read after a new content was set in the mock file. This fixes it by waiting to singal read happened when the read content is the same as the expected one. Signed-off-by: Sergi Castro <sergi@tetrate.io> * Add more specific methods Signed-off-by: Sergi Castro <sergi@tetrate.io> --------- Signed-off-by: Sergi Castro <sergi@tetrate.io>
1 parent 0d8008e commit fd52e3c

File tree

1 file changed

+72
-56
lines changed

1 file changed

+72
-56
lines changed

internal/file_test.go

+72-56
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,8 @@ func TestFileWatcher_WatchFile(t *testing.T) {
4949
name: "all updates notified",
5050
fileReader: newMockReader("test", "original", nil),
5151
genUpdates: func(reader *mockReader) {
52-
reader.setData([]byte("update 1"))
53-
reader.waitForRead()
54-
reader.setData([]byte("update 2"))
55-
reader.waitForRead()
52+
reader.setDataAndWaitForRead([]byte("update 1"))
53+
reader.setDataAndWaitForRead([]byte("update 2"))
5654
},
5755
interval: watcherInterval,
5856
wantCallbacks: 2,
@@ -63,14 +61,10 @@ func TestFileWatcher_WatchFile(t *testing.T) {
6361
name: "no content changes don't notify",
6462
fileReader: newMockReader("test", "original", nil),
6563
genUpdates: func(reader *mockReader) {
66-
reader.setData([]byte("update 1"))
67-
reader.waitForRead()
68-
reader.setData([]byte("update 2"))
69-
reader.waitForRead()
70-
reader.setData([]byte("update 2"))
71-
reader.waitForRead()
72-
reader.setData([]byte("update 2"))
73-
reader.waitForRead()
64+
reader.setDataAndWaitForRead([]byte("update 1"))
65+
reader.setDataAndWaitForRead([]byte("update 2"))
66+
reader.setDataAndWaitForRead([]byte("update 2"))
67+
reader.setDataAndWaitForRead([]byte("update 2"))
7468
},
7569
interval: watcherInterval,
7670
wantCallbacks: 2,
@@ -81,11 +75,8 @@ func TestFileWatcher_WatchFile(t *testing.T) {
8175
name: "missed update due to slow interval",
8276
fileReader: newMockReader("test", "original", nil),
8377
genUpdates: func(reader *mockReader) {
84-
reader.setData([]byte("update 1"))
85-
// no waiting for the read to happen and performing next update
86-
// reader.waitForRead()
87-
reader.setData([]byte("update 2"))
88-
reader.waitForRead()
78+
reader.setData([]byte("update 1")) // no waiting for the read to happen and performing next update
79+
reader.setDataAndWaitForRead([]byte("update 2"))
8980
},
9081
interval: watcherInterval,
9182
wantCallbacks: 1,
@@ -102,15 +93,12 @@ func TestFileWatcher_WatchFile(t *testing.T) {
10293
name: "error reading file after start",
10394
fileReader: newMockReader("test", "original", nil),
10495
genUpdates: func(reader *mockReader) {
105-
reader.setData([]byte("update 1"))
106-
reader.waitForRead()
107-
reader.setErr(errors.New("error reading file"))
108-
reader.waitForRead()
96+
reader.setDataAndWaitForRead([]byte("update 1"))
97+
reader.setErrAdnWaitForRead(errors.New("error reading file"))
10998
// stop error
110-
reader.setErr(nil)
99+
reader.unsetErr()
111100
// even if an error happens, next updates should be notified
112-
reader.setData([]byte("update 2"))
113-
reader.waitForRead()
101+
reader.setDataAndWaitForRead([]byte("update 2"))
114102
},
115103
interval: watcherInterval,
116104
wantCallbacks: 2,
@@ -158,7 +146,7 @@ func TestFileWatcher_WatchFile(t *testing.T) {
158146
require.False(t, ok)
159147
}
160148

161-
tt.fileReader.waitForRead() // Wait for the first read to happen, the one synchronous
149+
tt.fileReader.waitForRead(got) // Wait for the first read to happen, the one synchronous
162150
require.Equal(t, tt.want, string(got))
163151
require.NoError(t, err)
164152

@@ -199,7 +187,7 @@ func TestFileWatcher_WatchFile(t *testing.T) {
199187
mu1.Unlock()
200188
})
201189
require.NoError(t, err)
202-
file1.waitForRead() // Wait for the first read to happen
190+
file1.waitForRead([]byte("original1")) // Wait for the first read to happen
203191

204192
file2 := newMockReader("test2", "original2", nil)
205193
got2, err := fw.WatchFile(file2, watcherInterval, func(data []byte) {
@@ -209,14 +197,11 @@ func TestFileWatcher_WatchFile(t *testing.T) {
209197
mu2.Unlock()
210198
})
211199
require.NoError(t, err)
212-
file2.waitForRead() // Wait for the first read to happen
200+
file2.waitForRead([]byte("original2")) // Wait for the first read to happen
213201

214-
file1.setData([]byte("update 1-1"))
215-
file1.waitForRead()
216-
file2.setData([]byte("update 2-1"))
217-
file2.waitForRead()
218-
file1.setData([]byte("update 1-2"))
219-
file1.waitForRead()
202+
file1.setDataAndWaitForRead([]byte("update 1-1"))
203+
file2.setDataAndWaitForRead([]byte("update 2-1"))
204+
file1.setDataAndWaitForRead([]byte("update 1-2"))
220205

221206
// ensure no more updates are notified before verifying the results
222207
cancel()
@@ -250,7 +235,7 @@ func TestFileWatcher_WatchFile(t *testing.T) {
250235
muU.Unlock()
251236
})
252237
require.NoError(t, err)
253-
file1.waitForRead() // Wait for the first read to happen
238+
file1.waitForRead([]byte("original")) // Wait for the first read to happen
254239

255240
wg := sync.WaitGroup{}
256241
wg.Add(2) // 2 callbacks to be notified
@@ -263,12 +248,10 @@ func TestFileWatcher_WatchFile(t *testing.T) {
263248
muO.Unlock()
264249
})
265250
require.NoError(t, err)
266-
file1.waitForRead() // Wait for the first read to happen again
251+
file1.waitForRead([]byte("override")) // Wait for the first read to happen again
267252

268-
file1.setData([]byte("update 1"))
269-
file1.waitForRead()
270-
file1.setData([]byte("update 2"))
271-
file1.waitForRead()
253+
file1.setDataAndWaitForRead([]byte("update 1"))
254+
file1.setDataAndWaitForRead([]byte("update 2"))
272255

273256
// ensure no more updates are notified before verifying the results
274257
cancel()
@@ -284,57 +267,90 @@ func TestFileWatcher_WatchFile(t *testing.T) {
284267

285268
var _ Reader = (*mockReader)(nil)
286269

287-
type mockReader struct {
288-
id string
289-
err error
270+
type (
271+
mockReader struct {
272+
id string
273+
err error
290274

291-
m sync.Mutex
292-
fileData []byte
275+
m sync.Mutex
276+
fileData []byte
293277

294-
// reads is used to signal that a read happened, it should be buffered to avoid deadlocks.
295-
// It is used to know if a read happened but there's no need to block reads happening if no one is waiting for them.
296-
reads chan struct{}
297-
}
278+
// reads is used to signal that a read happened, it should be buffered to avoid deadlocks.
279+
// It is used to know if a read happened but there's no need to block reads happening if no one is waiting for them.
280+
reads chan msg
281+
}
282+
283+
msg struct {
284+
data []byte
285+
err error
286+
}
287+
)
298288

299289
func newMockReader(id, data string, err error) *mockReader {
300290
return &mockReader{
301291
id: id,
302292
fileData: []byte(data),
303293
err: err,
304-
reads: make(chan struct{}, 50),
294+
reads: make(chan msg, 50),
305295
}
306296
}
307297

298+
// Implement Reader interface
308299
func (m *mockReader) ID() string {
309300
return m.id
310301
}
311302

303+
// Implement Reader interface
312304
func (m *mockReader) Read() ([]byte, error) {
313-
// Notify that a read happened
314-
defer func() { m.reads <- struct{}{} }()
315-
316305
m.m.Lock()
317306
defer m.m.Unlock()
318307

308+
// Notify that a read happened
309+
defer func() { m.reads <- msg{data: m.fileData, err: m.err} }()
310+
319311
if m.err != nil {
320312
return nil, m.err
321313
}
322314

323315
return m.fileData, nil
324316
}
325317

318+
// setData sets the data to be read.
326319
func (m *mockReader) setData(data []byte) {
327320
m.m.Lock()
328321
defer m.m.Unlock()
329322
m.fileData = data
330323
}
331324

332-
func (m *mockReader) setErr(err error) {
325+
// setDataAndWaitForRead sets the data and waits for the read to happen with the given data.
326+
func (m *mockReader) setDataAndWaitForRead(data []byte) {
327+
m.setData(data)
328+
m.waitForRead(data)
329+
}
330+
331+
// waitForRead waits for the given data to be read.
332+
func (m *mockReader) waitForRead(data []byte) {
333+
readData := <-m.reads // wait for at least first read
334+
for string(readData.data) != string(data) {
335+
readData = <-m.reads
336+
}
337+
}
338+
339+
// setErrAndWaitForRead sets the error and waits for the read to happen with the given error.
340+
func (m *mockReader) setErrAdnWaitForRead(err error) {
333341
m.m.Lock()
334-
defer m.m.Unlock()
335342
m.err = err
343+
m.m.Unlock()
344+
345+
readData := <-m.reads // wait for at least first read
346+
for !errors.Is(err, readData.err) {
347+
readData = <-m.reads
348+
}
336349
}
337350

338-
func (m *mockReader) waitForRead() {
339-
<-m.reads
351+
// unsetErr unsets the error to stop the mockReader to fail on Read().
352+
func (m *mockReader) unsetErr() {
353+
m.m.Lock()
354+
defer m.m.Unlock()
355+
m.err = nil
340356
}

0 commit comments

Comments
 (0)