mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-23 12:47:48 +00:00
- 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).
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
+180
-99
@@ -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 <name>_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))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user