Test that a native create re-arms the reminder wake
The native API is JSON POSTs, not page loads. Main's scheduledWork middleware re-arms after every request; this pins that a native create arms the wake for the reminder it schedules. Fails (timer not armed) with the middleware removed from routes.go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+64
−0
internal/calendartest/native_schedule_test.go+64 −0
CI passed — run details
CI log
=== vet === go vet ./... === fmt === === test === go test ./... ? amadan.net/oficina/calendar/cmd/calendar [no test files] ok amadan.net/oficina/calendar/internal/calendar 4.468s ? 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 1.850s ok amadan.net/oficina/calendar/internal/guardstest 0.039s === migration-check === go run github.com/carlosframework/rastrillo/cmd/rastrillo migration check rastrillo migration check: models and migrations agree
diff --git a/internal/calendartest/native_schedule_test.go b/internal/calendartest/native_schedule_test.go| new file mode 100644 |
| index 0000000..0b74d7d |
| --- /dev/null |
| +++ b/internal/calendartest/native_schedule_test.go |
| @@ -0,0 +1,64 @@ |
| +package calendartest |
| + |
| +import ( |
| + "bytes" |
| + "context" |
| + "encoding/json" |
| + "net/http" |
| + "net/http/httptest" |
| + "testing" |
| + "time" |
| + |
| + calendar "amadan.net/oficina/calendar/internal/calendar" |
| +) |
| + |
| +// A native create is a JSON POST, not a page load. Main's scheduledWork |
| +// middleware re-arms the wake after EVERY request, so the reminder the |
| +// native create schedules is armed before anyone opens a page. The |
| +// merge of native/testflight kept that behaviour; this stands in front |
| +// of it. |
| +func TestNativeCreateArmsTheWakeForItsReminder(t *testing.T) { |
| + control := controlForTest(t) |
| + app, session := signedIn(t, "someone@example.com") |
| + |
| + rec := getAs(t, app.Handler(), session, "/api/native/session") |
| + var sess struct { |
| + DefaultCalendarID int64 `json:"default_calendar_id"` |
| + } |
| + if rec.Code != http.StatusOK || json.Unmarshal(rec.Body.Bytes(), &sess) != nil || sess.DefaultCalendarID == 0 { |
| + t.Fatalf("native session = %d: %s", rec.Code, rec.Body.String()) |
| + } |
| + if at, _ := control.snapshot(); !at.IsZero() { |
| + t.Fatalf("timer armed before any work existed: %v", at) |
| + } |
| + |
| + start := time.Now().UTC().Add(2 * time.Minute) |
| + body, _ := json.Marshal(map[string]any{ |
| + "calendar_id": sess.DefaultCalendarID, "title": "Native standup", "tz": "UTC", |
| + "start_local": start.Format("2006-01-02T15:04"), "end_local": start.Add(15 * time.Minute).Format("2006-01-02T15:04"), |
| + }) |
| + req := httptest.NewRequest(http.MethodPost, "/api/native/events", bytes.NewReader(body)) |
| + req.Header.Set("Origin", calendar.TestOrigin) |
| + req.Header.Set("Content-Type", "application/json") |
| + req.AddCookie(session) |
| + rec = httptest.NewRecorder() |
| + app.Handler().ServeHTTP(rec, req) |
| + var saved struct { |
| + ID int64 `json:"id"` |
| + Warning string `json:"warning"` |
| + } |
| + if rec.Code != http.StatusOK || json.Unmarshal(rec.Body.Bytes(), &saved) != nil || saved.ID == 0 || saved.Warning != "" { |
| + t.Fatalf("native create = %d: %s", rec.Code, rec.Body.String()) |
| + } |
| + |
| + expected := app.StoreForTest().NextDueAt(context.Background()) |
| + if expected.IsZero() { |
| + t.Fatal("native create scheduled no reminder, so this test proves nothing") |
| + } |
| + control.waitArmed(t) |
| + // The default reminder is already overdue, so the wake is "now": |
| + // no earlier than the due moment and no later than the check. |
| + if at, _ := control.snapshot(); at.Before(expected) || at.After(time.Now()) { |
| + t.Fatalf("native POST armed %v, want between %v and now", at, expected) |
| + } |
| +} |