Drive the archive reopen debounce test from a clock (closes #190)
check / check (push) Successful in 3m27s

The archive writer's reopen debounce test made two writes that had to land inside the real 2-second window, then slept 2.1 seconds to cross it, so a slow host could turn correct code red. The archive writer now reads the time for its reopen debounce from a clock field, time.Now in production, and the test moves that clock instead of sleeping: two writes at one instant open the file once, and a write one debounce later closes and reopens it once. Removing the debounce check fails the test. This was the last test whose result depended on real elapsed time.

Model: opus-5-5
This commit was merged in pull request #438.
This commit is contained in:
2026-10-02 16:03:01 +02:00
parent 88b961c115
commit 3e209bfe4e
3 changed files with 24 additions and 6 deletions
+6
View File
@@ -512,6 +512,12 @@ func (e *ExportArchiveWriter) Reopen(
return e.w.reopen(expiry)
}
// SetNow replaces the clock the writer measures its reopen
// debounce on.
func (e *ExportArchiveWriter) SetNow(now func() time.Time) {
e.w.now = now
}
// Reopens reports how many times the file has been opened.
func (e *ExportArchiveWriter) Reopens() int {
return e.w.reopens
+7 -2
View File
@@ -194,6 +194,10 @@ type archiveWriter struct {
lastReopen time.Time
reopens int
// now is the clock the reopen debounce is measured on. It is
// time.Now outside tests.
now func() time.Time
// evicted marks a writer that has been removed from the
// registry. Its handle is closed and it must never open the
// file again: nothing holds it any more, so a reopen would
@@ -228,6 +232,7 @@ func newArchiveWriter(
path: path,
log: log,
debounce: archiveReopenDebounce,
now: time.Now,
}
}
@@ -263,7 +268,7 @@ func (w *archiveWriter) write(
)
}
if time.Since(w.lastReopen) >= w.debounce {
if w.now().Sub(w.lastReopen) >= w.debounce {
return w.reopen(expiry)
}
@@ -323,7 +328,7 @@ func (w *archiveWriter) openMode(
}
w.db = gdb
w.lastReopen = time.Now()
w.lastReopen = w.now()
w.reopens++
if expiry > 0 {
+11 -4
View File
@@ -184,13 +184,20 @@ func TestArchiveWriter_RecreatesAfterRemoval(
func TestArchiveWriter_ReopenDebounce(t *testing.T) {
t.Parallel()
// A generous debounce keeps the two rapid writes inside
// the window even on a heavily loaded test machine.
const debounce = 2 * time.Second
path := filepath.Join(t.TempDir(), "archive-wh.db")
w := delivery.NewExportArchiveWriter(
path, archiveTestLogger(), 2*time.Second,
path, archiveTestLogger(), debounce,
)
// The writer measures its reopen debounce on this clock, which
// only the test moves, so how long the host takes between
// writes cannot change the result.
now := time.Now()
w.SetNow(func() time.Time { return now })
require.NoError(t, w.Write(
delivery.ExportArchivedEvent{EventID: "a"}, 0,
))
@@ -202,7 +209,7 @@ func TestArchiveWriter_ReopenDebounce(t *testing.T) {
// initial open — no extra close/reopen.
assert.Equal(t, 1, w.Reopens())
time.Sleep(2100 * time.Millisecond)
now = now.Add(debounce)
require.NoError(t, w.Write(
delivery.ExportArchivedEvent{EventID: "c"}, 0,