diff --git a/test.mk b/test.mk index 7b624cc..4f96870 100644 --- a/test.mk +++ b/test.mk @@ -283,9 +283,12 @@ run-integration-tests-v2: ## Bring up the gnmi-gen suite env, run all suites, te exit $$status # Nightly / local-only fleet suite. Not wired into CI. -# SCALE_TARGETS defaults to 200; override e.g. SCALE_TARGETS=50 make integration-test-scale -SCALE_TARGETS ?= 200 +# SCALE_TARGETS defaults to 200, SCALE_REPLICAS to 4. +# e.g. SCALE_TARGETS=50 SCALE_REPLICAS=2 make integration-test-scale +SCALE_TARGETS ?= 200 +SCALE_REPLICAS ?= 4 .PHONY: integration-test-scale integration-test-scale: integration-env-check ## Run 013-scale (sets RUN_SCALE=1) - RUN_SCALE=1 SCALE_TARGETS=$(SCALE_TARGETS) go test -tags=integration -count=1 -timeout 45m -v ./$(IT_SUITE_DIR)/013-scale/... + RUN_SCALE=1 SCALE_TARGETS=$(SCALE_TARGETS) SCALE_REPLICAS=$(SCALE_REPLICAS) \ + go test -tags=integration -count=1 -timeout 45m -v ./$(IT_SUITE_DIR)/013-scale/... diff --git a/test/integration/harness/suite.go b/test/integration/harness/suite.go index 03257b7..e227a6d 100644 --- a/test/integration/harness/suite.go +++ b/test/integration/harness/suite.go @@ -49,6 +49,9 @@ type Options struct { GnmiGenConfigData []byte // Baseline fixtures applied after the simulator is up, before m.Run. Baseline []string + // BaselineVars are merged into every baseline fixture template (on top of + // the harness base vars). Used for suite-wide knobs like replica count. + BaselineVars map[string]any // RequireTargets are simulated targets that must report "up" before tests // start. RequireTargets []string @@ -107,7 +110,7 @@ func New(opts Options) (*Suite, error) { } for _, f := range opts.Baseline { - if err := s.applyBaseline(f); err != nil { + if err := s.applyBaseline(f, opts.BaselineVars); err != nil { return s, fmt.Errorf("applying baseline %s: %w", f, err) } } @@ -306,12 +309,12 @@ func (s *Suite) waitTargetsUp(names []string) error { } } -func (s *Suite) applyBaseline(path string) error { +func (s *Suite) applyBaseline(path string, vars map[string]any) error { b, err := os.ReadFile(path) if err != nil { return err } - _, err = s.K8s.applyYAML(string(b), nil) + _, err = s.K8s.applyYAML(string(b), vars) return err } diff --git a/test/integration/suite/013-scale/fixtures/baseline.yaml b/test/integration/suite/013-scale/fixtures/baseline.yaml index 9ec8677..bceb3b3 100644 --- a/test/integration/suite/013-scale/fixtures/baseline.yaml +++ b/test/integration/suite/013-scale/fixtures/baseline.yaml @@ -1,4 +1,5 @@ -# Shared props for 013-scale. The 200 Target CRs are generated in AfterBaseline. +# Shared props for 013-scale. Target CRs are generated in AfterBaseline. +# Cluster replicas come from SCALE_REPLICAS via BaselineVars. apiVersion: v1 kind: Secret metadata: @@ -24,7 +25,7 @@ metadata: name: c1 spec: image: {{ .GnmicImage }} - replicas: 4 + replicas: {{ .Replicas }} api: restPort: 7890 resources: diff --git a/test/integration/suite/013-scale/scale_test.go b/test/integration/suite/013-scale/scale_test.go index 85934f9..52741db 100644 --- a/test/integration/suite/013-scale/scale_test.go +++ b/test/integration/suite/013-scale/scale_test.go @@ -4,7 +4,8 @@ // single-target churn cost, sustained membership change, and mass reboot. // // Gated behind RUN_SCALE=1 (see TestMain). Not part of the default CI lane. -// Fleet size defaults to 200 and is overridable with SCALE_TARGETS. +// Fleet size defaults to 200 (SCALE_TARGETS) and collector pods to 4 +// (SCALE_REPLICAS). package scale import ( @@ -29,13 +30,13 @@ const ( cluster = "c1" pipeline = "fleet" output = "prom" - replicas = 4 ) var ( s *harness.Suite targets []string fleetN int + replicas int spareSim string sparePort int minPerPod int @@ -47,9 +48,14 @@ func TestMain(m *testing.M) { fmt.Fprintln(os.Stderr, "013-scale: skipped (set RUN_SCALE=1 to enable)") os.Exit(0) } - fleetN = scaleTargets() - if fleetN < 4 { - fmt.Fprintf(os.Stderr, "013-scale: SCALE_TARGETS=%d too small (min 4)\n", fleetN) + fleetN = envInt("SCALE_TARGETS", 200) + replicas = envInt("SCALE_REPLICAS", 4) + if replicas < 1 { + fmt.Fprintf(os.Stderr, "013-scale: SCALE_REPLICAS=%d too small (min 1)\n", replicas) + os.Exit(1) + } + if fleetN < replicas { + fmt.Fprintf(os.Stderr, "013-scale: SCALE_TARGETS=%d < SCALE_REPLICAS=%d\n", fleetN, replicas) os.Exit(1) } spareSim = fmt.Sprintf("dev-%d", fleetN+1) @@ -59,8 +65,8 @@ func TestMain(m *testing.M) { for i := 1; i <= fleetN; i++ { targets[i-1] = fmt.Sprintf("dev-%d", i) } - fmt.Fprintf(os.Stderr, "[harness] suite 013-scale: SCALE_TARGETS=%d spare=%s placement=%d..%d per pod\n", - fleetN, spareSim, minPerPod, maxPerPod) + fmt.Fprintf(os.Stderr, "[harness] suite 013-scale: SCALE_TARGETS=%d SCALE_REPLICAS=%d spare=%s placement=%d..%d per pod\n", + fleetN, replicas, spareSim, minPerPod, maxPerPod) require := append(append([]string{}, targets...), spareSim) os.Exit(harness.RunSuite(m, harness.Options{ @@ -68,18 +74,19 @@ func TestMain(m *testing.M) { GnmiGenConfigData: renderGnmiGenConfig(fleetN + 1), RequireTargets: require, Baseline: []string{"fixtures/baseline.yaml"}, + BaselineVars: map[string]any{"Replicas": replicas}, AfterBaseline: applyFleetTargets, }, &s)) } -func scaleTargets() int { - v := os.Getenv("SCALE_TARGETS") +func envInt(name string, def int) int { + v := os.Getenv(name) if v == "" { - return 200 + return def } n, err := strconv.Atoi(v) if err != nil || n <= 0 { - return 200 + return def } return n } @@ -147,12 +154,12 @@ func waitFleetReady(t *testing.T) time.Duration { harness.WaitClusterCounts(t, s.K8s, cluster, harness.ClusterCounts{ TargetsCount: harness.I32(int32(fleetN)), UnassignedTargets: harness.I32(0), - ReadyReplicas: harness.I32(replicas), + ReadyReplicas: harness.I32(int32(replicas)), }) s.GnmiGen.WaitFleetStreams(t, harness.Long, 1, targets) s.GnmiGen.WaitStreams(t, spareSim, 0) elapsed := time.Since(start) - t.Logf("fleet converged in %s (SCALE_TARGETS=%d)", elapsed, fleetN) + t.Logf("fleet converged in %s (SCALE_TARGETS=%d SCALE_REPLICAS=%d)", elapsed, fleetN, replicas) return elapsed }