Files
spinifex/tests/e2e/multinode/gateway_test.go
T
Josh Siviour 92fa467c90 refactor(e2e/multinode): flatten spread + parallel bucket + drop phase numbers (#245)
* refactor(e2e/multinode): flatten phase 11 + parallelize bucket #1 + drop phase numbers

Split monolithic phase11_PlacementAndNATGateway (~430 lines, 8 inline
sub-steps) into 6 top-level Tests, each owning its own VPC graph via
t.Cleanup and layered setup helpers (spreadSetupVPC, spreadSetupBastion,
spreadSetupPrivateTrio, spreadSetupNATGW). The cleanup-ordering test
flips *bool latches as each explicit teardown step succeeds so the
LIFO unwind is a no-op on the success path.

Add t.Parallel() to read-only / independent Tests: ClusterHealth,
InstanceDistribution, GuestSSH, VPCNetworking. Deviates from the
mulga-siv-127 bead's bucket-#1 listing by keeping CrossNodeGateway
sequential (asserts a snapshot equality across gateways that the
parallel VPC test would break by churning instance count mid-assert)
and CrossNodeOps sequential (stops/starts trio[0], would race
GuestSSH). Both deviations documented in tests_test.go + plan doc.

Drop the bash phase numbering (phaseN_X funcs + "Phase N" log strings)
from the rest of the suite — 10 funcs renamed to runX. Phase numbers
were a port-time crutch; the Test names now describe each scenario and
phase numbers ageing into noise as bash is retired in Stage H.

* refactor(e2e/multinode): collapse spread Tests + control execution order

Two changes wedged together since they touch the same files:

1. Collapse the 6 top-level TestMultinodeSpread* Tests into a single
   TestMultinodeSpread with 6 t.Run sub-tests sharing one VPC + bastion +
   private trio + NAT GW setup chain. The 6-test split paid setup cost
   6× — bastion launch + private trio launch + NAT GW provision per Test
   pushed phase-11 wall-clock near 60min vs ~15min monolithic. Shared-
   setup layout keeps JUnit granularity (one row per sub-test) while
   restoring the monolithic budget. Setup helpers register t.Cleanup
   against the outer test so teardown runs once at the end (LIFO:
   NAT GW → trio → bastion → VPC).

2. Move the TestMultinodeSpread wrapper into tests_test.go so file-source
   order controls execution position. Previously the func lived in
   placement_nat_test.go which sorts before preflight_test.go and
   tests_test.go alphabetically — Spread ran FIRST in the sequential
   bucket, defeating Preflight's fail-fast on a sick cluster. Wrapper now
   runs after NodeRecovery so the cluster has been fully degrade-tested
   before Spread's 4-VM + NAT GW + custom-VPC graph spins up.
2026-05-21 20:53:59 +10:00

52 lines
1.9 KiB
Go

//go:build e2e
package multinode
import (
"testing"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/tests/e2e/harness"
"github.com/stretchr/testify/require"
)
// runCrossNodeGateway is the Go port of cross-node gateway access
// (run-multinode-e2e.sh:828-851). Drives DescribeInstances through every
// node's gateway and asserts each returns the same instance count as node1
// (the test runner's local gateway).
//
// Catches the regression where the daemon answers only locally-hosted
// instances instead of fanning out via NATS — i.e. a stale awsgw routing
// table or a queue-group misconfiguration.
func runCrossNodeGateway(t *testing.T, fix *Fixture) {
harness.Phase(t, "Multinode — Cross-Node Gateway Access")
// Trigger trio launch so the baseline count is meaningful.
_ = needInstanceTrio(t, fix)
baseline, err := fix.AWS.EC2.DescribeInstances(&ec2.DescribeInstancesInput{})
require.NoError(t, err, "baseline describe-instances")
want := countInstances(baseline)
harness.Detail(t, "baseline_node", fix.Cluster.Nodes[0].Name, "instances", want)
require.Greater(t, want, 0, "baseline returned 0 instances (trio not registered?)")
// Bash skips node1 (the local one) — its baseline already represents that gateway.
for _, n := range fix.Cluster.Nodes[1:] {
harness.Step(t, "DescribeInstances via %s (%s)", n.Name, n.Addr)
cli := harness.AWSClientForGateway(t, fix.Env, n)
out, err := cli.EC2.DescribeInstances(&ec2.DescribeInstancesInput{})
require.NoErrorf(t, err, "describe-instances via %s", n.Name)
got := countInstances(out)
harness.Detail(t, "node", n.Name, "instances", got)
require.Equalf(t, want, got, "%s returned %d instances, baseline %d (cross-node fan-out broken)", n.Name, got, want)
}
}
func countInstances(out *ec2.DescribeInstancesOutput) int {
n := 0
for _, r := range out.Reservations {
n += len(r.Instances)
}
return n
}