ananke/cmd/ananke/builder_test.go

119 lines
4.0 KiB
Go

package main
import (
"io"
"log"
"os"
"path/filepath"
"testing"
)
// TestBuildOrchestratorCreatesStateDirs runs one orchestration or CLI step.
// Signature: TestBuildOrchestratorCreatesStateDirs(t *testing.T).
// Why: keeps behavior explicit so startup/shutdown workflows remain maintainable as services evolve.
func TestBuildOrchestratorCreatesStateDirs(t *testing.T) {
cfgPath := writeTestConfig(t)
logger := log.New(io.Discard, "", 0)
cfg, orch, err := buildOrchestrator(logger, cfgPath, true)
if err != nil {
t.Fatalf("buildOrchestrator failed: %v", err)
}
if orch == nil {
t.Fatalf("expected orchestrator instance")
}
if _, err := os.Stat(cfg.State.Dir); err != nil {
t.Fatalf("expected state dir %s: %v", cfg.State.Dir, err)
}
if _, err := os.Stat(cfg.State.ReportsDir); err != nil {
t.Fatalf("expected reports dir %s: %v", cfg.State.ReportsDir, err)
}
if filepath.Base(cfg.State.RunHistoryPath) != "runs.json" {
t.Fatalf("unexpected run history path: %s", cfg.State.RunHistoryPath)
}
}
// TestBuildOrchestratorFailsWhenStateDirIsFile runs one orchestration or CLI step.
// Signature: TestBuildOrchestratorFailsWhenStateDirIsFile(t *testing.T).
// Why: covers EnsureDir error path in orchestrator builder.
func TestBuildOrchestratorFailsWhenStateDirIsFile(t *testing.T) {
cfgPath := writeTestConfig(t)
stateFile := filepath.Join(t.TempDir(), "state-file")
if err := os.WriteFile(stateFile, []byte("x"), 0o600); err != nil {
t.Fatalf("write state file: %v", err)
}
// Build a minimal explicit config to avoid brittle string surgery.
raw := `control_planes: [titan-0a]
workers: [titan-04]
ssh_user: atlas
ssh_port: 2277
ssh_node_hosts:
titan-0a: 192.168.22.11
titan-04: 192.168.22.30
ssh_managed_nodes: [titan-0a, titan-04]
expected_flux_branch: main
expected_flux_source_url: ssh://git@scm.bstein.dev:2242/bstein/titan-iac.git
iac_repo_path: /tmp
ups:
enabled: false
state:
dir: ` + stateFile + `
reports_dir: ` + filepath.Join(stateFile, "reports") + `
run_history_path: ` + filepath.Join(stateFile, "runs.json") + `
lock_path: ` + filepath.Join(stateFile, "ananke.lock") + `
intent_path: ` + filepath.Join(stateFile, "intent.json") + `
`
if err := os.WriteFile(cfgPath, []byte(raw), 0o644); err != nil {
t.Fatalf("rewrite config: %v", err)
}
logger := log.New(io.Discard, "", 0)
if _, _, err := buildOrchestrator(logger, cfgPath, true); err == nil {
t.Fatalf("expected buildOrchestrator failure when state dir is a file")
}
}
// TestBuildOrchestratorFailsWhenReportsDirIsFile runs one orchestration or CLI step.
// Signature: TestBuildOrchestratorFailsWhenReportsDirIsFile(t *testing.T).
// Why: covers reports-dir EnsureDir error path in orchestrator builder.
func TestBuildOrchestratorFailsWhenReportsDirIsFile(t *testing.T) {
cfgPath := writeTestConfig(t)
stateDir := filepath.Join(t.TempDir(), "state")
if err := os.MkdirAll(stateDir, 0o755); err != nil {
t.Fatalf("mkdir state dir: %v", err)
}
reportsFile := filepath.Join(stateDir, "reports-file")
if err := os.WriteFile(reportsFile, []byte("x"), 0o600); err != nil {
t.Fatalf("write reports file: %v", err)
}
raw := `control_planes: [titan-0a]
workers: [titan-04]
ssh_user: atlas
ssh_port: 2277
ssh_node_hosts:
titan-0a: 192.168.22.11
titan-04: 192.168.22.30
ssh_managed_nodes: [titan-0a, titan-04]
expected_flux_branch: main
expected_flux_source_url: ssh://git@scm.bstein.dev:2242/bstein/titan-iac.git
iac_repo_path: /tmp
ups:
enabled: false
state:
dir: ` + stateDir + `
reports_dir: ` + reportsFile + `
run_history_path: ` + filepath.Join(stateDir, "runs.json") + `
lock_path: ` + filepath.Join(stateDir, "ananke.lock") + `
intent_path: ` + filepath.Join(stateDir, "intent.json") + `
`
if err := os.WriteFile(cfgPath, []byte(raw), 0o644); err != nil {
t.Fatalf("rewrite config: %v", err)
}
logger := log.New(io.Discard, "", 0)
if _, _, err := buildOrchestrator(logger, cfgPath, true); err == nil {
t.Fatalf("expected buildOrchestrator failure when reports dir is a file")
}
}