package notifications import ( "context" "testing" "time" "bookra/apps/backend/internal/config" "bookra/apps/backend/internal/db" "bookra/apps/backend/internal/domain" ) func TestDispatchDueProcessesPendingEmailReminders(t *testing.T) { repo := db.NewMemoryRepository() startsAt := time.Now().UTC().Add(26 * time.Hour) created, err := repo.CreateBooking(context.Background(), db.CreateBookingParams{ TenantID: "5d6b3551-0a3e-4b86-bdf0-e9df20a47148", BookingMode: "appointment", CustomerName: "Reminder Customer", CustomerEmail: "reminder@example.com", StartsAt: startsAt, EndsAt: startsAt.Add(time.Hour), Status: "confirmed", Reference: "BK-TEST-REMINDER", }) if err != nil { t.Fatalf("create booking: %v", err) } if err := repo.CreateReminderJob(context.Background(), db.ReminderJobParams{ TenantID: "5d6b3551-0a3e-4b86-bdf0-e9df20a47148", BookingID: created.ID, Channel: "email", ScheduledFor: time.Now().UTC().Add(-time.Minute), }); err != nil { t.Fatalf("create reminder job: %v", err) } service := NewService(config.Config{ Environment: "development", EmailFrom: "noreply@bookra.dev", SMSFrom: "Bookra", }, repo) response, err := service.DispatchDue(context.Background(), 10) if err != nil { t.Fatalf("dispatch due: %v", err) } if response.ProcessedCount != 1 { t.Fatalf("expected processed count 1, got %d", response.ProcessedCount) } if response.SentCount != 1 { t.Fatalf("expected sent count 1, got %d", response.SentCount) } if response.FailedCount != 0 { t.Fatalf("expected failed count 0, got %d", response.FailedCount) } pending, err := repo.ListDueReminderJobs(context.Background(), time.Now().UTC().Add(time.Hour), 10) if err != nil { t.Fatalf("list due reminder jobs: %v", err) } if len(pending) != 0 { t.Fatalf("expected no pending jobs after dispatch, got %d", len(pending)) } } func TestDispatchDueFailsUnknownChannel(t *testing.T) { repo := db.NewMemoryRepository() if err := repo.CreateReminderJob(context.Background(), db.ReminderJobParams{ TenantID: "5d6b3551-0a3e-4b86-bdf0-e9df20a47148", BookingID: "booking-unknown-channel", Channel: "push", ScheduledFor: time.Now().UTC().Add(-time.Minute), }); err != nil { t.Fatalf("create reminder job: %v", err) } service := NewService(config.Config{Environment: "development"}, repo) response, err := service.DispatchDue(context.Background(), 10) if err != nil { t.Fatalf("dispatch due: %v", err) } if response.ProcessedCount != 1 || response.FailedCount != 1 { t.Fatalf("expected one failed job, got %+v", response) } } func TestDispatchRequestContractShape(t *testing.T) { request := domain.DispatchReminderJobsRequest{Limit: 20} if request.Limit != 20 { t.Fatalf("expected limit 20, got %d", request.Limit) } }