package job import ( "log/slog" "testing" "time" ) func TestConfigValidate(t *testing.T) { tests := []struct { name string config Config wantErr bool }{ { name: "empty config", config: Config{}, wantErr: true, }, { name: "missing name", config: Config{ Schedule: "0 9 * * *", Task: "do something", }, wantErr: true, }, { name: "missing task", config: Config{ Name: "test", Schedule: "0 9 * * *", }, wantErr: true, }, { name: "missing schedule", config: Config{ Name: "test", Task: "do something", }, wantErr: true, }, { name: "negative max iterations", config: Config{ Name: "test", Task: "do something", Schedule: "0 9 * * *", MaxIterations: -1, }, wantErr: true, }, { name: "minimal valid config", config: Config{ Name: "test", Task: "do something", Schedule: "0 9 * * *", }, wantErr: false, }, { name: "full valid config", config: Config{ Name: "test", Task: "do something", Schedule: "0 9 * * *", Timeout: "10m", MaxIterations: 20, SystemMessage: "You are an assistant.", }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.config.Validate() if (err != nil) != tt.wantErr { t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) } }) } } func TestConfigIsEnabled(t *testing.T) { // nil enabled → defaults to true cfg := Config{Name: "test"} if !cfg.IsEnabled() { t.Error("expected nil enabled to be true") } // explicit true enabled := true cfg.Enabled = &enabled if !cfg.IsEnabled() { t.Error("expected explicit true") } // explicit false disabled := false cfg.Enabled = &disabled if cfg.IsEnabled() { t.Error("expected explicit false") } } func TestConfigMaxIterations(t *testing.T) { // Zero means unlimited cfg := Config{Name: "test"} if got := cfg.MaxIterations; got != 0 { t.Errorf("default max iterations = %d, want 0", got) } cfg.MaxIterations = 0 if got := cfg.MaxIterations; got != 0 { t.Errorf("explicit zero max iterations = %d, want 0", got) } // Positive value passes through cfg.MaxIterations = 25 if got := cfg.MaxIterations; got != 25 { t.Errorf("custom max iterations = %d, want 25", got) } } func TestConfigTimeout(t *testing.T) { cfg := Config{Name: "test"} if cfg.Timeout != "" { t.Errorf("default timeout = %q, want empty", cfg.Timeout) } cfg.Timeout = "10m" got, err := time.ParseDuration(cfg.Timeout) if err != nil { t.Fatalf("ParseDuration(%q) error = %v", cfg.Timeout, err) } if got.Minutes() != 10 { t.Errorf("parsed timeout = %v, want 10m", got) } } func TestNew(t *testing.T) { cfg := Config{ Name: "test", Task: "do something", Schedule: "0 9 * * *", Timeout: "10m", MaxIterations: 20, SystemMessage: "You are an assistant.", } j, err := New(cfg, slog.Default(), nil) if err != nil { t.Fatalf("New() error = %v", err) } if j.Name() != "test" { t.Errorf("Name() = %q, want %q", j.Name(), "test") } if j.Schedule() != "0 9 * * *" { t.Errorf("Schedule() = %q, want %q", j.Schedule(), "0 9 * * *") } if !j.IsEnabled() { t.Error("IsEnabled() = false, want true") } if j.SystemMessage() != "You are an assistant." { t.Errorf("SystemMessage() = %q, want %q", j.SystemMessage(), "You are an assistant.") } if j.Task() != "do something" { t.Errorf("Task() = %q, want %q", j.Task(), "do something") } if j.Timeout().Minutes() != 10 { t.Errorf("Timeout() = %v, want 10m", j.Timeout()) } if j.MaxIterations() != 20 { t.Errorf("MaxIterations() = %d, want 20", j.MaxIterations()) } if j.Cron() == nil { t.Error("Cron() = nil, want non-nil") } } func TestNew_Disabled(t *testing.T) { disabled := false cfg := Config{ Name: "test", Task: "do something", Schedule: "0 9 * * *", Enabled: &disabled, } j, err := New(cfg, slog.Default(), nil) if err != nil { t.Fatalf("New() error = %v", err) } if j.IsEnabled() { t.Error("IsEnabled() = true, want false") } } func TestNew_InvalidSchedule(t *testing.T) { cfg := Config{ Name: "test", Task: "do something", Schedule: "not-a-cron", } _, err := New(cfg, slog.Default(), nil) if err == nil { t.Fatal("New() expected error for invalid schedule") } } func TestNew_InvalidTimeout(t *testing.T) { cfg := Config{ Name: "test", Task: "do something", Schedule: "0 9 * * *", Timeout: "not-a-duration", } _, err := New(cfg, slog.Default(), nil) if err == nil { t.Fatal("New() expected error for invalid timeout") } }