ananke/testing/config/config_quality_matrix_test.go

239 lines
7.8 KiB
Go
Raw Normal View History

package config
import (
"os"
"path/filepath"
"strings"
"testing"
icfg "scm.bstein.dev/bstein/ananke/internal/config"
)
func loadBaselineConfig(t *testing.T) icfg.Config {
t.Helper()
dir := t.TempDir()
path := filepath.Join(dir, "ananke.yaml")
if err := os.WriteFile(path, []byte("ups:\n enabled: false\n"), 0o600); err != nil {
t.Fatalf("write baseline config: %v", err)
}
cfg, err := icfg.Load(path)
if err != nil {
t.Fatalf("load baseline config: %v", err)
}
return cfg
}
// TestHookServiceCatalogAndMergeContracts runs one orchestration or CLI step.
// Signature: TestHookServiceCatalogAndMergeContracts(t *testing.T).
// Why: validates startup checklist defaults and merge semantics so host-level
// overrides cannot silently drop required service behavior checks.
func TestHookServiceCatalogAndMergeContracts(t *testing.T) {
checks := icfg.TestHookDefaultServiceChecklist()
if len(checks) < 20 {
t.Fatalf("expected substantial default checklist, got %d checks", len(checks))
}
seen := map[string]icfg.ServiceChecklistCheck{}
for _, check := range checks {
seen[strings.TrimSpace(check.Name)] = check
}
logging, ok := seen["logging-ui-user-session"]
if !ok || !logging.RequireRobotAuth || strings.TrimSpace(logging.FinalURLNotContains) == "" {
t.Fatalf("expected logging-ui-user-session to require robot auth + final URL validation")
}
keycloak, ok := seen["keycloak-admin-user-session"]
if !ok || !keycloak.RequireRobotAuth || strings.TrimSpace(keycloak.FinalURLNotContains) == "" {
t.Fatalf("expected keycloak-admin-user-session hard auth assertions")
}
critical := icfg.TestHookDefaultCriticalServiceEndpoints()
if len(critical) == 0 {
t.Fatalf("expected critical endpoint defaults")
}
foundMonitoring := false
for _, entry := range critical {
if entry == "monitoring/grafana" {
foundMonitoring = true
break
}
}
if !foundMonitoring {
t.Fatalf("expected monitoring/grafana critical endpoint default")
}
mergedChecks := icfg.TestHookMergeServiceChecklistDefaults(
[]icfg.ServiceChecklistCheck{
{Name: "custom", URL: "https://custom.bstein.dev/", TimeoutSeconds: 5},
{Name: "logging-ui-user-session", URL: "https://override.invalid/", TimeoutSeconds: 5},
},
[]icfg.ServiceChecklistCheck{
{Name: "logging-ui-user-session", URL: "https://logs.bstein.dev/", TimeoutSeconds: 5},
{Name: "metrics-ui-user-session", URL: "https://metrics.bstein.dev/", TimeoutSeconds: 5},
},
)
if len(mergedChecks) != 3 {
t.Fatalf("expected 3 merged checks with dedupe, got %d", len(mergedChecks))
}
mergedStrings := icfg.TestHookMergeStringDefaults(
[]string{" one ", "one", "", "two"},
[]string{"two", "three", " "},
)
if strings.Join(mergedStrings, ",") != "one,two,three" {
t.Fatalf("unexpected merged string defaults: %v", mergedStrings)
}
}
// TestValidateServiceChecklistAuthContracts runs one orchestration or CLI step.
// Signature: TestValidateServiceChecklistAuthContracts(t *testing.T).
// Why: covers service-checklist auth and final-url validation branches that are
// critical for preventing false-positive startup success.
func TestValidateServiceChecklistAuthContracts(t *testing.T) {
t.Run("invalid auth mode", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.Mode = "bad-mode"
if err := cfg.Validate(); err == nil {
t.Fatalf("expected invalid mode validation error")
}
})
t.Run("invalid keycloak base url", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.KeycloakBaseURL = "://broken"
if err := cfg.Validate(); err == nil {
t.Fatalf("expected invalid keycloak base URL validation error")
}
})
t.Run("missing secret key fields", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.AdminSecretPasswordKey = ""
if err := cfg.Validate(); err == nil {
t.Fatalf("expected missing admin secret password key validation error")
}
})
t.Run("require robot auth with mode none", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.Mode = "none"
cfg.Startup.ServiceChecklist = append(cfg.Startup.ServiceChecklist, icfg.ServiceChecklistCheck{
Name: "robot-only",
URL: "https://logs.bstein.dev/",
RequireRobotAuth: true,
TimeoutSeconds: 5,
})
if err := cfg.Validate(); err == nil {
t.Fatalf("expected require_robot_auth + mode none validation error")
}
})
t.Run("final url markers without redirects", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.ServiceChecklist = append(cfg.Startup.ServiceChecklist, icfg.ServiceChecklistCheck{
Name: "final-url-invalid",
URL: "https://logs.bstein.dev/",
AcceptedStatuses: []int{200},
FinalURLContains: "/app/home",
TimeoutSeconds: 5,
})
if err := cfg.Validate(); err == nil {
t.Fatalf("expected final_url marker validation error when redirects disabled")
}
})
t.Run("invalid accepted status code", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.ServiceChecklist[0].AcceptedStatuses = []int{700}
if err := cfg.Validate(); err == nil {
t.Fatalf("expected invalid accepted status code error")
}
})
t.Run("required node label map contracts", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.RequiredNodeLabels = map[string]map[string]string{" ": {"k": "v"}}
if err := cfg.Validate(); err == nil {
t.Fatalf("expected empty required-node-label key error")
}
cfg = loadBaselineConfig(t)
cfg.Startup.RequiredNodeLabels = map[string]map[string]string{"titan-23": {}}
if err := cfg.Validate(); err == nil {
t.Fatalf("expected empty required-node-label map error")
}
cfg = loadBaselineConfig(t)
cfg.Startup.RequiredNodeLabels = map[string]map[string]string{"titan-23": {"zone": " "}}
if err := cfg.Validate(); err == nil {
t.Fatalf("expected empty required-node-label value error")
}
})
t.Run("missing auth fields", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.Realm = ""
if err := cfg.Validate(); err == nil {
t.Fatalf("expected missing realm error")
}
cfg = loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.RobotUsername = ""
if err := cfg.Validate(); err == nil {
t.Fatalf("expected missing robot username error")
}
cfg = loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.AdminSecretNamespace = ""
if err := cfg.Validate(); err == nil {
t.Fatalf("expected missing admin secret namespace error")
}
cfg = loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.AdminSecretName = ""
if err := cfg.Validate(); err == nil {
t.Fatalf("expected missing admin secret name error")
}
cfg = loadBaselineConfig(t)
cfg.Startup.ServiceChecklistAuth.AdminSecretUsernameKey = ""
if err := cfg.Validate(); err == nil {
t.Fatalf("expected missing admin secret username key error")
}
})
t.Run("service checklist missing url", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Startup.ServiceChecklist[0].URL = " "
if err := cfg.Validate(); err == nil {
t.Fatalf("expected missing checklist URL error")
}
})
t.Run("coordination and state contracts", func(t *testing.T) {
cfg := loadBaselineConfig(t)
cfg.Coordination.ForwardShutdownHost = "titan-24"
cfg.Coordination.ForwardShutdownConfig = ""
if err := cfg.Validate(); err == nil {
t.Fatalf("expected forward-shutdown config error")
}
cfg = loadBaselineConfig(t)
cfg.Coordination.PeerHosts = []string{"titan-24", " "}
if err := cfg.Validate(); err == nil {
t.Fatalf("expected peer host empty entry error")
}
cfg = loadBaselineConfig(t)
cfg.Coordination.Role = "invalid"
if err := cfg.Validate(); err == nil {
t.Fatalf("expected invalid coordination role error")
}
cfg = loadBaselineConfig(t)
cfg.State.ReportsDir = ""
if err := cfg.Validate(); err == nil {
t.Fatalf("expected state reports_dir required error")
}
})
}