100 lines
3.5 KiB
Go
100 lines
3.5 KiB
Go
|
|
package cluster
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"errors"
|
||
|
|
"io"
|
||
|
|
"log"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"scm.bstein.dev/bstein/ananke/internal/config"
|
||
|
|
"scm.bstein.dev/bstein/ananke/internal/execx"
|
||
|
|
"scm.bstein.dev/bstein/ananke/internal/state"
|
||
|
|
)
|
||
|
|
|
||
|
|
// TestCriticalEndpointHelpers runs one orchestration or CLI step.
|
||
|
|
// Signature: TestCriticalEndpointHelpers(t *testing.T).
|
||
|
|
// Why: covers critical endpoint parsing and readiness checks that gate startup completion.
|
||
|
|
func TestCriticalEndpointHelpers(t *testing.T) {
|
||
|
|
cfg := config.Config{
|
||
|
|
Startup: config.Startup{
|
||
|
|
CriticalServiceEndpoints: []string{"monitoring/victoria-metrics-single-server"},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
orch := buildOrchestratorWithStubs(t, cfg, []commandStub{
|
||
|
|
{match: matchContains("kubectl", "get endpoints victoria-metrics-single-server"), out: "10.42.0.10\n10.42.0.11\n"},
|
||
|
|
})
|
||
|
|
ok, detail, ns, svc, err := orch.criticalServiceEndpointsReady(context.Background())
|
||
|
|
if err != nil || !ok {
|
||
|
|
t.Fatalf("expected criticalServiceEndpointsReady success, got ok=%v detail=%q ns=%q svc=%q err=%v", ok, detail, ns, svc, err)
|
||
|
|
}
|
||
|
|
if detail != "services=1" {
|
||
|
|
t.Fatalf("unexpected readiness detail: %q", detail)
|
||
|
|
}
|
||
|
|
gotNS, gotSvc, err := parseCriticalServiceEndpoint("monitoring/victoria-metrics-single-server")
|
||
|
|
if err != nil || gotNS != "monitoring" || gotSvc != "victoria-metrics-single-server" {
|
||
|
|
t.Fatalf("unexpected parse result ns=%q svc=%q err=%v", gotNS, gotSvc, err)
|
||
|
|
}
|
||
|
|
if _, _, err := parseCriticalServiceEndpoint("invalid"); err == nil {
|
||
|
|
t.Fatalf("expected parseCriticalServiceEndpoint error")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestCriticalEndpointAutoHealWorkflow runs one orchestration or CLI step.
|
||
|
|
// Signature: TestCriticalEndpointAutoHealWorkflow(t *testing.T).
|
||
|
|
// Why: covers endpoint-zero recovery where startup heals workload replicas before succeeding.
|
||
|
|
func TestCriticalEndpointAutoHealWorkflow(t *testing.T) {
|
||
|
|
cfg := config.Config{
|
||
|
|
Startup: config.Startup{
|
||
|
|
CriticalServiceEndpointWaitSec: 2,
|
||
|
|
CriticalServiceEndpointPollSec: 1,
|
||
|
|
CriticalServiceEndpoints: []string{"monitoring/victoria-metrics-single-server"},
|
||
|
|
},
|
||
|
|
State: config.State{
|
||
|
|
Dir: t.TempDir(),
|
||
|
|
ReportsDir: filepath.Join(t.TempDir(), "reports"),
|
||
|
|
RunHistoryPath: filepath.Join(t.TempDir(), "runs.json"),
|
||
|
|
},
|
||
|
|
}
|
||
|
|
orch := &Orchestrator{
|
||
|
|
cfg: cfg,
|
||
|
|
runner: &execx.Runner{},
|
||
|
|
store: state.New(cfg.State.RunHistoryPath),
|
||
|
|
log: log.New(io.Discard, "", 0),
|
||
|
|
}
|
||
|
|
|
||
|
|
endpointChecks := 0
|
||
|
|
dispatch := func(_ context.Context, _ time.Duration, name string, args ...string) (string, error) {
|
||
|
|
joined := name + " " + strings.Join(args, " ")
|
||
|
|
if strings.Contains(joined, "get endpoints victoria-metrics-single-server") {
|
||
|
|
endpointChecks++
|
||
|
|
if endpointChecks == 1 {
|
||
|
|
return "", nil
|
||
|
|
}
|
||
|
|
return "10.42.0.10\n", nil
|
||
|
|
}
|
||
|
|
if strings.Contains(joined, "scale deployment victoria-metrics-single-server") {
|
||
|
|
return "", errors.New(`Error from server (NotFound): deployments.apps "victoria-metrics-single-server" not found`)
|
||
|
|
}
|
||
|
|
if strings.Contains(joined, "scale statefulset victoria-metrics-single-server") {
|
||
|
|
return "", nil
|
||
|
|
}
|
||
|
|
if strings.Contains(joined, "rollout status statefulset/victoria-metrics-single-server") {
|
||
|
|
return "statefulset rolled out", nil
|
||
|
|
}
|
||
|
|
return "", nil
|
||
|
|
}
|
||
|
|
orch.runOverride = dispatch
|
||
|
|
orch.runSensitiveOverride = dispatch
|
||
|
|
|
||
|
|
if err := orch.waitForCriticalServiceEndpoints(context.Background()); err != nil {
|
||
|
|
t.Fatalf("waitForCriticalServiceEndpoints failed: %v", err)
|
||
|
|
}
|
||
|
|
if endpointChecks < 2 {
|
||
|
|
t.Fatalf("expected repeated endpoint checks, got %d", endpointChecks)
|
||
|
|
}
|
||
|
|
}
|