package store import ( "context" "testing" "time" ) func TestAlertLifecycle(t *testing.T) { ctx := context.Background() st := testStore(t) dev := mustCreateDevice(t, st, "Harry's phone", "Harry", "android") a, err := st.CreateAlert(ctx, &dev.ID, AlertLimit, "Harry's phone reached its limit.") if err != nil { t.Fatalf("CreateAlert: %v", err) } if a.Delivered { t.Error("a fresh alert must not be delivered") } if a.DeviceName != "Harry's phone" { t.Errorf("device name = %q", a.DeviceName) } // The alert is audited. audit, err := st.ListAudit(ctx, 10) if err != nil { t.Fatalf("ListAudit: %v", err) } if len(audit) == 0 || audit[0].Action != "alert.limit" { t.Fatalf("audit = %#v, want an alert.limit row", audit) } if err := st.MarkAlertDelivered(ctx, a.ID, ""); err != nil { t.Fatalf("MarkAlertDelivered: %v", err) } got, err := st.GetAlert(ctx, a.ID) if err != nil { t.Fatalf("GetAlert: %v", err) } if !got.Delivered || got.DeliveredAt == nil || got.Error != "" { t.Errorf("delivered alert = %#v", got) } // A delivery failure is recorded, not hidden. b, err := st.CreateAlert(ctx, nil, AlertNotify, "message") if err != nil { t.Fatalf("CreateAlert notify: %v", err) } if err := st.MarkAlertDelivered(ctx, b.ID, "post apprise: status 500"); err != nil { t.Fatalf("MarkAlertDelivered: %v", err) } got, err = st.GetAlert(ctx, b.ID) if err != nil { t.Fatalf("GetAlert: %v", err) } if got.Delivered || got.Error != "post apprise: status 500" { t.Errorf("failed alert = %#v", got) } if _, err := st.CreateAlert(ctx, nil, "bogus", "x"); err == nil { t.Error("CreateAlert accepted an unknown kind") } } func TestAlertStatesRoundTrip(t *testing.T) { ctx := context.Background() st := testStore(t) dev := mustCreateDevice(t, st, "Finn's computer", "Finn", "windows") states, err := st.AlertStates(ctx) if err != nil { t.Fatalf("AlertStates: %v", err) } if len(states) != 0 { t.Fatalf("states = %#v, want empty", states) } if err := st.SetAlertState(ctx, dev.ID, true, false); err != nil { t.Fatalf("SetAlertState: %v", err) } states, err = st.AlertStates(ctx) if err != nil { t.Fatalf("AlertStates: %v", err) } if st := states[dev.ID]; !st.Locked || st.Offline { t.Fatalf("state = %#v, want locked only", st) } if err := st.SetAlertState(ctx, dev.ID, false, true); err != nil { t.Fatalf("SetAlertState: %v", err) } states, _ = st.AlertStates(ctx) if st := states[dev.ID]; st.Locked || !st.Offline { t.Fatalf("state = %#v, want offline only", st) } } func TestUsageByDeviceForDay(t *testing.T) { ctx := context.Background() st := testStore(t) harry := mustCreateDevice(t, st, "Harry's phone", "Harry", "android") finn := mustCreateDevice(t, st, "Finn's computer", "Finn", "windows") day := time.Date(2026, 10, 13, 0, 0, 0, 0, time.UTC).Format("2006-01-02") if _, err := st.InsertTelemetry(ctx, harry.ID, day, []TelemetryEntry{ {App: "com.spotify.music", Seconds: 3600}, {Domain: "youtube.com", Seconds: 900}, }); err != nil { t.Fatalf("InsertTelemetry: %v", err) } if _, err := st.InsertTelemetry(ctx, finn.ID, day, []TelemetryEntry{{App: "chrome", Seconds: 1800}}); err != nil { t.Fatalf("InsertTelemetry: %v", err) } rows, err := st.UsageByDeviceForDay(ctx, day) if err != nil { t.Fatalf("UsageByDeviceForDay: %v", err) } if len(rows) != 2 { t.Fatalf("rows = %d, want 2", len(rows)) } if rows[0].Name != "Harry's phone" || rows[0].AppSeconds != 3600 || rows[0].DomainSeconds != 900 { t.Errorf("harry row = %#v", rows[0]) } if rows[1].Child != "Finn" || rows[1].AppSeconds != 1800 { t.Errorf("finn row = %#v", rows[1]) } // A day with no reports returns nothing. if rows, err := st.UsageByDeviceForDay(ctx, "2000-01-01"); err != nil || len(rows) != 0 { t.Fatalf("empty day: rows=%#v err=%v", rows, err) } }