package jobspec import ( "testing" ) func TestREQ152_ScheduleTimeoutDaemonSet(t *testing.T) { input := "---\n" + "kind: DaemonSet\n" + "name: logs\n" + "schedule:\n" + " mode: every-node\n" + " cron: \"*/5 * * * *\"\n" + "timeout: 30s\n" + "restart:\n" + " mode: service\n" + "runtime:\n" + " one_of: process\n" + " command: /bin/true\n" + "---\nbody\n" spec, err := ParseMarkdown([]byte(input)) if err != nil { t.Fatalf("ParseMarkdown: %v", err) } if spec.Count != 0 { t.Errorf("DaemonSet Count = %d, want 0 (no default)", spec.Count) } if spec.Schedule == nil { t.Fatal("Schedule is nil") } if spec.Schedule.Mode != "every-node" { t.Errorf("Schedule.Mode = %q, want every-node", spec.Schedule.Mode) } if spec.Schedule.Cron != "*/5 * * * *" { t.Errorf("Schedule.Cron = %q, want */5 * * * *", spec.Schedule.Cron) } if spec.Timeout != "30s" { t.Errorf("Timeout = %q, want 30s", spec.Timeout) } } func TestREQ152_JobScheduleTimeout(t *testing.T) { input := "---\n" + "kind: Job\n" + "name: nightly\n" + "schedule:\n" + " cron: \"0 2 * * *\"\n" + "timeout: 1h\n" + "runtime:\n" + " one_of: process\n" + " command: /bin/true\n" + "---\nbody\n" spec, err := ParseMarkdown([]byte(input)) if err != nil { t.Fatalf("ParseMarkdown: %v", err) } if spec.Count != 1 { t.Errorf("Job Count = %d, want 1 (default)", spec.Count) } if spec.Schedule == nil || spec.Schedule.Cron != "0 2 * * *" { t.Errorf("Schedule.Cron = %+v, want 0 2 * * *", spec.Schedule) } if spec.Timeout != "1h" { t.Errorf("Timeout = %q, want 1h", spec.Timeout) } } // TestREQ152_DaemonSetPassesLint verifies a DaemonSet spec with a // schedule block, restart, and runtime parses AND validates cleanly // under the schema (T11). DaemonSet must NOT default Count to 1. func TestREQ152_DaemonSetPassesLint(t *testing.T) { input := "---\n" + "kind: DaemonSet\n" + "name: log-shipper\n" + "schedule:\n" + " mode: every-node\n" + "restart:\n" + " mode: service\n" + " max_retries: 5\n" + " delay: 5s\n" + "runtime:\n" + " one_of: process\n" + " command: /usr/local/bin/log-shipper\n" + "---\n# Log shipper\n\nRuns on every node.\n" spec, err := ParseMarkdown([]byte(input)) if err != nil { t.Fatalf("ParseMarkdown: %v", err) } if spec.Count != 0 { t.Errorf("DaemonSet Count = %d, want 0", spec.Count) } if spec.Schedule == nil || spec.Schedule.Mode != "every-node" { t.Errorf("Schedule.Mode = %+v, want every-node", spec.Schedule) } if spec.Restart == nil || spec.Restart.Mode != "service" { t.Errorf("Restart.Mode = %+v, want service", spec.Restart) } } // TestREQ152_TimeoutEnforced verifies the timeout field is parsed and // stored on the WorkloadSpec (T12). func TestREQ152_TimeoutEnforced(t *testing.T) { cases := []struct { timeout string want string }{ {"30s", "30s"}, {"5m", "5m"}, {"1h30m", "1h30m"}, {"900s", "900s"}, } for _, c := range cases { input := "---\nkind: Job\nname: t\ntimeout: " + c.timeout + "\nruntime:\n one_of: process\n command: /bin/true\n---\nbody\n" spec, err := ParseMarkdown([]byte(input)) if err != nil { t.Fatalf("ParseMarkdown(%q): %v", c.timeout, err) } if spec.Timeout != c.want { t.Errorf("Timeout = %q, want %q", spec.Timeout, c.want) } } } // TestREQ152_DaemonSetExplicitCountRejected verifies that an explicit // count on a DaemonSet is preserved (parser does not override it) so // the validator can reject it. func TestREQ152_DaemonSetExplicitCountPreserved(t *testing.T) { input := "---\nkind: DaemonSet\nname: d\ncount: 3\nschedule:\n mode: every-node\nrestart:\n mode: service\nruntime:\n one_of: process\n command: /bin/true\n---\nbody\n" spec, err := ParseMarkdown([]byte(input)) if err != nil { t.Fatalf("ParseMarkdown: %v", err) } if spec.Count != 3 { t.Errorf("DaemonSet explicit Count = %d, want 3 (preserved, not defaulted)", spec.Count) } }