2026-04-08 23:52:29 -03:00
package orchestrator
import (
"context"
"errors"
"io"
"log"
"net/http"
"net/http/httptest"
neturl "net/url"
"os"
"path/filepath"
"strings"
"testing"
"time"
"scm.bstein.dev/bstein/ananke/internal/cluster"
"scm.bstein.dev/bstein/ananke/internal/config"
"scm.bstein.dev/bstein/ananke/internal/execx"
"scm.bstein.dev/bstein/ananke/internal/state"
)
// TestHookGapMatrixPart5CoverageClosure runs one orchestration or CLI step.
// Signature: TestHookGapMatrixPart5CoverageClosure(t *testing.T).
// Why: closes branch gaps that still remained after drill-style tests by driving
// low-coverage orchestrator internals through the exported top-level hook surface.
func TestHookGapMatrixPart5CoverageClosure ( t * testing . T ) {
t . Run ( "critical-endpoint-backend-heal-matrix" , func ( t * testing . T ) {
t . Run ( "empty-namespace-service-noop" , func ( t * testing . T ) {
orch , _ := newHookOrchestrator ( t , lifecycleConfig ( t ) , nil , nil )
healed , err := orch . TestHookMaybeHealCriticalEndpointBackends ( context . Background ( ) , "" , "" )
if err != nil || len ( healed ) != 0 {
t . Fatalf ( "expected empty noop heal, healed=%v err=%v" , healed , err )
}
} )
t . Run ( "scale-error-bubbles" , func ( t * testing . T ) {
run := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
if name == "kubectl" && strings . Contains ( command , " -n monitoring scale deployment grafana " ) {
return "" , errors . New ( "boom" )
}
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
orch , _ := newHookOrchestrator ( t , lifecycleConfig ( t ) , run , run )
_ , err := orch . TestHookMaybeHealCriticalEndpointBackends ( context . Background ( ) , "monitoring" , "grafana" )
if err == nil || ! strings . Contains ( err . Error ( ) , "scale monitoring/deployment/grafana to 1" ) {
t . Fatalf ( "expected deployment scale error, got %v" , err )
}
} )
t . Run ( "deployment-notfound-statefulset-healed" , func ( t * testing . T ) {
run := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
switch {
case name == "kubectl" && strings . Contains ( command , " -n monitoring scale deployment grafana " ) :
return "" , errors . New ( "Error from server (NotFound): deployments.apps \"grafana\" not found" )
case name == "kubectl" && strings . Contains ( command , " -n monitoring scale statefulset grafana " ) :
return "" , nil
case name == "kubectl" && strings . Contains ( command , "rollout status statefulset/grafana" ) :
return "rolled out" , nil
default :
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
}
orch , _ := newHookOrchestrator ( t , lifecycleConfig ( t ) , run , run )
healed , err := orch . TestHookMaybeHealCriticalEndpointBackends ( context . Background ( ) , "monitoring" , "grafana" )
if err != nil {
t . Fatalf ( "expected statefulset fallback heal success, got %v" , err )
}
if len ( healed ) != 1 || healed [ 0 ] != "monitoring/statefulset/grafana" {
t . Fatalf ( "expected statefulset heal entry, got %v" , healed )
}
} )
} )
t . Run ( "ingress-backend-heal-and-stability-matrix" , func ( t * testing . T ) {
t . Run ( "ingress-host-heal-noop-and-error" , func ( t * testing . T ) {
cfg := lifecycleConfig ( t )
runNoop := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
switch {
case name == "kubectl" && strings . Contains ( command , "get ingress -A -o json" ) :
return ` { "items":[ { "metadata": { "namespace":"monitoring","name":"grafana"},"spec": { "rules":[ { "host":"other.bstein.dev"}]}}]} ` , nil
default :
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
}
orchNoop , _ := newHookOrchestrator ( t , cfg , runNoop , runNoop )
healed , err := orchNoop . TestHookHealIngressHostBackendReplicas ( context . Background ( ) , "metrics.bstein.dev" )
if err != nil || len ( healed ) != 0 {
t . Fatalf ( "expected no-op ingress heal, healed=%v err=%v" , healed , err )
}
runErr := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
switch {
case name == "kubectl" && strings . Contains ( command , "get ingress -A -o json" ) :
return ` { "items":[ { "metadata": { "namespace":"monitoring","name":"grafana"},"spec": { "rules":[ { "host":"metrics.bstein.dev"}]}}]} ` , nil
case name == "kubectl" && strings . Contains ( command , "get deploy,statefulset -A -o json" ) :
return ` { "items":[ { "kind":"Deployment","metadata": { "namespace":"monitoring","name":"grafana"},"spec": { "replicas":0}}]} ` , nil
case name == "kubectl" && strings . Contains ( command , " scale deployment grafana --replicas=1" ) :
return "" , errors . New ( "permission denied" )
default :
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
}
orchErr , _ := newHookOrchestrator ( t , cfg , runErr , runErr )
_ , err = orchErr . TestHookHealIngressHostBackendReplicas ( context . Background ( ) , "metrics.bstein.dev" )
if err == nil || ! strings . Contains ( err . Error ( ) , "scale monitoring/deployment/grafana to 1" ) {
t . Fatalf ( "expected ingress backend scale error, got %v" , err )
}
} )
t . Run ( "startup-stability-health-failure-branches" , func ( t * testing . T ) {
t . Run ( "flux-check-error" , func ( t * testing . T ) {
cfg := lifecycleConfig ( t )
cfg . Startup . RequireFluxHealth = true
cfg . Startup . RequireWorkloadConvergence = false
cfg . Startup . RequireServiceChecklist = false
cfg . Startup . RequireIngressChecklist = false
run := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
if name == "kubectl" && strings . Contains ( command , "get kustomizations.kustomize.toolkit.fluxcd.io -A -o json" ) {
return "" , errors . New ( "api down" )
}
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
orch , _ := newHookOrchestrator ( t , cfg , run , run )
if err := orch . TestHookStartupStabilityHealthy ( context . Background ( ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "flux check error" ) {
t . Fatalf ( "expected flux-check error branch, got %v" , err )
}
} )
t . Run ( "service-checklist-failure" , func ( t * testing . T ) {
srv := httptest . NewServer ( http . HandlerFunc ( httpStatusHandler ( 500 , "not ready" ) ) )
defer srv . Close ( )
cfg := lifecycleConfig ( t )
cfg . Startup . RequireFluxHealth = false
cfg . Startup . RequireWorkloadConvergence = false
cfg . Startup . RequireIngressChecklist = false
cfg . Startup . RequireServiceChecklist = true
cfg . Startup . ServiceChecklist = [ ] config . ServiceChecklistCheck {
{ Name : "svc" , URL : srv . URL , AcceptedStatuses : [ ] int { 200 } , TimeoutSeconds : 1 } ,
}
orch , _ := newHookOrchestrator ( t , cfg , nil , nil )
if err := orch . TestHookStartupStabilityHealthy ( context . Background ( ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "external services not healthy" ) {
t . Fatalf ( "expected service-check failure, got %v" , err )
}
} )
t . Run ( "ingress-checklist-failure" , func ( t * testing . T ) {
cfg := lifecycleConfig ( t )
cfg . Startup . RequireFluxHealth = false
cfg . Startup . RequireWorkloadConvergence = false
cfg . Startup . RequireServiceChecklist = false
cfg . Startup . RequireIngressChecklist = true
cfg . Startup . IngressChecklistInsecureSkip = true
run := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
if name == "kubectl" && strings . Contains ( command , "get ingress -A -o json" ) {
return ` { "items":[ { "metadata": { "namespace":"monitoring","name":"grafana"},"spec": { "rules":[ { "host":"nonexistent.invalid"}]}}]} ` , nil
}
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
orch , _ := newHookOrchestrator ( t , cfg , run , run )
if err := orch . TestHookStartupStabilityHealthy ( context . Background ( ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "ingress reachability not healthy" ) {
t . Fatalf ( "expected ingress-check failure, got %v" , err )
}
} )
t . Run ( "pod-failure-check-error-and-nonempty" , func ( t * testing . T ) {
cfg := lifecycleConfig ( t )
cfg . Startup . RequireFluxHealth = false
cfg . Startup . RequireWorkloadConvergence = false
cfg . Startup . RequireServiceChecklist = false
cfg . Startup . RequireIngressChecklist = false
runErr := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
if name == "kubectl" && strings . Contains ( command , "get pods -A -o json" ) {
return "" , errors . New ( "pods unavailable" )
}
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
orchErr , _ := newHookOrchestrator ( t , cfg , runErr , runErr )
if err := orchErr . TestHookStartupStabilityHealthy ( context . Background ( ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "pod failure check error" ) {
t . Fatalf ( "expected pod-check error branch, got %v" , err )
}
runFail := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
if name == "kubectl" && strings . Contains ( command , "get pods -A -o json" ) {
return ` { "items":[ { "metadata": { "namespace":"monitoring","name":"grafana-0","creationTimestamp":"2020-01-01T00:00:00Z","ownerReferences":[ { "kind":"ReplicaSet"}]},"spec": { "nodeName":"titan-23","containers":[ { "name":"grafana"}]},"status": { "containerStatuses":[ { "state": { "waiting": { "reason":"CrashLoopBackOff"}}}]}}]} ` , nil
}
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
orchFail , _ := newHookOrchestrator ( t , cfg , runFail , runFail )
if err := orchFail . TestHookStartupStabilityHealthy ( context . Background ( ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "pods in crash/image-pull failures" ) {
t . Fatalf ( "expected failing-pod branch, got %v" , err )
}
} )
} )
} )
t . Run ( "report-scaling-timesync-and-ssh-matrix" , func ( t * testing . T ) {
t . Run ( "report-artifact-and-progress-branches" , func ( t * testing . T ) {
cfg := lifecycleConfig ( t )
orch , _ := newHookOrchestrator ( t , cfg , nil , nil )
orch . TestHookNoteStartupAutoHeal ( "ignored without active report" )
orch . TestHookBeginStartupReport ( "drill" )
orch . TestHookNoteStartupAutoHeal ( "" )
orch . TestHookNoteStartupAutoHeal ( "restored critical workload replicas" )
orch . TestHookFinalizeStartupReport ( nil )
if err := orch . TestHookWriteRunRecordArtifact ( state . RunRecord {
ID : "shutdown-record-1" ,
Action : "shutdown" ,
Reason : "drill" ,
StartedAt : time . Now ( ) . UTC ( ) . Add ( - 3 * time . Second ) ,
EndedAt : time . Now ( ) . UTC ( ) ,
} ) ; err != nil {
t . Fatalf ( "expected shutdown run artifact success, got %v" , err )
}
if _ , err := os . Stat ( orch . TestHookLastShutdownReportPath ( ) ) ; err != nil {
t . Fatalf ( "expected last-shutdown report artifact, err=%v" , err )
}
stateFile := filepath . Join ( t . TempDir ( ) , "state-as-file" )
if err := os . WriteFile ( stateFile , [ ] byte ( "x" ) , 0 o644 ) ; err != nil {
t . Fatalf ( "seed state file: %v" , err )
}
badCfg := lifecycleConfig ( t )
badCfg . State . Dir = stateFile
badCfg . State . ReportsDir = filepath . Join ( stateFile , "reports" )
badCfg . State . RunHistoryPath = filepath . Join ( stateFile , "runs.json" )
bad := cluster . New ( badCfg , & execx . Runner { DryRun : false } , state . New ( badCfg . State . RunHistoryPath ) , log . New ( io . Discard , "" , 0 ) )
if err := bad . TestHookWriteStartupReportFile ( filepath . Join ( stateFile , "startup.json" ) , "running" ) ; err == nil {
t . Fatalf ( "expected startup report mkdir/write error" )
}
bad . TestHookPersistStartupProgress ( "running" )
bad . TestHookFinalizeRecord ( "shutdown" , "drill" , "simulated-failure" )
} )
t . Run ( "scaled-snapshot-write-and-restore-errors" , func ( t * testing . T ) {
listRun := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
switch {
case name == "kubectl" && strings . Contains ( command , "get deployment -A -o jsonpath=" ) :
return "monitoring\tgrafana\t1\n" , nil
case name == "kubectl" && strings . Contains ( command , "get statefulset -A -o jsonpath=" ) :
return "" , nil
case name == "kubectl" && strings . Contains ( command , " scale deployment grafana --replicas=1" ) :
return "" , nil
default :
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
}
stateAsFile := filepath . Join ( t . TempDir ( ) , "state-as-file" )
if err := os . WriteFile ( stateAsFile , [ ] byte ( "x" ) , 0 o644 ) ; err != nil {
t . Fatalf ( "seed state file: %v" , err )
}
cfgWriteErr := lifecycleConfig ( t )
cfgWriteErr . State . Dir = stateAsFile
orchWriteErr := cluster . New ( cfgWriteErr , & execx . Runner { DryRun : false } , state . New ( cfgWriteErr . State . RunHistoryPath ) , log . New ( io . Discard , "" , 0 ) )
orchWriteErr . SetCommandOverrides ( listRun , listRun )
entries , err := orchWriteErr . TestHookListScalableWorkloads ( context . Background ( ) )
if err != nil {
t . Fatalf ( "list entries for write-error case: %v" , err )
}
if err := orchWriteErr . TestHookWriteScaledWorkloadSnapshot ( entries ) ; err == nil {
t . Fatalf ( "expected write scaled snapshot error" )
}
cfgRemoveErr := lifecycleConfig ( t )
2026-04-09 04:56:41 -03:00
snapshotPath := filepath . Join ( cfgRemoveErr . State . Dir , "scaled-workloads.json" )
removeErrRun := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
switch {
case name == "kubectl" && strings . Contains ( command , "get deployment -A -o jsonpath=" ) :
return "monitoring\tgrafana\t1\n" , nil
case name == "kubectl" && strings . Contains ( command , "get statefulset -A -o jsonpath=" ) :
return "" , nil
case name == "kubectl" && strings . Contains ( command , " scale deployment grafana --replicas=1" ) :
if err := os . Remove ( snapshotPath ) ; err != nil && ! os . IsNotExist ( err ) {
return "" , err
}
if err := os . MkdirAll ( snapshotPath , 0 o755 ) ; err != nil {
return "" , err
}
if err := os . WriteFile ( filepath . Join ( snapshotPath , "keep" ) , [ ] byte ( "x" ) , 0 o644 ) ; err != nil {
return "" , err
}
return "" , nil
default :
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
}
orchRemoveErr , _ := newHookOrchestrator ( t , cfgRemoveErr , removeErrRun , removeErrRun )
2026-04-08 23:52:29 -03:00
entries , err = orchRemoveErr . TestHookListScalableWorkloads ( context . Background ( ) )
if err != nil {
t . Fatalf ( "list entries for remove-error case: %v" , err )
}
if err := orchRemoveErr . TestHookWriteScaledWorkloadSnapshot ( entries ) ; err != nil {
t . Fatalf ( "seed snapshot for remove-error case: %v" , err )
}
if err := orchRemoveErr . TestHookRestoreScaledApps ( context . Background ( ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "remove scaled workload snapshot" ) {
t . Fatalf ( "expected remove snapshot error, got %v" , err )
}
} )
t . Run ( "timesync-quorum-and-strict" , func ( t * testing . T ) {
build := func ( mode string , quorum int , local string , remote map [ string ] string ) * cluster . Orchestrator {
cfg := lifecycleConfig ( t )
cfg . ControlPlanes = [ ] string { "titan-db" , "titan-24" }
cfg . SSHManagedNodes = [ ] string { "titan-db" , "titan-24" }
cfg . SSHNodeHosts [ "titan-24" ] = "titan-24"
cfg . Startup . TimeSyncWaitSeconds = 1
cfg . Startup . TimeSyncPollSeconds = 1
cfg . Startup . TimeSyncMode = mode
cfg . Startup . TimeSyncQuorum = quorum
run := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
switch {
case name == "sh" && strings . Contains ( command , "timedatectl show -p NTPSynchronized" ) :
return local , nil
case name == "ssh" && strings . Contains ( command , "timedatectl show -p NTPSynchronized" ) :
for node , out := range remote {
if strings . Contains ( command , node ) {
return out , nil
}
}
return "no" , nil
default :
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
}
orch , _ := newHookOrchestrator ( t , cfg , run , run )
return orch
}
strict := build ( "strict" , 0 , "no" , map [ string ] string { "titan-db" : "no" , "titan-24" : "no" } )
if err := strict . TestHookWaitForTimeSync ( context . Background ( ) , [ ] string { "titan-db" , "titan-24" } ) ; err == nil || ! strings . Contains ( err . Error ( ) , "time sync not ready" ) {
t . Fatalf ( "expected strict-mode timeout, got %v" , err )
}
quorumOK := build ( "quorum" , 1 , "yes" , map [ string ] string { "titan-db" : "yes" , "titan-24" : "no" } )
if err := quorumOK . TestHookWaitForTimeSync ( context . Background ( ) , [ ] string { "titan-db" , "titan-24" } ) ; err != nil {
t . Fatalf ( "expected quorum-mode success, got %v" , err )
}
quorumFail := build ( "quorum" , 2 , "yes" , map [ string ] string { "titan-db" : "yes" , "titan-24" : "no" } )
if err := quorumFail . TestHookWaitForTimeSync ( context . Background ( ) , [ ] string { "titan-db" , "titan-24" } ) ; err == nil || ! strings . Contains ( err . Error ( ) , "time sync quorum not ready" ) {
t . Fatalf ( "expected quorum-mode timeout, got %v" , err )
}
} )
t . Run ( "poststart-and-ssh-helper-branches" , func ( t * testing . T ) {
cfg := lifecycleConfig ( t )
cfg . Startup . PostStartProbes = [ ] string { "https://metrics.bstein.dev/health" }
cfg . Startup . PostStartProbeWaitSeconds = 2
cfg . Startup . PostStartProbePollSeconds = 1
cfg . SSHManagedNodes = [ ] string { "titan-db" }
cfg . SSHConfigFile = " /tmp/ananke-ssh-config "
cfg . SSHIdentityFile = " /tmp/ananke-ssh-id "
run := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
if name == "curl" {
return "500" , nil
}
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
orch , _ := newHookOrchestrator ( t , cfg , run , run )
if ! orch . TestHookSSHManaged ( "titan-db" ) || orch . TestHookSSHManaged ( "titan-23" ) {
t . Fatalf ( "unexpected sshManaged evaluation" )
}
if got := orch . TestHookResolveSSHConfigFile ( ) ; got != "/tmp/ananke-ssh-config" {
t . Fatalf ( "unexpected ssh config path: %q" , got )
}
if got := orch . TestHookResolveSSHIdentityFile ( ) ; got != "/tmp/ananke-ssh-id" {
t . Fatalf ( "unexpected ssh identity path: %q" , got )
}
ctx , cancel := context . WithCancel ( context . Background ( ) )
cancel ( )
if err := orch . TestHookWaitForPostStartProbes ( ctx ) ; ! errors . Is ( err , context . Canceled ) {
t . Fatalf ( "expected canceled post-start probe wait, got %v" , err )
}
dryCfg := lifecycleConfig ( t )
dry := cluster . New ( dryCfg , & execx . Runner { DryRun : true } , state . New ( dryCfg . State . RunHistoryPath ) , log . New ( io . Discard , "" , 0 ) )
if err := dry . TestHookWaitForPostStartProbes ( context . Background ( ) ) ; err != nil {
t . Fatalf ( "expected dry-run post-start skip, got %v" , err )
}
} )
} )
t . Run ( "coordination-and-workload-ignore-helpers" , func ( t * testing . T ) {
t . Run ( "peer-guard-skip-unknown-and-block" , func ( t * testing . T ) {
cfg := lifecycleConfig ( t )
cfg . Coordination . PeerHosts = [ ] string { "ghost" , "titan-24" }
cfg . Coordination . StartupGuardMaxAgeSec = 120
cfg . SSHManagedNodes = append ( cfg . SSHManagedNodes , "titan-24" )
cfg . SSHNodeHosts [ "titan-24" ] = "titan-24"
now := time . Now ( ) . UTC ( ) . Format ( time . RFC3339 )
run := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
switch {
case name == "ssh" && strings . Contains ( command , "ghost" ) :
return "" , errors . New ( "no route to host" )
case name == "ssh" && strings . Contains ( command , "ananke intent --config /etc/ananke/ananke.yaml" ) :
return "__ANANKE_BOOTSTRAP_ACTIVE__\nintent=startup_in_progress reason=\"normal\" source=peer updated_at=" + now + "\n" , nil
default :
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
}
orch , _ := newHookOrchestrator ( t , cfg , run , run )
if err := orch . TestHookGuardPeerStartupIntents ( context . Background ( ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "startup_in_progress" ) {
t . Fatalf ( "expected startup_in_progress block, got %v" , err )
}
runUnknown := func ( ctx context . Context , timeout time . Duration , name string , args ... string ) ( string , error ) {
command := name + " " + strings . Join ( args , " " )
if name == "ssh" && strings . Contains ( command , "ananke intent --config /etc/ananke/ananke.yaml" ) {
return "__ANANKE_BOOTSTRAP_IDLE__\nintent=unknown_state reason=\"odd\" source=peer updated_at=" + now + "\n" , nil
}
return lifecycleDispatcher ( & commandRecorder { } ) ( ctx , timeout , name , args ... )
}
orchUnknown , _ := newHookOrchestrator ( t , cfg , runUnknown , runUnknown )
if err := orchUnknown . TestHookGuardPeerStartupIntents ( context . Background ( ) ) ; err != nil {
t . Fatalf ( "expected unknown-state ignore, got %v" , err )
}
} )
t . Run ( "workload-ignore-affinity-branch-matrix" , func ( t * testing . T ) {
ignored := [ ] string { "titan-22" }
if cluster . TestHookWorkloadTargetsIgnoredNodesRaw ( nil , ignored ) {
t . Fatalf ( "expected false when no affinity terms are present" )
}
if cluster . TestHookWorkloadTargetsIgnoredNodesRaw ( [ ] [ ] cluster . TestHookNodeSelectorExpr {
{ { Key : "kubernetes.io/hostname" , Operator : "In" , Values : [ ] string { "titan-22" } } } ,
{ { Key : "kubernetes.io/hostname" , Operator : "In" , Values : [ ] string { "titan-22" } } } ,
} , ignored ) {
t . Fatalf ( "expected false when more than one term is present" )
}
if cluster . TestHookWorkloadTargetsIgnoredNodesRaw ( [ ] [ ] cluster . TestHookNodeSelectorExpr {
{ { Key : "other" , Operator : "In" , Values : [ ] string { "titan-22" } } } ,
} , ignored ) {
t . Fatalf ( "expected false for non-hostname key" )
}
if cluster . TestHookWorkloadTargetsIgnoredNodesRaw ( [ ] [ ] cluster . TestHookNodeSelectorExpr {
{ { Key : "kubernetes.io/hostname" , Operator : "NotIn" , Values : [ ] string { "titan-22" } } } ,
} , ignored ) {
t . Fatalf ( "expected false for non-In operator" )
}
if cluster . TestHookWorkloadTargetsIgnoredNodesRaw ( [ ] [ ] cluster . TestHookNodeSelectorExpr {
{ { Key : "kubernetes.io/hostname" , Operator : "In" , Values : nil } } ,
} , ignored ) {
t . Fatalf ( "expected false for empty hostname values" )
}
if cluster . TestHookWorkloadTargetsIgnoredNodesRaw ( [ ] [ ] cluster . TestHookNodeSelectorExpr {
{ { Key : "kubernetes.io/hostname" , Operator : "In" , Values : [ ] string { "titan-22" , "titan-23" } } } ,
} , ignored ) {
t . Fatalf ( "expected false when any hostname is not ignored" )
}
if ! cluster . TestHookWorkloadTargetsIgnoredNodesRaw ( [ ] [ ] cluster . TestHookNodeSelectorExpr {
{ { Key : "kubernetes.io/hostname" , Operator : "In" , Values : [ ] string { "titan-22" } } } ,
} , ignored ) {
t . Fatalf ( "expected true when all affinity hostnames are ignored" )
}
if cluster . TestHookPodTargetsIgnoredNode ( "" , ignored ) {
t . Fatalf ( "expected false when pod has no explicit node name" )
}
} )
} )
}
// httpStatusHandler runs one orchestration or CLI step.
// Signature: httpStatusHandler(code int, body string) func(http.ResponseWriter, *http.Request).
// Why: keeps checklist/stability tests compact while still driving real HTTP probe branches.
func httpStatusHandler ( code int , body string ) func ( http . ResponseWriter , * http . Request ) {
return func ( w http . ResponseWriter , _ * http . Request ) {
w . WriteHeader ( code )
_ , _ = w . Write ( [ ] byte ( body ) )
}
}
// TestHookGapMatrixPart5IngressHostMappingRegression runs one orchestration or CLI step.
// Signature: TestHookGapMatrixPart5IngressHostMappingRegression(t *testing.T).
// Why: ensures host parsing fallback paths stay stable for ingress/service checklist failures.
func TestHookGapMatrixPart5IngressHostMappingRegression ( t * testing . T ) {
cfg := lifecycleConfig ( t )
cfg . Startup . ServiceChecklist = [ ] config . ServiceChecklistCheck {
{ Name : "metrics" , URL : "https://metrics.bstein.dev/api/health" } ,
}
orch , _ := newHookOrchestrator ( t , cfg , nil , nil )
if got := orch . TestHookChecklistFailureHost ( "metrics: down" ) ; got != "metrics.bstein.dev" {
t . Fatalf ( "expected metrics host map, got %q" , got )
}
rawURL := "https://grafana.bstein.dev/path"
if got := orch . TestHookChecklistFailureHost ( rawURL ) ; got != "" {
t . Fatalf ( "expected checklist host parser to treat raw URL as unknown prefix, got %q" , got )
}
if got := cluster . TestHookHostFromURL ( rawURL ) ; got != "grafana.bstein.dev" {
t . Fatalf ( "expected hostFromURL helper parse, got %q" , got )
}
u , _ := neturl . Parse ( rawURL )
if u == nil || u . Hostname ( ) == "" {
t . Fatalf ( "expected URL parse sanity" )
}
}