Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions internal/filedata/poller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,25 @@ func requireStopped(t *testing.T, p *Poller) {
}
}

// drainChanges discards the change callbacks that arrive within the settle window. A plain
// rewrite is not atomic: the truncation, the write, and the modification-time update are
// separate steps, and a poll that lands between two of them legitimately reports an extra
// change. A test that wants to assert silence waits for the write to be fully observed first.
func drainChanges(changed chan struct{}, settle time.Duration) {
deadline := time.After(settle)
for {
select {
case <-changed:
case <-deadline:
return
}
}
}

// writeFileWithNewModTime rewrites a file and guarantees the observed (modTime, size) state
// differs from the previous state, so the poller must detect it regardless of filesystem
// timestamp granularity.
// timestamp granularity. The write is an ordinary one, in separate steps, as application
// writes are.
func writeFileWithNewModTime(t *testing.T, path string, content string) {
t.Helper()
require.NoError(t, os.WriteFile(path, []byte(content), 0600))
Expand Down Expand Up @@ -94,13 +110,17 @@ func TestPollerDetectsSizeChangeWithSameModTime(t *testing.T) {
requireChange(t, changed)
}

func TestPollerFiresOncePerChange(t *testing.T) {
// The poller updates its baseline after a change, so it goes quiet once the file is stable. It
// does not promise one callback per logical change: a rewrite that the poller observes in more
// than one step is reported in more than one step, and the Reloader absorbs the excess.
func TestPollerStopsFiringWhenFileIsStable(t *testing.T) {
path := filepath.Join(t.TempDir(), "data.json")
writeFileWithNewModTime(t, path, "one")
changed := newPollerFixture(t, []string{path})

writeFileWithNewModTime(t, path, "two!")
requireChange(t, changed)
drainChanges(changed, 10*pollTestInterval)

requireNoChange(t, changed, 20*pollTestInterval)
}
Expand Down
Loading