| 1 | package calendartest |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "context" |
| 6 | "encoding/json" |
| 7 | "net/http" |
| 8 | "net/http/httptest" |
| 9 | "testing" |
| 10 | "time" |
| 11 | |
| 12 | calendar "amadan.net/oficina/calendar/internal/calendar" |
| 13 | ) |
| 14 | |
| 15 | // A native create is a JSON POST, not a page load. Main's scheduledWork |
| 16 | // middleware re-arms the wake after EVERY request, so the reminder the |
| 17 | // native create schedules is armed before anyone opens a page. The |
| 18 | // merge of native/testflight kept that behaviour; this stands in front |
| 19 | // of it. |
| 20 | func TestNativeCreateArmsTheWakeForItsReminder(t *testing.T) { |
| 21 | control := controlForTest(t) |
| 22 | app, session := signedIn(t, "someone@example.com") |
| 23 | |
| 24 | rec := getAs(t, app.Handler(), session, "/api/native/session") |
| 25 | var sess struct { |
| 26 | DefaultCalendarID int64 `json:"default_calendar_id"` |
| 27 | } |
| 28 | if rec.Code != http.StatusOK || json.Unmarshal(rec.Body.Bytes(), &sess) != nil || sess.DefaultCalendarID == 0 { |
| 29 | t.Fatalf("native session = %d: %s", rec.Code, rec.Body.String()) |
| 30 | } |
| 31 | if at, _ := control.snapshot(); !at.IsZero() { |
| 32 | t.Fatalf("timer armed before any work existed: %v", at) |
| 33 | } |
| 34 | |
| 35 | start := time.Now().UTC().Add(2 * time.Minute) |
| 36 | body, _ := json.Marshal(map[string]any{ |
| 37 | "calendar_id": sess.DefaultCalendarID, "title": "Native standup", "tz": "UTC", |
| 38 | "start_local": start.Format("2006-01-02T15:04"), "end_local": start.Add(15 * time.Minute).Format("2006-01-02T15:04"), |
| 39 | }) |
| 40 | req := httptest.NewRequest(http.MethodPost, "/api/native/events", bytes.NewReader(body)) |
| 41 | req.Header.Set("Origin", calendar.TestOrigin) |
| 42 | req.Header.Set("Content-Type", "application/json") |
| 43 | req.AddCookie(session) |
| 44 | rec = httptest.NewRecorder() |
| 45 | app.Handler().ServeHTTP(rec, req) |
| 46 | var saved struct { |
| 47 | ID int64 `json:"id"` |
| 48 | Warning string `json:"warning"` |
| 49 | } |
| 50 | if rec.Code != http.StatusOK || json.Unmarshal(rec.Body.Bytes(), &saved) != nil || saved.ID == 0 || saved.Warning != "" { |
| 51 | t.Fatalf("native create = %d: %s", rec.Code, rec.Body.String()) |
| 52 | } |
| 53 | |
| 54 | expected := app.StoreForTest().NextDueAt(context.Background()) |
| 55 | if expected.IsZero() { |
| 56 | t.Fatal("native create scheduled no reminder, so this test proves nothing") |
| 57 | } |
| 58 | control.waitArmed(t) |
| 59 | // The default reminder is already overdue, so the wake is "now": |
| 60 | // no earlier than the due moment and no later than the check. |
| 61 | if at, _ := control.snapshot(); at.Before(expected) || at.After(time.Now()) { |
| 62 | t.Fatalf("native POST armed %v, want between %v and now", at, expected) |
| 63 | } |
| 64 | } |
| 65 | |