package scheduler import ( "context" "errors" "testing" "time" ) // R-314/R-177 (`09` §3 decision 185): RunNow runs a registered job once, now, and refuses an unknown // name and a job already running — the operator's run_job action rests on these three answers. func TestRunNow_RunsOnceAndReportsCompletion(t *testing.T) { s := discardScheduler() calls := 0 var sawOnDemand bool s.Daily("fill-watch", farFuture(5), func(ctx context.Context) error { calls++ sawOnDemand = OnDemand(ctx) return nil }) ctx, cancel := context.WithCancel(context.Background()) defer cancel() s.Start(ctx) defer s.Stop() done, err := s.RunNow("fill-watch") if err != nil { t.Fatalf("RunNow(fill-watch): %v", err) } select { case jerr := <-done: if jerr != nil { t.Fatalf("job error = %v", jerr) } case <-time.After(5 * time.Second): t.Fatal("RunNow never completed") } if calls != 1 || !sawOnDemand { t.Fatalf("calls=%d onDemand=%v, want 1 and true", calls, sawOnDemand) } if j := s.GetJobs()[0]; j.Running || j.LastRun.IsZero() { t.Fatalf("after RunNow: Running=%v LastRun=%v — want false and set", j.Running, j.LastRun) } } func TestRunNow_RefusesUnknownRunningAndUnstarted(t *testing.T) { s := discardScheduler() release := make(chan struct{}) s.Daily("offsite-integrity", farFuture(5), func(ctx context.Context) error { <-release; return nil }) if _, err := s.RunNow("offsite-integrity"); !errors.Is(err, ErrNotStarted) { t.Fatalf("before Start: err=%v, want ErrNotStarted", err) } ctx, cancel := context.WithCancel(context.Background()) defer cancel() s.Start(ctx) defer s.Stop() if _, err := s.RunNow("no-such-job"); !errors.Is(err, ErrUnknownJob) { t.Fatalf("unknown: err=%v, want ErrUnknownJob", err) } done, err := s.RunNow("offsite-integrity") if err != nil { t.Fatalf("first RunNow: %v", err) } if _, err := s.RunNow("offsite-integrity"); !errors.Is(err, ErrJobRunning) { t.Fatalf("second RunNow while running: err=%v, want ErrJobRunning", err) } close(release) <-done // Released: it may run again. done2, err := s.RunNow("offsite-integrity") if err != nil { t.Fatalf("RunNow after completion: %v", err) } <-done2 }