package config import "testing" // TestValidateRejectsInvalidFieldsMatrix runs one orchestration or CLI step. // Signature: TestValidateRejectsInvalidFieldsMatrix(t *testing.T). // Why: exercises validation branches so every config guardrail is test-covered. func TestValidateRejectsInvalidFieldsMatrix(t *testing.T) { base := defaults() base.UPS.Target = "pyrphoros@localhost" if err := base.Validate(); err != nil { t.Fatalf("test baseline config must validate: %v", err) } cases := []struct { name string mutate func(*Config) }{ {"empty_control_planes", func(c *Config) { c.ControlPlanes = nil }}, {"empty_expected_flux_branch", func(c *Config) { c.ExpectedFluxBranch = "" }}, {"empty_expected_flux_source", func(c *Config) { c.ExpectedFluxSource = "" }}, {"empty_iac_repo_path", func(c *Config) { c.IACRepoPath = "" }}, {"bad_shutdown_budget", func(c *Config) { c.Shutdown.DefaultBudgetSeconds = 0 }}, {"bad_shutdown_history_samples", func(c *Config) { c.Shutdown.HistoryMinSamples = 0 }}, {"bad_shutdown_emergency_budget", func(c *Config) { c.Shutdown.EmergencyBudgetSec = 0 }}, {"bad_shutdown_emergency_samples", func(c *Config) { c.Shutdown.EmergencyMinSamples = 0 }}, {"bad_drain_parallelism", func(c *Config) { c.Shutdown.DrainParallelism = 0 }}, {"bad_scale_parallelism", func(c *Config) { c.Shutdown.ScaleParallelism = 0 }}, {"bad_ssh_parallelism", func(c *Config) { c.Shutdown.SSHParallelism = 0 }}, {"bad_api_wait", func(c *Config) { c.Startup.APIWaitSeconds = 0 }}, {"bad_api_poll", func(c *Config) { c.Startup.APIPollSeconds = 0 }}, {"bad_min_battery_percent", func(c *Config) { c.Startup.MinimumBatteryPercent = 101 }}, {"bad_node_inventory_poll", func(c *Config) { c.Startup.NodeInventoryReachPollSeconds = 0 }}, {"bad_time_sync_wait", func(c *Config) { c.Startup.TimeSyncWaitSeconds = 0 }}, {"bad_time_sync_poll", func(c *Config) { c.Startup.TimeSyncPollSeconds = 0 }}, {"bad_time_sync_quorum", func(c *Config) { c.Startup.TimeSyncMode = "quorum"; c.Startup.TimeSyncQuorum = 0 }}, {"bad_storage_wait", func(c *Config) { c.Startup.StorageReadyWaitSeconds = 0 }}, {"bad_storage_poll", func(c *Config) { c.Startup.StorageReadyPollSeconds = 0 }}, {"bad_storage_min_ready_nodes", func(c *Config) { c.Startup.StorageMinReadyNodes = 0 }}, {"bad_post_start_wait", func(c *Config) { c.Startup.PostStartProbeWaitSeconds = 0 }}, {"bad_post_start_poll", func(c *Config) { c.Startup.PostStartProbePollSeconds = 0 }}, {"bad_service_checklist_wait", func(c *Config) { c.Startup.ServiceChecklistWaitSeconds = 0 }}, {"bad_service_checklist_poll", func(c *Config) { c.Startup.ServiceChecklistPollSeconds = 0 }}, {"bad_service_checklist_stability", func(c *Config) { c.Startup.ServiceChecklistStabilitySec = -1 }}, {"bad_service_checklist_item_name", func(c *Config) { c.Startup.ServiceChecklist = []ServiceChecklistCheck{{Name: "", URL: "https://ok", TimeoutSeconds: 5}} }}, {"bad_service_checklist_item_timeout", func(c *Config) { c.Startup.ServiceChecklist = []ServiceChecklistCheck{{Name: "x", URL: "https://ok", TimeoutSeconds: 0}} }}, {"bad_service_checklist_http_code", func(c *Config) { c.Startup.ServiceChecklist = []ServiceChecklistCheck{{Name: "x", URL: "https://ok", TimeoutSeconds: 5, AcceptedStatuses: []int{999}}} }}, {"bad_critical_endpoint_wait", func(c *Config) { c.Startup.CriticalServiceEndpointWaitSec = 0 }}, {"bad_critical_endpoint_poll", func(c *Config) { c.Startup.CriticalServiceEndpointPollSec = 0 }}, {"bad_empty_critical_endpoints_when_required", func(c *Config) { c.Startup.RequireCriticalServiceEndpoints = true c.Startup.CriticalServiceEndpoints = nil }}, {"bad_empty_critical_endpoint_entry", func(c *Config) { c.Startup.CriticalServiceEndpoints = []string{"", "monitoring/victoria-metrics-single-server"} }}, {"bad_malformed_critical_endpoint_entry", func(c *Config) { c.Startup.CriticalServiceEndpoints = []string{"monitoring-victoria-metrics-single-server"} }}, {"bad_ingress_wait", func(c *Config) { c.Startup.IngressChecklistWaitSeconds = 0 }}, {"bad_ingress_poll", func(c *Config) { c.Startup.IngressChecklistPollSeconds = 0 }}, {"bad_ingress_http_code", func(c *Config) { c.Startup.IngressChecklistAccepted = []int{700} }}, {"bad_ingress_ignore_entry", func(c *Config) { c.Startup.IngressChecklistIgnoreHosts = []string{"", "grafana.bstein.dev"} }}, {"bad_node_ssh_wait", func(c *Config) { c.Startup.NodeSSHAuthWaitSeconds = 0 }}, {"bad_node_ssh_poll", func(c *Config) { c.Startup.NodeSSHAuthPollSeconds = 0 }}, {"bad_flux_wait", func(c *Config) { c.Startup.FluxHealthWaitSeconds = 0 }}, {"bad_flux_poll", func(c *Config) { c.Startup.FluxHealthPollSeconds = 0 }}, {"bad_workload_wait", func(c *Config) { c.Startup.WorkloadConvergenceWaitSeconds = 0 }}, {"bad_workload_poll", func(c *Config) { c.Startup.WorkloadConvergencePollSeconds = 0 }}, {"bad_stuck_pod_grace", func(c *Config) { c.Startup.StuckPodGraceSeconds = 0 }}, {"bad_empty_post_start_probe_entry", func(c *Config) { c.Startup.PostStartProbes = []string{"https://ok", ""} }}, {"bad_empty_ignore_flux_entry", func(c *Config) { c.Startup.IgnoreFluxKustomizations = []string{"", "ns/name"} }}, {"bad_empty_ignore_workloads_entry", func(c *Config) { c.Startup.IgnoreWorkloads = []string{"", "ns/name"} }}, {"bad_empty_ignore_workload_namespaces_entry", func(c *Config) { c.Startup.IgnoreWorkloadNamespaces = []string{"", "vault"} }}, {"bad_empty_ignore_unavailable_nodes_entry", func(c *Config) { c.Startup.IgnoreUnavailableNodes = []string{"", "titan-22"} }}, {"bad_empty_vault_key_file", func(c *Config) { c.Startup.VaultUnsealKeyFile = "" }}, {"bad_ssh_port_low", func(c *Config) { c.SSHPort = 0 }}, {"bad_ups_provider", func(c *Config) { c.UPS.Enabled = true; c.UPS.Provider = "" }}, {"bad_ups_target_empty", func(c *Config) { c.UPS.Enabled = true; c.UPS.Provider = "nut"; c.UPS.Target = ""; c.UPS.Targets = nil }}, {"bad_ups_targets_item_empty", func(c *Config) { c.UPS.Enabled = true c.UPS.Provider = "nut" c.UPS.Target = "" c.UPS.Targets = []UPSTarget{{Name: "x", Target: ""}} }}, {"bad_startup_guard_age", func(c *Config) { c.Coordination.StartupGuardMaxAgeSec = 0 }}, {"bad_state_run_history_path", func(c *Config) { c.State.RunHistoryPath = "" }}, {"bad_state_intent_path", func(c *Config) { c.State.IntentPath = "" }}, } for _, tc := range cases { tc := tc t.Run(tc.name, func(t *testing.T) { cfg := base tc.mutate(&cfg) if err := cfg.Validate(); err == nil { t.Fatalf("expected validation error for %s", tc.name) } }) } } // TestApplyDefaultsPopulatesZeroConfig runs one orchestration or CLI step. // Signature: TestApplyDefaultsPopulatesZeroConfig(t *testing.T). // Why: validates that defaulting logic fills all critical runtime values. func TestApplyDefaultsPopulatesZeroConfig(t *testing.T) { var cfg Config cfg.ControlPlanes = []string{"titan-0a", "titan-0b", "titan-0c"} cfg.applyDefaults() if cfg.ExpectedFluxBranch == "" || cfg.ExpectedFluxSource == "" || cfg.IACRepoPath == "" { t.Fatalf("expected core defaults to be set") } if cfg.State.Dir == "" || cfg.State.ReportsDir == "" || cfg.State.RunHistoryPath == "" || cfg.State.LockPath == "" || cfg.State.IntentPath == "" { t.Fatalf("expected state defaults to be set") } if cfg.Startup.TimeSyncMode == "" || cfg.Startup.EtcdRestoreControlPlane == "" || cfg.Startup.VaultUnsealKeyFile == "" { t.Fatalf("expected startup defaults to be set") } if cfg.Startup.CriticalServiceEndpointWaitSec <= 0 || cfg.Startup.CriticalServiceEndpointPollSec <= 0 { t.Fatalf("expected critical service endpoint timing defaults to be set") } if len(cfg.Startup.CriticalServiceEndpoints) == 0 { t.Fatalf("expected critical service endpoint defaults to be set") } if cfg.Shutdown.SSHParallelism <= 0 || cfg.Shutdown.ScaleParallelism <= 0 || cfg.Shutdown.DrainParallelism <= 0 { t.Fatalf("expected shutdown parallelism defaults to be set") } } // TestValidateAcceptsFullySpecifiedConfig runs one orchestration or CLI step. // Signature: TestValidateAcceptsFullySpecifiedConfig(t *testing.T). // Why: covers success branches for forward-shutdown and UPS target validation. func TestValidateAcceptsFullySpecifiedConfig(t *testing.T) { cfg := defaults() cfg.UPS.Target = "pyrphoros@localhost" cfg.Coordination.ForwardShutdownHost = "titan-db" cfg.Coordination.ForwardShutdownConfig = "/etc/ananke/ananke.yaml" cfg.Coordination.PeerHosts = []string{"titan-24"} if err := cfg.Validate(); err != nil { t.Fatalf("expected fully specified config to validate: %v", err) } }