Files
spinifex/tests/e2e/multinode/tests_test.go
T
joshsiv-mulga c9a4e904a8 test(e2e): fresh-install reachability baselines + drop qemu hostfwd fallback
Add baseline tests that confirm two fresh-install regressions the existing
suite masks (it authorizes tcp/22 on the default SG before every SSH probe):

  - default SG default-deny gates external reach of instances in the
    default subnet (SG, not routing)
  - a newly-created public subnet never gets its OVN IGW egress LRP, so it
    has no route to the VPC IGW despite MapPublicIpOnLaunch

Plus a positive test: instances sharing the default SG can communicate via
ICMP (same-host single-node, cross-host multinode).

Single-node baselines run after TestClusterStatsCLI (0-VM gate); multinode
after TestMultinodePreflight (fixture init). Instances are self-cleaning so
they don't perturb the singleton-VM ordering.

Remove the qemu hostfwd SSH fallback from the harness (InstancePublicSSHHost,
GuestSSHEndpoint) - it bypasses the OVN datapath and masks these regressions.
Endpoints now t.Fatal when no public IP is assigned.
2026-06-04 19:56:02 +10:00

122 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//go:build e2e
package multinode
import "testing"
// Top-level Test* wrappers. Each delegates to a runX function in the matching
// <name>_test.go file. Names follow the single-node convention (TestX) so
// isolated runs via `go test -run TestMultinodeClusterHealth` are stable.
//
// Spread placement + NAT GW (formerly bash phase 11) lives in
// placement_nat_test.go as a single TestMultinodeSpread with 6 t.Run
// sub-tests sharing one VPC + bastion + private trio + NAT GW setup chain.
// Sub-test layout keeps JUnit granularity without paying 6× setup cost.
//
// Parallelism:
//
// Bucket #1 (parallel): the read-only / independent Tests below call
// t.Parallel(). They share the package-singleton trio (sync.Once gated) and
// the harness Fixture but never mutate it — DescribeInstances / SSH probe /
// VPC creation in independent CIDR space.
//
// Sequential (no t.Parallel — would race the parallel bucket):
// - TestMultinodePreflight : runs first; initialises pkg fixture.
// - TestMultinodeVolumeLifecycle : touches predastore state.
// - TestMultinodeCrossNodeGateway : asserts equality between baseline
// DescribeInstances and per-gateway DescribeInstances; concurrent VPC
// test launches/terminates instances mid-assert, breaking equality.
// Bead spec listed it in bucket #1 but the snapshot assumption fails
// under parallel state churn; keep sequential.
// - TestMultinodeCrossNodeOps : stops/starts trio[0], would race
// TestMultinodeGuestSSH which iterates every trio member. Bead spec
// listed it in bucket #1 but the trio mutation makes that unsafe;
// keep sequential until bucket #3 reworks shared-state ownership.
// - TestMultinodeNodeFailure/Recovery : StopNode/StartNode mutate cluster.
// - TestMultinodeSpread : owns EIP pool + VPC CIDR
// 10.100.0.0/16; sub-tests share the setup chain sequentially.
// TestMultinodePreflight runs sequentially because it initialises the
// package fixture singleton.
func TestMultinodePreflight(t *testing.T) {
runPreflight(t, requireMultiNodeFixture(t))
}
// Fresh-install reachability baselines run right after preflight and before
// any test calls needInstanceTrio (which authorizes SSH on the default SG),
// so the default SG / subnet / route table are exercised pristine. Both own
// their mutable resources (dedicated SGs, self-cleaning instances) and never
// mutate a default resource.
func TestMultinodeDefaultSGReachabilityBaseline(t *testing.T) {
runMultinodeDefaultSGReachabilityBaseline(t, requireMultiNodeFixture(t))
}
func TestMultinodeSameSGCrossHostComms(t *testing.T) {
runMultinodeSameSGCrossHostComms(t, requireMultiNodeFixture(t))
}
func TestMultinodeClusterHealth(t *testing.T) {
t.Parallel()
runClusterHealth(t, requireMultiNodeFixture(t))
}
func TestMultinodeInstanceDistribution(t *testing.T) {
t.Parallel()
runInstanceDistribution(t, requireMultiNodeFixture(t))
}
func TestMultinodeGuestSSH(t *testing.T) {
t.Parallel()
runGuestSSH(t, requireMultiNodeFixture(t))
}
// TestMultinodeVolumeLifecycle is sequential — touches predastore state
// shared with other suites.
func TestMultinodeVolumeLifecycle(t *testing.T) {
runVolumeLifecycle(t, requireMultiNodeFixture(t))
}
// TestMultinodeCrossNodeGateway is sequential — asserts a stable
// instance-count snapshot across gateways, which the parallel VPC test
// would break by launching/terminating its own instances mid-assert.
func TestMultinodeCrossNodeGateway(t *testing.T) {
runCrossNodeGateway(t, requireMultiNodeFixture(t))
}
// TestMultinodeCrossNodeOps is sequential — stops/starts trio[0], which
// would race TestMultinodeGuestSSH.
func TestMultinodeCrossNodeOps(t *testing.T) {
runCrossNodeOps(t, requireMultiNodeFixture(t))
}
func TestMultinodeNodeFailure(t *testing.T) {
runNodeFailure(t, requireMultiNodeFixture(t))
}
func TestMultinodeNodeRecovery(t *testing.T) {
runNodeRecovery(t, requireMultiNodeFixture(t))
}
// TestMultinodeSpread runs after NodeRecovery so the cluster is fully
// healthy + degrade-tested before this Test launches its 4-VM + NAT GW +
// custom-VPC graph. Sequential — owns 10.100.0.0/16 + EIP pool; sub-tests
// share the setup chain (see placement_nat_test.go).
func TestMultinodeSpread(t *testing.T) {
runSpread(t, requireMultiNodeFixture(t))
}
// TestMultinodeVPCNetworking owns its own 10.200.0.0/16 VPC (no EIP use)
// so it's safe alongside bucket #1.
func TestMultinodeVPCNetworking(t *testing.T) {
t.Parallel()
runVPCNetworking(t, requireMultiNodeFixture(t))
}
// TestMultinodeIPSec is read-only over SSH — verifies the OVN native IPsec
// wiring (OVS DB cert pointers, xfrm SAs, ESP traffic) without launching
// any AWS resources. Safe to run alongside the parallel bucket.
func TestMultinodeIPSec(t *testing.T) {
t.Parallel()
runIPSec(t, requireMultiNodeFixture(t))
}