package jobdef import ( "os" "path/filepath" "testing" ) func TestLoadValid(t *testing.T) { dir := t.TempDir() content := ` job: name: test-job version: 1 description: "A test job" trigger: type: manual scope: type: item compute: type: validate command: create-validate runner: tags: [create] timeout: 300 max_retries: 2 priority: 50 ` path := filepath.Join(dir, "test-job.yaml") if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("writing test file: %v", err) } def, err := Load(path) if err != nil { t.Fatalf("Load: %v", err) } if def.Name != "test-job" { t.Errorf("name = %q, want %q", def.Name, "test-job") } if def.Version != 1 { t.Errorf("version = %d, want 1", def.Version) } if def.Trigger.Type != "manual" { t.Errorf("trigger type = %q, want %q", def.Trigger.Type, "manual") } if def.Scope.Type != "item" { t.Errorf("scope type = %q, want %q", def.Scope.Type, "item") } if def.Compute.Type != "validate" { t.Errorf("compute type = %q, want %q", def.Compute.Type, "validate") } if def.Compute.Command != "create-validate" { t.Errorf("compute command = %q, want %q", def.Compute.Command, "create-validate") } if len(def.Runner.Tags) != 1 || def.Runner.Tags[0] != "create" { t.Errorf("runner tags = %v, want [create]", def.Runner.Tags) } if def.Timeout != 300 { t.Errorf("timeout = %d, want 300", def.Timeout) } if def.MaxRetries != 2 { t.Errorf("max_retries = %d, want 2", def.MaxRetries) } if def.Priority != 50 { t.Errorf("priority = %d, want 50", def.Priority) } } func TestLoadDefaults(t *testing.T) { dir := t.TempDir() content := ` job: name: minimal trigger: type: manual scope: type: item compute: type: custom command: do-something ` path := filepath.Join(dir, "minimal.yaml") if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("writing test file: %v", err) } def, err := Load(path) if err != nil { t.Fatalf("Load: %v", err) } if def.Timeout != 600 { t.Errorf("default timeout = %d, want 600", def.Timeout) } if def.MaxRetries != 1 { t.Errorf("default max_retries = %d, want 1", def.MaxRetries) } if def.Priority != 100 { t.Errorf("default priority = %d, want 100", def.Priority) } if def.Version != 1 { t.Errorf("default version = %d, want 1", def.Version) } } func TestLoadInvalidTriggerType(t *testing.T) { dir := t.TempDir() content := ` job: name: bad-trigger trigger: type: invalid_trigger scope: type: item compute: type: validate command: create-validate ` path := filepath.Join(dir, "bad.yaml") if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("writing test file: %v", err) } _, err := Load(path) if err == nil { t.Fatal("expected error for invalid trigger type") } } func TestLoadMissingName(t *testing.T) { dir := t.TempDir() content := ` job: trigger: type: manual scope: type: item compute: type: validate command: create-validate ` path := filepath.Join(dir, "no-name.yaml") if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("writing test file: %v", err) } _, err := Load(path) if err == nil { t.Fatal("expected error for missing name") } } func TestLoadMissingCommand(t *testing.T) { dir := t.TempDir() content := ` job: name: no-command trigger: type: manual scope: type: item compute: type: validate ` path := filepath.Join(dir, "no-cmd.yaml") if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("writing test file: %v", err) } _, err := Load(path) if err == nil { t.Fatal("expected error for missing command") } } func TestLoadAllDirectory(t *testing.T) { dir := t.TempDir() job1 := ` job: name: job-one trigger: type: manual scope: type: item compute: type: validate command: create-validate ` job2 := ` job: name: job-two trigger: type: revision_created scope: type: assembly compute: type: export command: create-export ` if err := os.WriteFile(filepath.Join(dir, "one.yaml"), []byte(job1), 0644); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "two.yml"), []byte(job2), 0644); err != nil { t.Fatal(err) } // Non-YAML file should be ignored if err := os.WriteFile(filepath.Join(dir, "readme.txt"), []byte("ignore me"), 0644); err != nil { t.Fatal(err) } defs, err := LoadAll(dir) if err != nil { t.Fatalf("LoadAll: %v", err) } if len(defs) != 2 { t.Fatalf("loaded %d definitions, want 2", len(defs)) } if _, ok := defs["job-one"]; !ok { t.Error("job-one not found") } if _, ok := defs["job-two"]; !ok { t.Error("job-two not found") } } func TestLoadAllEmptyDirectory(t *testing.T) { dir := t.TempDir() defs, err := LoadAll(dir) if err != nil { t.Fatalf("LoadAll: %v", err) } if len(defs) != 0 { t.Errorf("loaded %d definitions from empty dir, want 0", len(defs)) } } func TestLoadWithFilter(t *testing.T) { dir := t.TempDir() content := ` job: name: filtered-job trigger: type: revision_created filter: item_type: assembly scope: type: assembly compute: type: validate command: create-validate ` path := filepath.Join(dir, "filtered.yaml") if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("writing test file: %v", err) } def, err := Load(path) if err != nil { t.Fatalf("Load: %v", err) } if def.Trigger.Filter["item_type"] != "assembly" { t.Errorf("filter item_type = %q, want %q", def.Trigger.Filter["item_type"], "assembly") } } func TestLoadWithArgs(t *testing.T) { dir := t.TempDir() content := ` job: name: args-job trigger: type: manual scope: type: item compute: type: export command: create-export args: format: step include_mesh: true ` path := filepath.Join(dir, "args.yaml") if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("writing test file: %v", err) } def, err := Load(path) if err != nil { t.Fatalf("Load: %v", err) } if def.Compute.Args["format"] != "step" { t.Errorf("args format = %v, want %q", def.Compute.Args["format"], "step") } if def.Compute.Args["include_mesh"] != true { t.Errorf("args include_mesh = %v, want true", def.Compute.Args["include_mesh"]) } } func TestValidateInvalidScopeType(t *testing.T) { d := &Definition{ Name: "test", Trigger: TriggerConfig{Type: "manual"}, Scope: ScopeConfig{Type: "galaxy"}, Compute: ComputeConfig{Type: "validate", Command: "create-validate"}, } if err := d.Validate(); err == nil { t.Fatal("expected error for invalid scope type") } } func TestValidateInvalidComputeType(t *testing.T) { d := &Definition{ Name: "test", Trigger: TriggerConfig{Type: "manual"}, Scope: ScopeConfig{Type: "item"}, Compute: ComputeConfig{Type: "teleport", Command: "beam-up"}, } if err := d.Validate(); err == nil { t.Fatal("expected error for invalid compute type") } }