From 40f8c4da94444b3349ed92b0c5d8b24352d304d2 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 21 May 2026 22:47:26 +1000 Subject: [PATCH] refactor(e2e/single): drop phase numbers + parallel bucket #1 (#247) - Rename 36 phaseN_X / phaseIAM_N funcs to runX. - Drop numeric suffix from 7 TestIAMN_X wrappers (TestIAM1_UserCRUD -> TestIAMUserCRUD). - Rewrite harness.Phase log strings "Phase N - X" -> "Single - X" to mirror multinode convention. - Add t.Parallel() to bucket #1: 10 read-only / own-everything top-level Tests (Environment, ClusterStatsCLI, Discovery, SerialConsoleAccess, KeyPairs, Image, TagManagement, AccountScoping, VPCSubnetE2E, RouteTableValidation). Sequential bucket retains source-order singleton lifecycle (InstanceLaunch through FinalClusterStats). --- tests/e2e/single/account_test.go | 6 +- tests/e2e/single/createimage_test.go | 6 +- tests/e2e/single/datapath_test.go | 6 +- tests/e2e/single/discovery_test.go | 24 +-- tests/e2e/single/iam_test.go | 42 ++-- tests/e2e/single/image_test.go | 6 +- tests/e2e/single/instance_test.go | 30 +-- tests/e2e/single/keypair_test.go | 6 +- tests/e2e/single/lifecycle_test.go | 30 +-- tests/e2e/single/natgw_test.go | 6 +- tests/e2e/single/negative_test.go | 6 +- tests/e2e/single/securitygroup_test.go | 6 +- tests/e2e/single/snapshot_test.go | 12 +- tests/e2e/single/tags_test.go | 6 +- tests/e2e/single/teardown_test.go | 6 +- tests/e2e/single/tests_test.go | 279 ++++++++++++++++--------- tests/e2e/single/volume_test.go | 12 +- tests/e2e/single/vpc_test.go | 12 +- 18 files changed, 291 insertions(+), 210 deletions(-) diff --git a/tests/e2e/single/account_test.go b/tests/e2e/single/account_test.go index 22fac6d7e..6bc97cf1e 100644 --- a/tests/e2e/single/account_test.go +++ b/tests/e2e/single/account_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/require" ) -// phase8Acct_AccountScoping ports run-e2e.sh Phase 8 EC2 Account Scoping +// runAccountScoping ports run-e2e.sh Phase 8 EC2 Account Scoping // (lines 1915–2624). Validates that EC2 resources (instances, volumes, key // pairs, snapshots, VPCs, IGWs, EIGWs) are isolated between tenant accounts // created via `spx admin account create`. @@ -41,8 +41,8 @@ import ( // Step9_GlobalResources — regions/AZs/instance types identical // Step10_EdgeCases — empty Gamma + non-existent resource ids // Step11_Cleanup — explicit best-effort teardown (also runs via t.Cleanup) -func phase8Acct_AccountScoping(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 8 (acct) — EC2 Account Scoping") +func runAccountScoping(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — EC2 Account Scoping") amiID := needAMI(t, fix) instType, _ := needInstanceTypeArch(t, fix) diff --git a/tests/e2e/single/createimage_test.go b/tests/e2e/single/createimage_test.go index 24b87773e..bd6acc54b 100644 --- a/tests/e2e/single/createimage_test.go +++ b/tests/e2e/single/createimage_test.go @@ -12,12 +12,12 @@ import ( "github.com/stretchr/testify/require" ) -// phase5e_CreateImage builds a custom AMI from the running instance and +// runCreateImage builds a custom AMI from the running instance and // records the backing snapshot ID so Phase 9 cleanup can delete the // snapshot before terminating the instance (otherwise DeleteOnTermination // trips over the still-referenced snapshot). Maps to run-e2e.sh ~805–844. -func phase5e_CreateImage(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5e — CreateImage Lifecycle") +func runCreateImage(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — CreateImage Lifecycle") inst, _ := needInstance(t, fix) instanceID := aws.StringValue(inst.InstanceId) diff --git a/tests/e2e/single/datapath_test.go b/tests/e2e/single/datapath_test.go index dfd639a58..3c50ae0f7 100644 --- a/tests/e2e/single/datapath_test.go +++ b/tests/e2e/single/datapath_test.go @@ -26,7 +26,7 @@ systemd-run --unit=sge-http --description="Phase 8e HTTP server" \ /usr/bin/python3 -m http.server 8080 --bind 0.0.0.0 ` -// phase8e_SGToSGDatapath validates the closed loop from RunInstances +// runSGToSGDatapath validates the closed loop from RunInstances // (--security-group-ids) -> ENI -> vpcd -> OVN port group + ACL -> datapath // drop. Creates two SGs (client / target) with an SG-to-SG ingress rule for // tcp/8080, launches one VM in each, then exercises: @@ -42,8 +42,8 @@ systemd-run --unit=sge-http --description="Phase 8e HTTP server" \ // // OVN gated — skipped on dev laptops without ovn-nbctl/sudo. Maps to // run-e2e.sh ~3188-3442. -func phase8e_SGToSGDatapath(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 8e — Security Group SG-to-SG Datapath (OVN)") +func runSGToSGDatapath(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Security Group SG-to-SG Datapath (OVN)") harness.SkipIfNoOVN(t) // Bootstrap every prereq up front. runSGEInstance / primaryENI use diff --git a/tests/e2e/single/discovery_test.go b/tests/e2e/single/discovery_test.go index 93275380f..0f4be757d 100644 --- a/tests/e2e/single/discovery_test.go +++ b/tests/e2e/single/discovery_test.go @@ -16,11 +16,11 @@ import ( "github.com/stretchr/testify/require" ) -// phase1_Environment verifies KVM, AWS gateway TLS reachability, daemon NATS +// runEnvironment verifies KVM, AWS gateway TLS reachability, daemon NATS // readiness, and the basic region/AZ discovery calls. Maps to run-e2e.sh // lines ~51–93. -func phase1_Environment(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 1 — Environment") +func runEnvironment(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Environment") // /dev/kvm — skip rather than fatal in local-dev to match the bash // "exit 1" only when KVM is genuinely required (CI). Local devs without @@ -88,11 +88,11 @@ func phase1_Environment(t *testing.T, fix *Fixture) { }) } -// phase1b_ClusterStats exercises the spx CLI cluster surface (`get nodes`, +// runClusterStatsCLI exercises the spx CLI cluster surface (`get nodes`, // `top nodes`, `get vms`). Single-node only — multinode mode is tested by a // different scenario. Maps to run-e2e.sh ~95–127. -func phase1b_ClusterStats(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 1b — Cluster Stats CLI") +func runClusterStatsCLI(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Cluster Stats CLI") if fix.Env.Mode != harness.ModeSingle { t.Skipf("Phase 1b is single-node only (mode=%s)", fix.Env.Mode) } @@ -114,12 +114,12 @@ func phase1b_ClusterStats(t *testing.T, fix *Fixture) { "spx get vms should be empty before Phase 5\n%s", vms) } -// phase2_Discovery re-asserts describe-regions / describe-availability-zones +// runDiscovery re-asserts describe-regions / describe-availability-zones // (cheap but it's where the bash records them as a phase boundary) and picks // the nano instance type + architecture used throughout the rest of the run. // Maps to run-e2e.sh ~128–164. -func phase2_Discovery(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 2 — Discovery & Metadata") +func runDiscovery(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Discovery Phase 2 — Discovery & Metadata Metadata") regions, err := fix.AWS.EC2.DescribeRegions(&ec2.DescribeRegionsInput{}) require.NoError(t, err) @@ -137,11 +137,11 @@ func phase2_Discovery(t *testing.T, fix *Fixture) { harness.Detail(t, "instance_type", instType, "arch", arch, "az", az) } -// phase2b_SerialConsole flips serial-console-access on then off and verifies +// runSerialConsoleAccess flips serial-console-access on then off and verifies // each transition with both the action-returned bool and a follow-up // get-status round-trip. Maps to run-e2e.sh ~166–202. -func phase2b_SerialConsole(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 2b — Serial Console Access") +func runSerialConsoleAccess(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Serial Console Access") harness.Step(t, "default state should be disabled") if got := harness.GetSerialConsoleAccessEnabled(t, fix.AWS); got { diff --git a/tests/e2e/single/iam_test.go b/tests/e2e/single/iam_test.go index 17dea628d..5e6ac393e 100644 --- a/tests/e2e/single/iam_test.go +++ b/tests/e2e/single/iam_test.go @@ -92,15 +92,15 @@ const ( }` ) -// phaseIAM1_UserCRUD ports run-e2e.sh IAM Phase 1 (~1405–1459): +// runIAMUserCRUD ports run-e2e.sh IAM Phase 1 (~1405–1459): // CreateUser, GetUser, ListUsers, UpdateUser (rename+path), DeleteUser // plus the EntityAlreadyExists / NoSuchEntity negative paths. Each // created user is scheduled for cleanup so a mid-phase failure can't // poison later runs. UpdateUser exercises an out-of-band rename + // rename-back so Phase 2+ continue to find "alice" by the well-known // name. -func phaseIAM1_UserCRUD(t *testing.T, fix *Fixture) { - harness.Phase(t, "IAM Phase 1 — User CRUD") +func runIAMUserCRUD(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — IAM User CRUD") // Defensive: drop leftovers from a prior failed run before recreate. iamDeleteUserBestEffort(fix, iamUserAlice) @@ -217,13 +217,13 @@ func phaseIAM1_UserCRUD(t *testing.T, fix *Fixture) { }) } -// phaseIAM2_AccessKeyLifecycle ports IAM Phase 2 (~1463–1534): +// runIAMAccessKeyLifecycle ports IAM Phase 2 (~1463–1534): // CreateAccessKey, ListAccessKeys, UpdateAccessKey (deactivate/activate), // DeleteAccessKey plus LimitExceeded / NoSuchEntity negative paths. // Captures alice's primary key into the Fixture so Phase 3 can sign // requests with it. -func phaseIAM2_AccessKeyLifecycle(t *testing.T, fix *Fixture) { - harness.Phase(t, "IAM Phase 2 — Access Key Lifecycle") +func runIAMAccessKeyLifecycle(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — IAM Access Key Lifecycle") iamEnsureAlice(t, fix) iamEnsureBob(t, fix) @@ -315,13 +315,13 @@ func phaseIAM2_AccessKeyLifecycle(t *testing.T, fix *Fixture) { require.Len(t, after.AccessKeyMetadata, 1, "alice should have 1 key after delete") } -// phaseIAM3_UserAuthentication ports IAM Phase 3 (~1538–1579): +// runIAMUserAuthentication ports IAM Phase 3 (~1538–1579): // build a scoped AWS client with alice's key and confirm signing // works (active key) / fails (deactivated key, bad secret, bogus ID). // Also creates bob's key so Phase 5 enforcement / Phase 7 cleanup // can use it. -func phaseIAM3_UserAuthentication(t *testing.T, fix *Fixture) { - harness.Phase(t, "IAM Phase 3 — User Authentication") +func runIAMUserAuthentication(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — IAM User Authentication") // Daemon does not yet honour active-key signatures created via the IAM // API — every scoped DescribeInstances returns 403. Skip-gate until // the handler lands; mulga-siv-100 tracks the daemon-side work. @@ -375,14 +375,14 @@ func phaseIAM3_UserAuthentication(t *testing.T, fix *Fixture) { require.NoError(t, err, "root describe-instances") } -// phaseIAM4_PolicyCRUD ports IAM Phase 4 (~1583–1698): +// runIAMPolicyCRUD ports IAM Phase 4 (~1583–1698): // CreatePolicy (5 variants), CreatePolicyVersion / ListPolicyVersions / // SetDefaultPolicyVersion / DeletePolicyVersion (extends bash, per // task spec), GetPolicy, GetPolicyVersion, ListPolicies plus // EntityAlreadyExists / MalformedPolicyDocument / NoSuchEntity errors. // Captures the admin account ID into the Fixture for Phase 5–7. -func phaseIAM4_PolicyCRUD(t *testing.T, fix *Fixture) { - harness.Phase(t, "IAM Phase 4 — Policy CRUD") +func runIAMPolicyCRUD(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — IAM Policy CRUD") // Defensive: drop any leftover test policies from a prior failed run. // Detach-then-delete isn't worth the round trips here — the cleanup @@ -553,12 +553,12 @@ func phaseIAM4_PolicyCRUD(t *testing.T, fix *Fixture) { "expected >=5 policies, got %d (%v)", len(all.Policies), iamPolicyNames(all.Policies)) } -// phaseIAM5_PolicyAttachmentEnforcement ports IAM Phase 5 (~1702–1833): +// runIAMPolicyAttachmentEnforcement ports IAM Phase 5 (~1702–1833): // AttachUserPolicy idempotency, ListAttachedUserPolicies, enforcement // (default deny / explicit allow / wildcard / explicit deny / root // bypass / prefix wildcard / FullAdmin), DetachUserPolicy. -func phaseIAM5_PolicyAttachmentEnforcement(t *testing.T, fix *Fixture) { - harness.Phase(t, "IAM Phase 5 — Policy Attachment & Enforcement") +func runIAMPolicyAttachmentEnforcement(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — IAM Policy Attachment IAM Phase 5 — Policy Attachment & Enforcement Enforcement") // Enforcement depends on scoped-credential signing (Phase 3) which the // daemon doesn't honour yet — mulga-siv-100. Skip-gate the whole phase // until the upstream gap closes. @@ -727,12 +727,12 @@ func phaseIAM5_PolicyAttachmentEnforcement(t *testing.T, fix *Fixture) { require.NoError(t, err, "charlie iam:ListUsers after FullAdmin") } -// phaseIAM6_PolicyLifecycle ports IAM Phase 6 (~1837–1864): +// runIAMPolicyLifecycle ports IAM Phase 6 (~1837–1864): // detach alice's policy and confirm she loses access; deleting a // still-attached policy must surface DeleteConflict; after detach + // delete the policy is gone (NoSuchEntity). -func phaseIAM6_PolicyLifecycle(t *testing.T, fix *Fixture) { - harness.Phase(t, "IAM Phase 6 — Policy Lifecycle (Detach & Delete)") +func runIAMPolicyLifecycle(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — IAM Policy Lifecycle (Detach IAM Phase 6 — Policy Lifecycle (Detach & Delete) Delete)") // DetachUserPolicy returns 404 NoSuchEntity even for attachments // confirmed by Phase 5 — daemon's attachment ledger isn't persisted // across the API boundary. Skip-gate; mulga-siv-100 tracks the fix. @@ -776,15 +776,15 @@ func phaseIAM6_PolicyLifecycle(t *testing.T, fix *Fixture) { }) } -// phaseIAM7_Cleanup ports IAM Phase 7 (~1868–1911): tear down every +// runIAMCleanup ports IAM Phase 7 (~1868–1911): tear down every // user, key, and policy created by Phases 1–6 even if intermediate // phases failed. Each step is best-effort so a missing resource // (already torn down or never created) doesn't fail the cleanup pass. // The final list-users / list-policies assertions are commented // expectations rather than hard checks because Phase 7 may run with // residual state from a partial Phase 1–6 failure. -func phaseIAM7_Cleanup(t *testing.T, fix *Fixture) { - harness.Phase(t, "IAM Phase 7 — Cleanup") +func runIAMCleanup(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — IAM Cleanup") // Resolve account ID before deleting users — iamEnsureAdminAccountID // probes via GetUser(alice), and the user is gone after the loop below. diff --git a/tests/e2e/single/image_test.go b/tests/e2e/single/image_test.go index 9d5e65b8b..7d061ba26 100644 --- a/tests/e2e/single/image_test.go +++ b/tests/e2e/single/image_test.go @@ -11,12 +11,12 @@ import ( "github.com/stretchr/testify/require" ) -// phase4_Image rediscovers the architecture-appropriate Ubuntu AMI that +// runImage rediscovers the architecture-appropriate Ubuntu AMI that // bootstrap-install.sh imported from the pre-staged gold-image file // (~/images/ubuntu-{26,24}.04.img → `spx admin images import --file`) and // stashes the ID on the fixture for Phase 5+. Maps to run-e2e.sh ~233–255. -func phase4_Image(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 4 — Image Management") +func runImage(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Image Management") // Resolve the gold-image AMI via the cluster discovery helper. The first // caller pays the DescribeImages + state-poll cost; this and every other diff --git a/tests/e2e/single/instance_test.go b/tests/e2e/single/instance_test.go index b0cfe1b11..750e900bc 100644 --- a/tests/e2e/single/instance_test.go +++ b/tests/e2e/single/instance_test.go @@ -17,12 +17,12 @@ import ( "github.com/stretchr/testify/require" ) -// phase5_LaunchInstance bootstraps the suite's primary instance and asserts +// runInstanceLaunch bootstraps the suite's primary instance and asserts // that the live row exposes the AMI / type / key the launch was given. // Delegates the launch + memoization to needInstance so any sibling Test* // hits the same cached row. Maps to run-e2e.sh ~257–343. -func phase5_LaunchInstance(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5 — Instance Lifecycle") +func runInstanceLaunch(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Instance Lifecycle") def := harness.EnsureDefaultVPC(t, fix.Harness) require.NotEmpty(t, def.SGID, "default SG ID required") @@ -35,11 +35,11 @@ func phase5_LaunchInstance(t *testing.T, fix *Fixture) { "root_device", aws.StringValue(inst.RootDeviceName)) } -// phase5aPre_ClusterStats re-runs `spx get vms` now that a VM is running. +// runInstanceClusterStats re-runs `spx get vms` now that a VM is running. // Single-node only — multinode uses a different cluster surface. Maps to // run-e2e.sh ~345–353. -func phase5aPre_ClusterStats(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5a-pre — Cluster Stats CLI (with running VM)") +func runInstanceClusterStats(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Cluster Stats CLI (with running VM)") if fix.Env.Mode != harness.ModeSingle { t.Skipf("Phase 5a-pre is single-node only (mode=%s)", fix.Env.Mode) } @@ -52,10 +52,10 @@ func phase5aPre_ClusterStats(t *testing.T, fix *Fixture) { "spx get vms should list running instance %s\n%s", instanceID, vms) } -// phase5a_Metadata round-trips DescribeInstances and asserts the basic +// runInstanceMetadata round-trips DescribeInstances and asserts the basic // metadata fields match what RunInstances saw. Maps to run-e2e.sh ~355–379. -func phase5a_Metadata(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5a — Instance Metadata Validation") +func runInstanceMetadata(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Instance Metadata Validation") want, _ := needInstance(t, fix) instanceID := aws.StringValue(want.InstanceId) @@ -85,11 +85,11 @@ func phase5a_Metadata(t *testing.T, fix *Fixture) { ) } -// phase5aii_SSHProbe waits for SSH to become reachable, then runs `id`, +// runSSHProbe waits for SSH to become reachable, then runs `id`, // `lsblk`, and `hostname` against the guest to confirm the VM booted and // presents the expected root volume. Maps to run-e2e.sh ~381–463. -func phase5aii_SSHProbe(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5a-ii — SSH Connectivity & Volume Verification") +func runSSHProbe(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — SSH Connectivity Phase 5a-ii — SSH Connectivity & Volume Verification Volume Verification") inst, rootVolumeID := needInstance(t, fix) _, keyPath := needKeyPair(t, fix) @@ -147,11 +147,11 @@ func phase5aii_SSHProbe(t *testing.T, fix *Fixture) { } } -// phase5aiii_ConsoleOutput verifies GetConsoleOutput round-trips the +// runConsoleOutput verifies GetConsoleOutput round-trips the // instance ID. The payload itself is base64 cloud-init output; bash doesn't // decode it and neither do we. Maps to run-e2e.sh ~465–478. -func phase5aiii_ConsoleOutput(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5a-iii — Console Output") +func runConsoleOutput(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Console Output") inst, _ := needInstance(t, fix) instanceID := aws.StringValue(inst.InstanceId) diff --git a/tests/e2e/single/keypair_test.go b/tests/e2e/single/keypair_test.go index fecc63a13..0d8f7eaa0 100644 --- a/tests/e2e/single/keypair_test.go +++ b/tests/e2e/single/keypair_test.go @@ -17,13 +17,13 @@ import ( "golang.org/x/crypto/ssh" ) -// phase3_KeyPairs exercises CreateKeyPair / ImportKeyPair / DescribeKeyPairs / +// runKeyPairs exercises CreateKeyPair / ImportKeyPair / DescribeKeyPairs / // DeleteKeyPair. The primary key pair is materialised via harness.EnsureKeyPair // — it owns the create path's assertions, memoizes for downstream Phase 5+ // callers, and registers TestSingleNode-scoped cleanup. test-key-2 is created // via import then deleted within this phase. Maps to run-e2e.sh ~204–231. -func phase3_KeyPairs(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 3 — SSH Key Management") +func runKeyPairs(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — SSH Key Management") const key2 = "test-key-2" diff --git a/tests/e2e/single/lifecycle_test.go b/tests/e2e/single/lifecycle_test.go index 1dca0272b..8a1bd8f5f 100644 --- a/tests/e2e/single/lifecycle_test.go +++ b/tests/e2e/single/lifecycle_test.go @@ -18,13 +18,13 @@ import ( "github.com/stretchr/testify/require" ) -// phase7_StopStart stops fix.Instance and waits for it to reach the +// runStopStart stops fix.Instance and waits for it to reach the // "stopped" state, then asserts that rebooting a stopped instance is // rejected with IncorrectInstanceState. Leaves the instance stopped so // Phase 7a / 7b can act against the stopped state. Maps to run-e2e.sh // ~1027–1053. -func phase7_StopStart(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 7 — Instance State Transitions (Stop)") +func runStopStart(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Instance State Transitions (Stop)") inst, _ := needInstance(t, fix) instanceID := aws.StringValue(inst.InstanceId) @@ -58,13 +58,13 @@ func phase7_StopStart(t *testing.T, fix *Fixture) { harness.WaitForInstanceState(t, fix.AWS, instanceID, "running") } -// phase7a_AttachToStoppedError creates a fresh 10 GiB volume and attempts +// runAttachToStoppedError creates a fresh 10 GiB volume and attempts // to attach it to the (currently stopped) primary instance. The attach // must fail with IncorrectInstanceState. The test volume is deleted // in-line on success and via t.Cleanup on early failure. Maps to // run-e2e.sh ~1054–1068. -func phase7a_AttachToStoppedError(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 7a — Attach Volume to Stopped Instance (Error Path)") +func runAttachToStoppedError(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Attach Volume to Stopped Instance (Error Path)") inst, _ := needInstance(t, fix) instanceID := aws.StringValue(inst.InstanceId) @@ -128,13 +128,13 @@ func phase7a_AttachToStoppedError(t *testing.T, fix *Fixture) { cleaned = true } -// phase7b_ModifyInstanceAttribute changes the (stopped) instance type to +// runModifyInstanceAttribute changes the (stopped) instance type to // the same-family ".small" upsize, starts the instance, SSHes in to // verify the new vCPU + memory budget, then stops the instance again so // Phase 7c-pre can drive its own start/reboot cycle. Maps to run-e2e.sh // ~1070–1177. -func phase7b_ModifyInstanceAttribute(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 7b — ModifyInstanceAttribute") +func runModifyInstanceAttribute(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — ModifyInstanceAttribute") inst, _ := needInstance(t, fix) instanceID := aws.StringValue(inst.InstanceId) @@ -252,14 +252,14 @@ func phase7b_ModifyInstanceAttribute(t *testing.T, fix *Fixture) { // Cleanup restores original type + running state for sibling Test*. } -// phase7cPre_Reboot starts the (stopped) primary instance, captures its +// runRebootInstance starts the (stopped) primary instance, captures its // pre-reboot private IP, issues a reboot, asserts the API never reports a // non-running state during a short polling window, waits for SSH to come // back, and verifies the guest actually rebooted (uptime < 120s) without // changing its private IP. Leaves the instance running. Maps to // run-e2e.sh ~1178–1236. -func phase7cPre_Reboot(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 7c-pre — Reboot Running Instance") +func runRebootInstance(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Reboot Running Instance") inst, _ := needInstance(t, fix) instanceID := aws.StringValue(inst.InstanceId) @@ -326,13 +326,13 @@ func phase7cPre_Reboot(t *testing.T, fix *Fixture) { // and Phase 8 expects the primary instance to still be up. } -// phase7c_RunInstancesMultiCount launches 2 sibling instances in a single +// runRunInstancesMultiCount launches 2 sibling instances in a single // RunInstances call, waits for both to reach "running", then terminates // them and waits for both to reach "terminated". The primary fix.Instance // is untouched and remains running for Phase 8. Maps to run-e2e.sh // ~1238–1296. -func phase7c_RunInstancesMultiCount(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 7c — RunInstances with MinCount/MaxCount > 1") +func runRunInstancesMultiCount(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — RunInstances with MinCount/MaxCount > 1") amiID := needAMI(t, fix) instType, _ := needInstanceTypeArch(t, fix) diff --git a/tests/e2e/single/natgw_test.go b/tests/e2e/single/natgw_test.go index 76eff5c18..ba057e286 100644 --- a/tests/e2e/single/natgw_test.go +++ b/tests/e2e/single/natgw_test.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/require" ) -// phase8d_NATGateway ports run-e2e.sh ~3017–3161 (Phase 8d). +// runNATGateway ports run-e2e.sh ~3017–3161 (Phase 8d). // // Stands up its own bastion + private-instance pair in the default VPC, // allocates a NAT Gateway in the default (public) subnet, attaches a @@ -30,11 +30,11 @@ import ( // sibling Stage F file). Everything launched here is torn down LIFO by // the registered t.Cleanup so a failure mid-flight still releases the // EIP and terminates both VMs. -func phase8d_NATGateway(t *testing.T, fix *Fixture) { +func runNATGateway(t *testing.T, fix *Fixture) { if !fix.PoolMode { t.Skip("Phase 8d requires pool-mode networking") } - harness.Phase(t, "Phase 8d — NAT Gateway E2E") + harness.Phase(t, "Single — NAT Gateway E2E") amiID := needAMI(t, fix) instType, _ := needInstanceTypeArch(t, fix) diff --git a/tests/e2e/single/negative_test.go b/tests/e2e/single/negative_test.go index 182e03825..6f8074c9f 100644 --- a/tests/e2e/single/negative_test.go +++ b/tests/e2e/single/negative_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" ) -// phase8_NegativeErrorPaths ports run-e2e.sh Phase 8 (lines ~1298–1399): +// runNegativeErrorPaths ports run-e2e.sh Phase 8 (lines ~1298–1399): // every sub-test exercises a single error code on the gateway. Each case // runs in its own t.Run so one failure doesn't poison the others; cleanup // is defensive (calls that unexpectedly succeed get torn down). @@ -36,8 +36,8 @@ import ( // 8p (idempotent) — DeleteKeyPair for unknown key must succeed // 8q InvalidInstanceID.NotFound — ModifyInstanceAttribute on running inst // 8r InvalidInstanceID.NotFound — RebootInstances on unknown id -func phase8_NegativeErrorPaths(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 8 — Negative / Error Path Tests") +func runNegativeErrorPaths(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Negative / Error Path Tests") // Bootstrap every prereq up front so the parallel sub-tests below all // see populated locals. diff --git a/tests/e2e/single/securitygroup_test.go b/tests/e2e/single/securitygroup_test.go index 390eafeb6..fe36ab265 100644 --- a/tests/e2e/single/securitygroup_test.go +++ b/tests/e2e/single/securitygroup_test.go @@ -26,12 +26,12 @@ var pingReceivedRE = regexp.MustCompile(`[1-3] (packets )?received`) // `0 received` or `100% packet loss`. Mirrors the bash grep pattern. var pingDroppedRE = regexp.MustCompile(`0 (packets )?received|100% packet loss`) -// phase5f_SecurityGroupEgress flips the default SG's allow-all egress rule and +// runSecurityGroupEgress flips the default SG's allow-all egress rule and // verifies vpcd programs OVN ACLs that actually drop traffic. Egress is tested // because in dev_networking mode ingress SSH bypasses OVN via QEMU hostfwd — // only egress hits the ACL. Maps to run-e2e.sh ~846–928. -func phase5f_SecurityGroupEgress(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5f — Security Group Enforcement (egress ACL)") +func runSecurityGroupEgress(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Security Group Enforcement (egress ACL)") inst, _ := needInstance(t, fix) _, keyPath := needKeyPair(t, fix) diff --git a/tests/e2e/single/snapshot_test.go b/tests/e2e/single/snapshot_test.go index 95c7eaacc..7b4538cd7 100644 --- a/tests/e2e/single/snapshot_test.go +++ b/tests/e2e/single/snapshot_test.go @@ -14,12 +14,12 @@ import ( "github.com/stretchr/testify/require" ) -// phase5c_SnapshotLifecycle creates, describes, copies, and deletes a +// runSnapshotLifecycle creates, describes, copies, and deletes a // snapshot off the running instance's root volume (the only volume that's // definitely backed by a mounted viperblock instance — create-snapshot // requires that). Maps to run-e2e.sh ~627–786. -func phase5c_SnapshotLifecycle(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5c — Snapshot Lifecycle") +func runSnapshotLifecycle(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Snapshot Lifecycle") _, rootVolumeID := needInstance(t, fix) @@ -140,14 +140,14 @@ func phase5c_SnapshotLifecycle(t *testing.T, fix *Fixture) { harness.Detail(t, "deleted_original", snapshotID) } -// phase5d_SnapshotBackedLaunch verifies the AMI used for the live instance +// runSnapshotBackedLaunch verifies the AMI used for the live instance // carries a snapshot reference — proof the launch went through the // cloneAMIToVolume → OpenFromSnapshot path. Maps to run-e2e.sh ~788–803. // // Bash's prose mentions verifying the predastore-side snapshot config, but // the actual bash only checks the EC2 API. We follow the bash. -func phase5d_SnapshotBackedLaunch(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5d — Snapshot-Backed Instance Launch") +func runSnapshotBackedLaunch(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Snapshot-Backed Instance Launch") amiID := needAMI(t, fix) diff --git a/tests/e2e/single/tags_test.go b/tests/e2e/single/tags_test.go index 2f60b41d2..43e8eacb2 100644 --- a/tests/e2e/single/tags_test.go +++ b/tests/e2e/single/tags_test.go @@ -12,14 +12,14 @@ import ( "github.com/stretchr/testify/require" ) -// phase6_TagManagement exercises CreateTags / DescribeTags / DeleteTags +// runTagManagement exercises CreateTags / DescribeTags / DeleteTags // against the Phase 5 instance and its root volume. Maps to run-e2e.sh // ~930–1026. Sub-steps mirror the bash 6a–6j checks; we additionally // assert in 6i that the value-conditional DeleteTags scoped to the // instance does NOT touch the matching tag on the root volume, which the // bash driver only implies via per-resource targeting. -func phase6_TagManagement(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 6 — Tag Management") +func runTagManagement(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Tag Management") inst, rootVolumeID := needInstance(t, fix) instanceID := aws.StringValue(inst.InstanceId) diff --git a/tests/e2e/single/teardown_test.go b/tests/e2e/single/teardown_test.go index b55a3e65c..47ec5953d 100644 --- a/tests/e2e/single/teardown_test.go +++ b/tests/e2e/single/teardown_test.go @@ -9,12 +9,12 @@ import ( "github.com/mulgadc/spinifex/tests/e2e/harness" ) -// phase9b_FinalClusterStats is a single-node sanity pass against `spx get +// runFinalClusterStats is a single-node sanity pass against `spx get // vms`. Replaces the umbrella's phase9 + phase9a (deleted) — resource // cleanup is now owned by harness.Fixture.Close, invoked from TestMain // after every Test* in the package has run. -func phase9b_FinalClusterStats(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 9b — Final Cluster Stats") +func runFinalClusterStats(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Final Cluster Stats") if fix.Env.Mode != harness.ModeSingle { t.Skipf("Phase 9b is single-node only (mode=%s)", fix.Env.Mode) } diff --git a/tests/e2e/single/tests_test.go b/tests/e2e/single/tests_test.go index 14778aa38..02d633e81 100644 --- a/tests/e2e/single/tests_test.go +++ b/tests/e2e/single/tests_test.go @@ -4,122 +4,203 @@ package single import "testing" -// Top-level Test* entry points. Each delegates to a phaseN_X function in -// this package, passing the package-scoped Fixture singleton. +// Top-level Test* entry points. Each delegates to a runX function in the +// matching _test.go file. Names are number-free (TestX) so isolated +// runs via `go test -run TestKeyPairs` are stable. // -// Every phase function self-bootstraps any prerequisite resource it needs -// via harness.Discover* / harness.Ensure* (or the package-local need* / -// iamEnsure* helpers), so a targeted `go test -run TestX` run works in -// isolation without depending on a sibling Test* having stashed state. +// Every run* function self-bootstraps prerequisites via harness.Discover* / +// harness.Ensure* (or the package-local need* / iamEnsure* helpers), so a +// targeted `go test -run TestX` invocation works in isolation without +// relying on a sibling Test* having stashed state. +// +// Parallelism (mulga-siv-128): +// +// Bucket #1 (parallel): read-only or own-everything Tests below call +// t.Parallel(). They share the package fixture but never mutate the +// singleton EC2 instance, default VPC, or default SG. +// +// Sequential (no t.Parallel — would race the singleton VM or shared state): +// - TestInstanceLaunch : first sequential — boots singleton. +// - TestInstanceClusterStats / Metadata +// / SSHProbe / ConsoleOutput : read singleton. +// - TestVolumeLifecycle / VolumeStatus : attach to singleton. +// - TestSnapshotLifecycle / +// SnapshotBackedLaunch / CreateImage : snapshot singleton. +// - TestSecurityGroupEgress : mutates default SG. +// - TestStopStart / AttachToStoppedError +// / ModifyInstanceAttribute / +// RebootInstance / RunInstancesMultiCount : mutate singleton state. +// - TestNegativeErrorPaths : sub-tests already parallel inside. +// - TestNATGateway / TestSGToSGDatapath : share EIP pool. +// - All TestIAM* : share IAM policy state via the +// package-scoped IAM fixture; sub-tests inside each already parallel. +// - TestFinalClusterStats : final sanity gate. -// Discovery + environment. -func TestEnvironment(t *testing.T) { phase1_Environment(t, requireSingleNodeFixture(t)) } -func TestClusterStatsCLI(t *testing.T) { phase1b_ClusterStats(t, requireSingleNodeFixture(t)) } -func TestDiscovery(t *testing.T) { phase2_Discovery(t, requireSingleNodeFixture(t)) } -func TestSerialConsoleAccess(t *testing.T) { phase2b_SerialConsole(t, requireSingleNodeFixture(t)) } +// --- Bucket #1: parallel-safe --- -// Key pairs + image. -func TestKeyPairs(t *testing.T) { phase3_KeyPairs(t, requireSingleNodeFixture(t)) } -func TestImage(t *testing.T) { phase4_Image(t, requireSingleNodeFixture(t)) } - -// Instance lifecycle. -func TestInstanceLaunch(t *testing.T) { - phase5_LaunchInstance(t, requireSingleNodeFixture(t)) -} -func TestInstanceClusterStats(t *testing.T) { - phase5aPre_ClusterStats(t, requireSingleNodeFixture(t)) -} -func TestInstanceMetadata(t *testing.T) { - phase5a_Metadata(t, requireSingleNodeFixture(t)) -} -func TestSSHProbe(t *testing.T) { - phase5aii_SSHProbe(t, requireSingleNodeFixture(t)) -} -func TestConsoleOutput(t *testing.T) { - phase5aiii_ConsoleOutput(t, requireSingleNodeFixture(t)) +func TestEnvironment(t *testing.T) { + t.Parallel() + runEnvironment(t, requireSingleNodeFixture(t)) } -// Volume + snapshot + AMI. -func TestVolumeLifecycle(t *testing.T) { - phase5b_VolumeLifecycle(t, requireSingleNodeFixture(t)) -} -func TestVolumeStatus(t *testing.T) { - phase5bii_VolumeStatus(t, requireSingleNodeFixture(t)) -} -func TestSnapshotLifecycle(t *testing.T) { - phase5c_SnapshotLifecycle(t, requireSingleNodeFixture(t)) -} -func TestSnapshotBackedLaunch(t *testing.T) { - phase5d_SnapshotBackedLaunch(t, requireSingleNodeFixture(t)) -} -func TestCreateImage(t *testing.T) { - phase5e_CreateImage(t, requireSingleNodeFixture(t)) -} -func TestSecurityGroupEgress(t *testing.T) { - phase5f_SecurityGroupEgress(t, requireSingleNodeFixture(t)) +func TestClusterStatsCLI(t *testing.T) { + t.Parallel() + runClusterStatsCLI(t, requireSingleNodeFixture(t)) } -// Tags + lifecycle transitions. -func TestTagManagement(t *testing.T) { phase6_TagManagement(t, requireSingleNodeFixture(t)) } -func TestStopStart(t *testing.T) { phase7_StopStart(t, requireSingleNodeFixture(t)) } -func TestAttachToStoppedError(t *testing.T) { - phase7a_AttachToStoppedError(t, requireSingleNodeFixture(t)) -} -func TestModifyInstanceAttribute(t *testing.T) { - phase7b_ModifyInstanceAttribute(t, requireSingleNodeFixture(t)) -} -func TestRebootInstance(t *testing.T) { - phase7cPre_Reboot(t, requireSingleNodeFixture(t)) -} -func TestRunInstancesMultiCount(t *testing.T) { - phase7c_RunInstancesMultiCount(t, requireSingleNodeFixture(t)) +func TestDiscovery(t *testing.T) { + t.Parallel() + runDiscovery(t, requireSingleNodeFixture(t)) } -// Negative / error paths. -func TestNegativeErrorPaths(t *testing.T) { - phase8_NegativeErrorPaths(t, requireSingleNodeFixture(t)) +func TestSerialConsoleAccess(t *testing.T) { + t.Parallel() + runSerialConsoleAccess(t, requireSingleNodeFixture(t)) } -// IAM 1–7. -func TestIAM1_UserCRUD(t *testing.T) { - phaseIAM1_UserCRUD(t, requireSingleNodeFixture(t)) -} -func TestIAM2_AccessKeyLifecycle(t *testing.T) { - phaseIAM2_AccessKeyLifecycle(t, requireSingleNodeFixture(t)) -} -func TestIAM3_UserAuthentication(t *testing.T) { - phaseIAM3_UserAuthentication(t, requireSingleNodeFixture(t)) -} -func TestIAM4_PolicyCRUD(t *testing.T) { - phaseIAM4_PolicyCRUD(t, requireSingleNodeFixture(t)) -} -func TestIAM5_PolicyAttachmentEnforcement(t *testing.T) { - phaseIAM5_PolicyAttachmentEnforcement(t, requireSingleNodeFixture(t)) -} -func TestIAM6_PolicyLifecycle(t *testing.T) { - phaseIAM6_PolicyLifecycle(t, requireSingleNodeFixture(t)) -} -func TestIAM7_Cleanup(t *testing.T) { - phaseIAM7_Cleanup(t, requireSingleNodeFixture(t)) +func TestKeyPairs(t *testing.T) { + t.Parallel() + runKeyPairs(t, requireSingleNodeFixture(t)) +} + +func TestImage(t *testing.T) { + t.Parallel() + runImage(t, requireSingleNodeFixture(t)) +} + +func TestTagManagement(t *testing.T) { + t.Parallel() + runTagManagement(t, requireSingleNodeFixture(t)) } -// Account scoping. func TestAccountScoping(t *testing.T) { - phase8Acct_AccountScoping(t, requireSingleNodeFixture(t)) + t.Parallel() + runAccountScoping(t, requireSingleNodeFixture(t)) } -// VPC / NAT / datapath. func TestVPCSubnetE2E(t *testing.T) { - phase8b_VPCSubnetE2E(t, requireSingleNodeFixture(t)) + t.Parallel() + runVPCSubnetE2E(t, requireSingleNodeFixture(t)) } -func TestRouteTableValidation(t *testing.T) { - phase8c_RouteTableValidation(t, requireSingleNodeFixture(t)) -} -func TestNATGateway(t *testing.T) { phase8d_NATGateway(t, requireSingleNodeFixture(t)) } -func TestSGToSGDatapath(t *testing.T) { phase8e_SGToSGDatapath(t, requireSingleNodeFixture(t)) } -// Final cluster sanity (replaces the umbrella's phase9b — phase9 + phase9a -// deleted; harness.Fixture.Close drains cleanups at process exit). -func TestFinalClusterStats(t *testing.T) { - phase9b_FinalClusterStats(t, requireSingleNodeFixture(t)) +func TestRouteTableValidation(t *testing.T) { + t.Parallel() + runRouteTableValidation(t, requireSingleNodeFixture(t)) +} + +// --- Sequential: singleton VM lifecycle --- + +func TestInstanceLaunch(t *testing.T) { + runInstanceLaunch(t, requireSingleNodeFixture(t)) +} + +func TestInstanceClusterStats(t *testing.T) { + runInstanceClusterStats(t, requireSingleNodeFixture(t)) +} + +func TestInstanceMetadata(t *testing.T) { + runInstanceMetadata(t, requireSingleNodeFixture(t)) +} + +func TestSSHProbe(t *testing.T) { + runSSHProbe(t, requireSingleNodeFixture(t)) +} + +func TestConsoleOutput(t *testing.T) { + runConsoleOutput(t, requireSingleNodeFixture(t)) +} + +func TestVolumeLifecycle(t *testing.T) { + runVolumeLifecycle(t, requireSingleNodeFixture(t)) +} + +func TestVolumeStatus(t *testing.T) { + runVolumeStatus(t, requireSingleNodeFixture(t)) +} + +func TestSnapshotLifecycle(t *testing.T) { + runSnapshotLifecycle(t, requireSingleNodeFixture(t)) +} + +func TestSnapshotBackedLaunch(t *testing.T) { + runSnapshotBackedLaunch(t, requireSingleNodeFixture(t)) +} + +func TestCreateImage(t *testing.T) { + runCreateImage(t, requireSingleNodeFixture(t)) +} + +func TestSecurityGroupEgress(t *testing.T) { + runSecurityGroupEgress(t, requireSingleNodeFixture(t)) +} + +func TestStopStart(t *testing.T) { + runStopStart(t, requireSingleNodeFixture(t)) +} + +func TestAttachToStoppedError(t *testing.T) { + runAttachToStoppedError(t, requireSingleNodeFixture(t)) +} + +func TestModifyInstanceAttribute(t *testing.T) { + runModifyInstanceAttribute(t, requireSingleNodeFixture(t)) +} + +func TestRebootInstance(t *testing.T) { + runRebootInstance(t, requireSingleNodeFixture(t)) +} + +func TestRunInstancesMultiCount(t *testing.T) { + runRunInstancesMultiCount(t, requireSingleNodeFixture(t)) +} + +// --- Sequential: shared-state / sub-test-parallel Tests --- + +func TestNegativeErrorPaths(t *testing.T) { + runNegativeErrorPaths(t, requireSingleNodeFixture(t)) +} + +func TestNATGateway(t *testing.T) { + runNATGateway(t, requireSingleNodeFixture(t)) +} + +func TestSGToSGDatapath(t *testing.T) { + runSGToSGDatapath(t, requireSingleNodeFixture(t)) +} + +// IAM Tests share the package-scoped IAM fixture; sub-tests inside each +// runIAM* already use t.Parallel for fan-out. +func TestIAMUserCRUD(t *testing.T) { + runIAMUserCRUD(t, requireSingleNodeFixture(t)) +} + +func TestIAMAccessKeyLifecycle(t *testing.T) { + runIAMAccessKeyLifecycle(t, requireSingleNodeFixture(t)) +} + +func TestIAMUserAuthentication(t *testing.T) { + runIAMUserAuthentication(t, requireSingleNodeFixture(t)) +} + +func TestIAMPolicyCRUD(t *testing.T) { + runIAMPolicyCRUD(t, requireSingleNodeFixture(t)) +} + +func TestIAMPolicyAttachmentEnforcement(t *testing.T) { + runIAMPolicyAttachmentEnforcement(t, requireSingleNodeFixture(t)) +} + +func TestIAMPolicyLifecycle(t *testing.T) { + runIAMPolicyLifecycle(t, requireSingleNodeFixture(t)) +} + +func TestIAMCleanup(t *testing.T) { + runIAMCleanup(t, requireSingleNodeFixture(t)) +} + +// TestFinalClusterStats runs as the last sequential test (parallel bucket +// runs afterwards, but those Tests are read-only / own-everything so a +// later cluster-stats snapshot would still be valid). +func TestFinalClusterStats(t *testing.T) { + runFinalClusterStats(t, requireSingleNodeFixture(t)) } diff --git a/tests/e2e/single/volume_test.go b/tests/e2e/single/volume_test.go index fde67e1c0..585e2c661 100644 --- a/tests/e2e/single/volume_test.go +++ b/tests/e2e/single/volume_test.go @@ -15,11 +15,11 @@ import ( "github.com/stretchr/testify/require" ) -// phase5b_VolumeLifecycle exercises create → modify → attach → detach → +// runVolumeLifecycle exercises create → modify → attach → detach → // delete on a fresh 10 GiB volume against the running Phase 5 instance. // Maps to run-e2e.sh ~488–612. -func phase5b_VolumeLifecycle(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5b — Volume Lifecycle (Attach/Detach)") +func runVolumeLifecycle(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Volume Lifecycle (Attach/Detach)") az := needAZ(t, fix) inst, _ := needInstance(t, fix) @@ -133,10 +133,10 @@ func phase5b_VolumeLifecycle(t *testing.T, fix *Fixture) { }, 2*time.Minute, 2*time.Second) } -// phase5bii_VolumeStatus runs DescribeVolumeStatus against the root volume +// runVolumeStatus runs DescribeVolumeStatus against the root volume // and asserts the response references it back. Maps to run-e2e.sh ~614–625. -func phase5bii_VolumeStatus(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 5b-ii — DescribeVolumeStatus") +func runVolumeStatus(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — DescribeVolumeStatus") _, rootVolumeID := needInstance(t, fix) diff --git a/tests/e2e/single/vpc_test.go b/tests/e2e/single/vpc_test.go index cffda3e2f..df685d5e9 100644 --- a/tests/e2e/single/vpc_test.go +++ b/tests/e2e/single/vpc_test.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/require" ) -// phase8b_VPCSubnetE2E ports run-e2e.sh Phase 8b (~2747-3496). +// runVPCSubnetE2E ports run-e2e.sh Phase 8b (~2747-3496). // // The bash driver layers Phase 8b on top of the *default* VPC + IGW that // admin init prebakes, then leans on Phase 8d / 8e to share the public and @@ -39,11 +39,11 @@ import ( // VPC graph down in the correct order: instance -> wait terminated -> // disassociate route table -> delete route(s) -> delete route table -> // detach IGW -> delete IGW -> delete subnets -> delete VPC. -func phase8b_VPCSubnetE2E(t *testing.T, fix *Fixture) { +func runVPCSubnetE2E(t *testing.T, fix *Fixture) { if !fix.PoolMode { t.Skip("Phase 8b requires pool-mode networking") } - harness.Phase(t, "Phase 8b — VPC Public/Private Subnet E2E") + harness.Phase(t, "Single — VPC Public/Private Subnet E2E") amiID := needAMI(t, fix) instType, _ := needInstanceTypeArch(t, fix) @@ -293,7 +293,7 @@ func phase8b_VPCSubnetE2E(t *testing.T, fix *Fixture) { } } -// phase8c_RouteTableValidation ports run-e2e.sh Phase 8c (~2626-2745). +// runRouteTableValidation ports run-e2e.sh Phase 8c (~2626-2745). // // Validates route-table CRUD + invariants against the *default* VPC's main // route table (always runs — no pool-mode gating). Three sub-tests: @@ -310,8 +310,8 @@ func phase8b_VPCSubnetE2E(t *testing.T, fix *Fixture) { // // Each step registers its own cleanup so a partial run still releases the // scratch route table / association regardless of which assertion fired. -func phase8c_RouteTableValidation(t *testing.T, fix *Fixture) { - harness.Phase(t, "Phase 8c — Route Table Validation") +func runRouteTableValidation(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — Route Table Validation") c := fix.AWS