package store import ( "context" "testing" "time" ) // snoozeNudge records a nudge and immediately snoozes it at ts. func snoozeNudge(t *testing.T, s *Store, rule string, ts time.Time) { t.Helper() ctx := context.Background() id, err := s.RecordNudge(ctx, rule, "voice", "drink water", ts) if err != nil { t.Fatalf("RecordNudge: %v", err) } if err := s.ResolveNudge(ctx, id, NudgeSnoozed, ts); err != nil { t.Fatalf("ResolveNudge: %v", err) } } func TestSnoozedUntilPerRule(t *testing.T) { s := newTestStore(t) now := time.Now().UTC().Truncate(time.Millisecond) snoozeNudge(t, s, "water", now.Add(-10*time.Minute)) snoozeNudge(t, s, "break", now.Add(-30*time.Minute)) got, err := s.SnoozedUntil(context.Background(), now) if err != nil { t.Fatalf("SnoozedUntil: %v", err) } if len(got) != 2 { t.Fatalf("want 2 snoozed rules, got %v", got) } wantWater := now.Add(-10 * time.Minute).Add(SnoozeDuration) if !got["water"].Equal(wantWater) { t.Fatalf("water until = %v, want %v", got["water"], wantWater) } } // The map must only ever hold the newest snooze for a rule, so a stale one // can't shorten (or lengthen) the live one. func TestSnoozedUntilUsesNewestSnooze(t *testing.T) { s := newTestStore(t) now := time.Now().UTC().Truncate(time.Millisecond) snoozeNudge(t, s, "water", now.Add(-90*time.Minute)) snoozeNudge(t, s, "water", now.Add(-5*time.Minute)) got, err := s.SnoozedUntil(context.Background(), now) if err != nil { t.Fatalf("SnoozedUntil: %v", err) } want := now.Add(-5 * time.Minute).Add(SnoozeDuration) if !got["water"].Equal(want) { t.Fatalf("water until = %v, want %v", got["water"], want) } } // A snooze must expire. If this ever regresses Maven goes quiet forever and // nobody can tell why. func TestSnoozedUntilExpires(t *testing.T) { s := newTestStore(t) now := time.Now().UTC().Truncate(time.Millisecond) snoozeNudge(t, s, "water", now.Add(-SnoozeDuration-time.Minute)) got, err := s.SnoozedUntil(context.Background(), now) if err != nil { t.Fatalf("SnoozedUntil: %v", err) } if _, ok := got["water"]; ok { t.Fatalf("expired snooze still active: %v", got) } } // Other outcomes are not snoozes. func TestSnoozedUntilIgnoresOtherOutcomes(t *testing.T) { s := newTestStore(t) ctx := context.Background() now := time.Now().UTC().Truncate(time.Millisecond) for _, outcome := range []string{NudgeActed, NudgeIgnored} { id, err := s.RecordNudge(ctx, "water", "voice", "drink water", now) if err != nil { t.Fatalf("RecordNudge: %v", err) } if err := s.ResolveNudge(ctx, id, outcome, now); err != nil { t.Fatalf("ResolveNudge: %v", err) } } if _, err := s.RecordNudge(ctx, "break", "voice", "stand up", now); err != nil { t.Fatalf("RecordNudge: %v", err) } got, err := s.SnoozedUntil(ctx, now) if err != nil { t.Fatalf("SnoozedUntil: %v", err) } if len(got) != 0 { t.Fatalf("want no snoozes, got %v", got) } }