package usecase import ( "context" "testing" "haixun-backend/internal/library/clock" "haixun-backend/internal/model/job/domain/entity" domusecase "haixun-backend/internal/model/job/domain/usecase" ) func TestRunSchedulerTick_CreatesRun(t *testing.T) { ctx := context.Background() template := demoTemplate() schedules := &memoryScheduleRepo{} queue := newMemoryQueueRepo() runs := newMemoryRunRepo(nil) uc := testUseCaseFull(template, runs, schedules, queue) now := clock.NowUnixNano() schedule := &entity.Schedule{ TemplateType: template.Type, Scope: "user", ScopeID: "scheduler-user", Enabled: true, Cron: "0 * * * *", Timezone: "Asia/Taipei", NextRunAt: now - 1, } _, _ = schedules.Create(ctx, schedule) created, err := uc.RunSchedulerTick(ctx, "test-holder") if err != nil { t.Fatalf("RunSchedulerTick() error = %v", err) } if created != 1 { t.Fatalf("created = %d, want 1", created) } if len(queue.queued("go")) == 0 { t.Fatal("expected queued job from scheduler tick") } if runs.run == nil { t.Fatal("expected run to be created") } meta, ok := runs.run.Payload[schedulePayloadKey].(map[string]any) if !ok { t.Fatal("expected _schedule payload metadata") } if meta["timezone"] != "Asia/Taipei" { t.Fatalf("timezone = %v, want Asia/Taipei", meta["timezone"]) } if meta["storage_tz"] != clock.StorageTimezone { t.Fatalf("storage_tz = %v, want %s", meta["storage_tz"], clock.StorageTimezone) } triggeredAt, ok := meta["triggered_at"].(int64) if !ok || triggeredAt <= 0 { t.Fatalf("triggered_at = %v, want positive unix nano UTC", meta["triggered_at"]) } } func TestCreateSchedule_InvalidCron(t *testing.T) { ctx := context.Background() template := demoTemplate() uc := testUseCaseFull(template, newMemoryRunRepo(nil), &memoryScheduleRepo{}, newMemoryQueueRepo()) _, err := uc.CreateSchedule(ctx, domusecase.CreateScheduleRequest{ TemplateType: template.Type, Scope: "user", ScopeID: "u1", Cron: "invalid", }) if err == nil { t.Fatal("expected invalid cron error") } }