oficina / calendar Public

Seed the boot-recovery test's work before the failing boot

TestTransientControlFailureAtBootRecovers inserted its queue row
straight into the database after the app had booted. When the retry
loop's first attempt ran before that INSERT it found nothing due,
succeeded, and nothing woke it again (a raw INSERT skips the request
middleware that does), so the timer stayed unarmed and the test failed
"timer was not armed" about one run in ten, on main as well. It turned
this branch's CI red.

The row is now written through a first boot of the same database, which
is then closed; the second boot meets the control failure with the work
already there, as a restarting instance does. 40 runs pass, and
dropping sync's retry request on a boot failure still fails it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 8a02f1e3f54e4f66d99a3465b9a85c40d2852ad9 parent dabf234
1 file changed, +15 −5
  • internal/calendartest/schedule_recovery_test.go +15 −5

CI passed — run details

CI log
=== vet ===
go vet ./...
go vet -tags browser ./internal/calendartest/
=== fmt ===
=== test ===
go test ./...
?   	amadan.net/oficina/calendar/cmd/calendar	[no test files]
ok  	amadan.net/oficina/calendar/internal/calendar	(cached)
?   	amadan.net/oficina/calendar/internal/calendar/icons	[no test files]
?   	amadan.net/oficina/calendar/internal/calendar/seal	[no test files]
ok  	amadan.net/oficina/calendar/internal/calendartest	2.494s
ok  	amadan.net/oficina/calendar/internal/guardstest	0.044s
?   	amadan.net/oficina/calendar/scripts/writeestilo	[no test files]
=== migration-check ===
go tool rastrillo migration check
rastrillo migration check: models and migrations agree
diff --git a/internal/calendartest/schedule_recovery_test.go b/internal/calendartest/schedule_recovery_test.go
index 4c2699d..1e1f420 100644
--- a/internal/calendartest/schedule_recovery_test.go
+++ b/internal/calendartest/schedule_recovery_test.go
@@ -9,16 +9,26 @@ import (
calendar "amadan.net/oficina/calendar/internal/calendar"
)
+// The work is in the database before the failing boot, as it is when an
+// instance restarts. It used to be inserted straight into the database
+// after boot, which raced the retry loop: when the first retry ran before
+// the INSERT it found nothing due, succeeded, and nothing woke it again
+// (a raw INSERT bypasses the request middleware that wakes it), so about
+// one run in ten failed "timer was not armed".
func TestTransientControlFailureAtBootRecovers(t *testing.T) {
control := controlForTest(t)
- control.mu.Lock()
- control.fail = true
- control.mu.Unlock()
- app := calendar.NewForTest(t, t.TempDir())
+ dir := t.TempDir()
+ seed := calendar.NewForTest(t, dir)
due := time.Now().Add(time.Hour).Unix()
- if _, err := app.DBForTest().Exec(`INSERT INTO reminder_queues (reminder_id,occurrence_key,due_at,attempts,late_by_sec) VALUES (1,'boot-retry',?,0,0)`, due); err != nil {
+ if _, err := seed.DBForTest().Exec(`INSERT INTO reminder_queues (reminder_id,occurrence_key,due_at,attempts,late_by_sec) VALUES (1,'boot-retry',?,0,0)`, due); err != nil {
t.Fatal(err)
}
+ seed.Close()
+ control.mu.Lock()
+ control.at = time.Time{}
+ control.fail = true
+ control.mu.Unlock()
+ calendar.NewForTest(t, dir)
control.mu.Lock()
control.fail = false
control.mu.Unlock()