Files
orca/internal/emitter/systemd_restart_test.go
T
Jon Chery cf3d98eb2b feat(P03): wire scheduler into job run + fix jobspec parser (REQ-151, REQ-152)
R-022: orca job run now deploys to remote nodes via scheduler -> emitter
-> SSH-push. Local exec fallback only when no remote nodes registered.

jobspec parser (REQ-152):
- schedule: and timeout: now parsed (were silently dropped)
- DaemonSet Count no longer defaults to 1 (was breaking DaemonSet)
- restart: policy translated to systemd Restart=/StartLimitBurst
- job lint: advisory warnings for cron/health/update/affinity (honest)

scheduler wiring (REQ-151, C-44):
- new internal/cli/job_dispatch.go: dispatchDecision + deployRemote
- scheduler.Schedule evaluates constraints/capacity/affinity
- --target overrides scheduler (manual pinning)
- local fallback only when len(ready non-localhost nodes)==0
- C-44: SSH-push failure returns error (no silent local fallback)
- systemd-analyze verify on rendered unit before deploy

Tests: 22 new test functions covering scheduler, parser, C-44, local
fallback, target override, systemd-analyze skip, restart directives.

---ci---
project: orca
phase: 3
milestone: v0.13
status: complete
requirements:
  covered: [151, 152]
---/ci---
2026-08-07 19:59:31 +00:00

86 lines
2.4 KiB
Go

package emitter
import (
"strings"
"testing"
"git.cloudinit.dev/coreci/orca/internal/jobspec"
)
func TestSystemdEmitter_RestartNever(t *testing.T) {
spec := &jobspec.WorkloadSpec{
Kind: "Job",
Name: "one",
Runtime: &jobspec.RuntimeBlock{OneOf: "process", Command: "/bin/true"},
Restart: &jobspec.RestartBlock{Mode: "never"},
}
files, err := SystemdEmitter{}.Render(spec, &Node{Hostname: "n"})
if err != nil {
t.Fatalf("Render: %v", err)
}
if !strings.Contains(files[0].Content, "Restart=no") {
t.Errorf("missing Restart=no:\n%s", files[0].Content)
}
}
func TestSystemdEmitter_RestartOnFailure(t *testing.T) {
spec := &jobspec.WorkloadSpec{
Kind: "Job",
Name: "retry",
Runtime: &jobspec.RuntimeBlock{OneOf: "process", Command: "/bin/true"},
Restart: &jobspec.RestartBlock{Mode: "on-failure", MaxRetries: 3, Delay: "5s"},
}
files, err := SystemdEmitter{}.Render(spec, &Node{Hostname: "n"})
if err != nil {
t.Fatalf("Render: %v", err)
}
c := files[0].Content
if !strings.Contains(c, "Restart=on-failure") {
t.Errorf("missing Restart=on-failure:\n%s", c)
}
if !strings.Contains(c, "StartLimitBurst=3") {
t.Errorf("missing StartLimitBurst=3:\n%s", c)
}
if !strings.Contains(c, "RestartSec=5s") {
t.Errorf("missing RestartSec=5s:\n%s", c)
}
if !strings.Contains(c, "StartLimitIntervalSec=5s") {
t.Errorf("missing StartLimitIntervalSec=5s:\n%s", c)
}
}
func TestSystemdEmitter_RestartService(t *testing.T) {
spec := &jobspec.WorkloadSpec{
Kind: "Service",
Name: "web",
Runtime: &jobspec.RuntimeBlock{OneOf: "process", Command: "/bin/httpd"},
Restart: &jobspec.RestartBlock{Mode: "service", MaxRetries: 5, Delay: "10s"},
}
files, err := SystemdEmitter{}.Render(spec, &Node{Hostname: "n"})
if err != nil {
t.Fatalf("Render: %v", err)
}
c := files[0].Content
if !strings.Contains(c, "Restart=always") {
t.Errorf("missing Restart=always:\n%s", c)
}
if !strings.Contains(c, "StartLimitBurst=5") {
t.Errorf("missing StartLimitBurst=5:\n%s", c)
}
}
func TestSystemdEmitter_RestartNilOmitted(t *testing.T) {
spec := &jobspec.WorkloadSpec{
Kind: "Job",
Name: "norest",
Runtime: &jobspec.RuntimeBlock{OneOf: "process", Command: "/bin/true"},
}
files, err := SystemdEmitter{}.Render(spec, &Node{Hostname: "n"})
if err != nil {
t.Fatalf("Render: %v", err)
}
if strings.Contains(files[0].Content, "Restart=") {
t.Errorf("nil Restart should omit Restart= line:\n%s", files[0].Content)
}
}