diff --git a/spinifex/handlers/ec2/vpc/default_subnet_mapping_test.go b/spinifex/handlers/ec2/vpc/default_subnet_mapping_test.go index be15ce33b..c5651ad8b 100644 --- a/spinifex/handlers/ec2/vpc/default_subnet_mapping_test.go +++ b/spinifex/handlers/ec2/vpc/default_subnet_mapping_test.go @@ -10,6 +10,7 @@ import ( ) func TestEnsureDefaultVPC_PublicIPMappingDisabled(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) svc.SetDefaultPublicIPMapping(false) @@ -24,6 +25,7 @@ func TestEnsureDefaultVPC_PublicIPMappingDisabled(t *testing.T) { } func TestEnsureDefaultVPC_PublicIPMappingDefaultOn(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.EnsureDefaultVPC(testAccountID) diff --git a/spinifex/handlers/ec2/vpc/eni_abandoned_test.go b/spinifex/handlers/ec2/vpc/eni_abandoned_test.go index 7559c7330..a05fbf822 100644 --- a/spinifex/handlers/ec2/vpc/eni_abandoned_test.go +++ b/spinifex/handlers/ec2/vpc/eni_abandoned_test.go @@ -35,6 +35,7 @@ func createAutoENI(t *testing.T, svc *VPCServiceImpl, subnetID, instanceID strin } func TestListAbandonedInstanceENIs(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -69,6 +70,7 @@ func TestListAbandonedInstanceENIs(t *testing.T) { // records that do name an instance, which is where a zombie hides. The two // listings must not overlap, or a sweep would act on the same record twice. func TestListAttachedInstanceENIs(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -102,6 +104,7 @@ func TestListAttachedInstanceENIs(t *testing.T) { // A record written before CreatedAt existed carries no age, and age is the only // thing standing between this listing and an ENI a launch is still using. func TestListAttachedInstanceENIsIgnoresZeroCreatedAt(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -122,6 +125,7 @@ func TestListAttachedInstanceENIsIgnoresZeroCreatedAt(t *testing.T) { // worth sweeping: the SG dependency check counts an abandoned ENI, so the group // stays undeletable for as long as the record survives. func TestAbandonedENIBlocksSecurityGroupDelete(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") diff --git a/spinifex/handlers/ec2/vpc/eni_hotplug_helpers_test.go b/spinifex/handlers/ec2/vpc/eni_hotplug_helpers_test.go index 2b78ca48f..20c51311a 100644 --- a/spinifex/handlers/ec2/vpc/eni_hotplug_helpers_test.go +++ b/spinifex/handlers/ec2/vpc/eni_hotplug_helpers_test.go @@ -11,6 +11,7 @@ import ( ) func TestGetENIRecord(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -25,12 +26,14 @@ func TestGetENIRecord(t *testing.T) { } func TestGetENIRecord_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.GetENIRecord(testAccountID, "eni-nonexistent") assert.ErrorContains(t, err, "InvalidNetworkInterfaceID.NotFound") } func TestUpdateENI_PatchesFields(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -51,6 +54,7 @@ func TestUpdateENI_PatchesFields(t *testing.T) { } func TestUpdateENI_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) err := svc.UpdateENI(testAccountID, "eni-nonexistent", func(r *ENIRecord) { r.AttachmentStatus = "attached" @@ -59,6 +63,7 @@ func TestUpdateENI_NotFound(t *testing.T) { } func TestUpdateENI_NoopPatchPersists(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -73,6 +78,7 @@ func TestUpdateENI_NoopPatchPersists(t *testing.T) { } func TestFindENIByAttachment(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -89,12 +95,14 @@ func TestFindENIByAttachment(t *testing.T) { } func TestFindENIByAttachment_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.FindENIByAttachment(testAccountID, "eni-attach-missing") assert.ErrorContains(t, err, "InvalidAttachmentID.NotFound") } func TestFindENIByAttachment_AccountScoped(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -111,6 +119,7 @@ func TestFindENIByAttachment_AccountScoped(t *testing.T) { // ENIRecord so a struct-field rename would surface as a test failure rather // than a silent JSON-tag drift. func TestUpdateENI_RoundTripsAllNewFields(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -136,6 +145,7 @@ func TestUpdateENI_RoundTripsAllNewFields(t *testing.T) { // TestUpdateENI_PreservesUnrelatedFields ensures a partial patch does not // clobber pre-existing record state. func TestUpdateENI_PreservesUnrelatedFields(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") diff --git a/spinifex/handlers/ec2/vpc/eni_lease_rebind_test.go b/spinifex/handlers/ec2/vpc/eni_lease_rebind_test.go index 73912b1bc..c1033b401 100644 --- a/spinifex/handlers/ec2/vpc/eni_lease_rebind_test.go +++ b/spinifex/handlers/ec2/vpc/eni_lease_rebind_test.go @@ -33,6 +33,7 @@ func stubAddNAT(t *testing.T, nc *nats.Conn, fail string) *[]string { } func TestRebindENIPublicIP_MovesRecordAndNAT(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) seen := stubAddNAT(t, nc, "") vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -56,6 +57,7 @@ func TestRebindENIPublicIP_MovesRecordAndNAT(t *testing.T) { // A NAT commit failure leaves the instance with no working ingress, so the // record must not be moved to advertise an address that does not route. func TestRebindENIPublicIP_NATFailureLeavesRecord(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) stubAddNAT(t, nc, "ovn unreachable") vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -72,6 +74,7 @@ func TestRebindENIPublicIP_NATFailureLeavesRecord(t *testing.T) { } func TestRebindENIPublicIP_IsIdempotent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) stubAddNAT(t, nc, "") vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -84,6 +87,7 @@ func TestRebindENIPublicIP_IsIdempotent(t *testing.T) { } func TestRebindENIPublicIP_RejectsMismatchAndUnknown(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) stubAddNAT(t, nc, "") vpcID := createTestVPC(t, svc, "10.0.0.0/16") diff --git a/spinifex/handlers/ec2/vpc/eni_mac_test.go b/spinifex/handlers/ec2/vpc/eni_mac_test.go index ee0444358..3b93615e8 100644 --- a/spinifex/handlers/ec2/vpc/eni_mac_test.go +++ b/spinifex/handlers/ec2/vpc/eni_mac_test.go @@ -9,18 +9,21 @@ import ( ) func TestGenerateENIMac_Deterministic(t *testing.T) { + t.Parallel() mac1 := generateENIMac("eni-abc123") mac2 := generateENIMac("eni-abc123") assert.Equal(t, mac1, mac2, "same input must produce same MAC") } func TestGenerateENIMac_DifferentInputs(t *testing.T) { + t.Parallel() mac1 := generateENIMac("eni-aaa") mac2 := generateENIMac("eni-bbb") assert.NotEqual(t, mac1, mac2, "different inputs should produce different MACs") } func TestGenerateENIMac_LocallyAdministered(t *testing.T) { + t.Parallel() mac := generateENIMac("eni-test123") hw, err := net.ParseMAC(mac) require.NoError(t, err) @@ -29,6 +32,7 @@ func TestGenerateENIMac_LocallyAdministered(t *testing.T) { } func TestGenerateENIMac_EmptyString(t *testing.T) { + t.Parallel() mac := generateENIMac("") hw, err := net.ParseMAC(mac) require.NoError(t, err) diff --git a/spinifex/handlers/ec2/vpc/eni_test.go b/spinifex/handlers/ec2/vpc/eni_test.go index a2057ad50..379719dea 100644 --- a/spinifex/handlers/ec2/vpc/eni_test.go +++ b/spinifex/handlers/ec2/vpc/eni_test.go @@ -29,6 +29,7 @@ func createTestENI(t *testing.T, svc *VPCServiceImpl, subnetId string) string { } func TestCreateNetworkInterface(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -49,6 +50,7 @@ func TestCreateNetworkInterface(t *testing.T) { } func TestCreateNetworkInterface_SequentialIPs(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -67,12 +69,14 @@ func TestCreateNetworkInterface_SequentialIPs(t *testing.T) { } func TestCreateNetworkInterface_MissingSubnet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateNetworkInterface(context.Background(), &ec2.CreateNetworkInterfaceInput{}, testAccountID) assert.ErrorContains(t, err, "MissingParameter") } func TestCreateNetworkInterface_InvalidSubnet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateNetworkInterface(context.Background(), &ec2.CreateNetworkInterfaceInput{ SubnetId: aws.String("subnet-nonexistent"), @@ -81,6 +85,7 @@ func TestCreateNetworkInterface_InvalidSubnet(t *testing.T) { } func TestCreateNetworkInterface_WithTags(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -109,6 +114,7 @@ func TestCreateNetworkInterface_WithTags(t *testing.T) { // marks the ENIRecord SuppressDHCP, threads it into the vpc.create-port event // for vpcd, and never persists as a customer-visible tag. func TestCreateNetworkInterface_DHCPDisabledTag_SuppressesDHCP(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -155,6 +161,7 @@ func TestCreateNetworkInterface_DHCPDisabledTag_SuppressesDHCP(t *testing.T) { // ordinary ENI (no internal tag) is unaffected: SuppressDHCP stays false and // the wire event carries no suppress_dhcp marker. func TestCreateNetworkInterface_NoDHCPDisabledTag_LeavesDHCPEnabled(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -185,6 +192,7 @@ func TestCreateNetworkInterface_NoDHCPDisabledTag_LeavesDHCPEnabled(t *testing.T } func TestDeleteNetworkInterface(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -203,6 +211,7 @@ func TestDeleteNetworkInterface(t *testing.T) { } func TestDeleteNetworkInterface_InUse(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -220,6 +229,7 @@ func TestDeleteNetworkInterface_InUse(t *testing.T) { } func TestDeleteNetworkInterface_ReleasesIP(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -245,6 +255,7 @@ func TestDeleteNetworkInterface_ReleasesIP(t *testing.T) { } func TestDescribeNetworkInterfaces_All(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -258,6 +269,7 @@ func TestDescribeNetworkInterfaces_All(t *testing.T) { } func TestDescribeNetworkInterfaces_ByID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -274,6 +286,7 @@ func TestDescribeNetworkInterfaces_ByID(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterBySubnet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetA := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -293,6 +306,7 @@ func TestDescribeNetworkInterfaces_FilterBySubnet(t *testing.T) { } func TestDescribeNetworkInterfaces_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DescribeNetworkInterfaces(context.Background(), &ec2.DescribeNetworkInterfacesInput{ NetworkInterfaceIds: []*string{aws.String("eni-nonexistent")}, @@ -301,6 +315,7 @@ func TestDescribeNetworkInterfaces_NotFound(t *testing.T) { } func TestAttachENI(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -323,6 +338,7 @@ func TestAttachENI(t *testing.T) { } func TestAttachENI_AlreadyAttached(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -337,6 +353,7 @@ func TestAttachENI_AlreadyAttached(t *testing.T) { } func TestDetachENI(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -379,6 +396,7 @@ func (k *failNTimesDeleteKV) Delete(ctx context.Context, key string, opts ...jet // from a fresh read rather than giving up, so a lagging replica never causes // a leaked ENI. func TestDetachAndDeleteENI_RetriesOnDeleteCASConflict(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -402,6 +420,7 @@ func TestDetachAndDeleteENI_RetriesOnDeleteCASConflict(t *testing.T) { // bounded: a Delete that never stops conflicting must surface an error // rather than retry forever or silently drop the ENI. func TestDetachAndDeleteENI_ExhaustsRetriesReturnsError(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -419,6 +438,7 @@ func TestDetachAndDeleteENI_ExhaustsRetriesReturnsError(t *testing.T) { // another ENI in between — so a delete that never succeeds must leave the // allocation exactly as it found it. func TestDetachAndDeleteENI_HoldsIPUntilDeleteSucceeds(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -440,6 +460,7 @@ func TestDetachAndDeleteENI_HoldsIPUntilDeleteSucceeds(t *testing.T) { // the public-facing guard is unchanged by the new atomic path: a genuinely // attached ENI without force must still return InvalidNetworkInterface.InUse. func TestDetachAndDeleteENI_ForceFalseOnLiveAttachment_StaysAWSFaithful(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -463,6 +484,7 @@ func TestDetachAndDeleteENI_ForceFalseOnLiveAttachment_StaysAWSFaithful(t *testi // with no separate re-read between the two — the mechanism that closes the // stale-replica window DetachENI+DeleteNetworkInterface used to open. func TestDetachAndDeleteENI_ForceTrueDeletesLiveAttachment(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -485,6 +507,7 @@ func TestDetachAndDeleteENI_ForceTrueDeletesLiveAttachment(t *testing.T) { // stops the caller logging a false "Deleted ENI on termination" for an ENI // it never touched. func TestDetachAndDeleteENI_AbsentForceTrue_ReturnsNotDeletedNoError(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) deleted, err := svc.DetachAndDeleteENI(context.Background(), testAccountID, "eni-never-existed", true) @@ -495,6 +518,7 @@ func TestDetachAndDeleteENI_AbsentForceTrue_ReturnsNotDeletedNoError(t *testing. // TestDetachAndDeleteENI_AbsentForceFalse_ReturnsNotFound asserts the public // (non-force) path stays AWS-faithful on an absent ENI. func TestDetachAndDeleteENI_AbsentForceFalse_ReturnsNotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DetachAndDeleteENI(context.Background(), testAccountID, "eni-never-existed", false) @@ -502,6 +526,7 @@ func TestDetachAndDeleteENI_AbsentForceFalse_ReturnsNotFound(t *testing.T) { } func TestGenerateENIMac(t *testing.T) { + t.Parallel() mac := generateENIMac("eni-test123") hw, err := net.ParseMAC(mac) require.NoError(t, err) @@ -517,6 +542,7 @@ func TestGenerateENIMac(t *testing.T) { // --- Filter tests --- func TestDescribeNetworkInterfaces_FilterByVpcId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpc1 := createTestVPC(t, svc, "10.0.0.0/16") vpc2 := createTestVPC(t, svc, "10.1.0.0/16") @@ -537,6 +563,7 @@ func TestDescribeNetworkInterfaces_FilterByVpcId(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByAttachmentInstanceId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -559,6 +586,7 @@ func TestDescribeNetworkInterfaces_FilterByAttachmentInstanceId(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByDescription(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -588,6 +616,7 @@ func TestDescribeNetworkInterfaces_FilterByDescription(t *testing.T) { } func TestCreateNetworkInterface_IPExhaustion(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") // /28 subnet: 16 IPs total, 4 reserved at start + 1 broadcast = 11 usable @@ -611,6 +640,7 @@ func TestCreateNetworkInterface_IPExhaustion(t *testing.T) { // --- NATS event tests --- func TestCreateNetworkInterface_PublishesEvent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -638,6 +668,7 @@ func TestCreateNetworkInterface_PublishesEvent(t *testing.T) { } func TestDeleteNetworkInterface_PublishesEvent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -668,6 +699,7 @@ func TestDeleteNetworkInterface_PublishesEvent(t *testing.T) { // is already gone by the time this runs, so a failed teardown must still let // the caller (instance terminate, appliance teardown) converge. func TestDeleteNetworkInterface_VpcdDeletePortError_NonFatal(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -689,6 +721,7 @@ func TestDeleteNetworkInterface_VpcdDeletePortError_NonFatal(t *testing.T) { } func TestModifyNetworkInterfaceAttribute_SecurityGroups(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -713,6 +746,7 @@ func TestModifyNetworkInterfaceAttribute_SecurityGroups(t *testing.T) { } func TestModifyNetworkInterfaceAttribute_PublishesUpdatePortSGs(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -744,6 +778,7 @@ func TestModifyNetworkInterfaceAttribute_PublishesUpdatePortSGs(t *testing.T) { } func TestModifyNetworkInterfaceAttribute_DescriptionOnly_NoSGEvent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -770,6 +805,7 @@ func TestModifyNetworkInterfaceAttribute_DescriptionOnly_NoSGEvent(t *testing.T) } func TestCreateNetworkInterface_PublishesEventCarriesSGs(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -798,6 +834,7 @@ func TestCreateNetworkInterface_PublishesEventCarriesSGs(t *testing.T) { } func TestModifyNetworkInterfaceAttribute_Description(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -818,6 +855,7 @@ func TestModifyNetworkInterfaceAttribute_Description(t *testing.T) { } func TestModifyNetworkInterfaceAttribute_SourceDestCheckOnly(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -855,6 +893,7 @@ func TestModifyNetworkInterfaceAttribute_SourceDestCheckOnly(t *testing.T) { } func TestModifyNetworkInterfaceAttribute_SourceDestCheckOnly_NoSGEvent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -881,6 +920,7 @@ func TestModifyNetworkInterfaceAttribute_SourceDestCheckOnly_NoSGEvent(t *testin } func TestModifyNetworkInterfaceAttribute_NoAttributes(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -893,6 +933,7 @@ func TestModifyNetworkInterfaceAttribute_NoAttributes(t *testing.T) { } func TestModifyNetworkInterfaceAttribute_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.ModifyNetworkInterfaceAttribute(context.Background(), &ec2.ModifyNetworkInterfaceAttributeInput{ @@ -903,6 +944,7 @@ func TestModifyNetworkInterfaceAttribute_NotFound(t *testing.T) { } func TestModifyNetworkInterfaceAttribute_MissingID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.ModifyNetworkInterfaceAttribute(context.Background(), &ec2.ModifyNetworkInterfaceAttributeInput{ @@ -912,6 +954,7 @@ func TestModifyNetworkInterfaceAttribute_MissingID(t *testing.T) { } func TestCreateNetworkInterface_WithSecurityGroups(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -929,6 +972,7 @@ func TestCreateNetworkInterface_WithSecurityGroups(t *testing.T) { } func TestCreateNetworkInterface_FallsBackToDefaultSG(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -943,6 +987,7 @@ func TestCreateNetworkInterface_FallsBackToDefaultSG(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByNetworkInterfaceId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -970,6 +1015,7 @@ func TestDescribeNetworkInterfaces_FilterByNetworkInterfaceId(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByStatus(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -999,6 +1045,7 @@ func TestDescribeNetworkInterfaces_FilterByStatus(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByPrivateIpAddress(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -1035,6 +1082,7 @@ func TestDescribeNetworkInterfaces_FilterByPrivateIpAddress(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByAvailabilityZone(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") // Create subnet with explicit AZ @@ -1066,6 +1114,7 @@ func TestDescribeNetworkInterfaces_FilterByAvailabilityZone(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByGroupId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -1103,6 +1152,7 @@ func TestDescribeNetworkInterfaces_FilterByGroupId(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByMacAddress(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -1131,6 +1181,7 @@ func TestDescribeNetworkInterfaces_FilterByMacAddress(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByAttachmentId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -1152,6 +1203,7 @@ func TestDescribeNetworkInterfaces_FilterByAttachmentId(t *testing.T) { } func TestDescribeNetworkInterfaces_FilterByAttachmentStatus(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -1212,6 +1264,7 @@ func putEIPRecord(t *testing.T, kv jetstream.KeyValue, key, eniID string) { } func TestIsEIPOwned_NilKV(t *testing.T) { + t.Parallel() svc := &VPCServiceImpl{eipKV: nil} owned, err := svc.isEIPOwned(context.Background(), "eni-111", testAccountID) @@ -1220,6 +1273,7 @@ func TestIsEIPOwned_NilKV(t *testing.T) { } func TestIsEIPOwned_NoKeys(t *testing.T) { + t.Parallel() svc, _ := setupEIPTestService(t) owned, err := svc.isEIPOwned(context.Background(), "eni-111", testAccountID) @@ -1228,6 +1282,7 @@ func TestIsEIPOwned_NoKeys(t *testing.T) { } func TestIsEIPOwned_MatchingENI(t *testing.T) { + t.Parallel() svc, kv := setupEIPTestService(t) putEIPRecord(t, kv, testAccountID+".eipalloc-001", "eni-111") @@ -1237,6 +1292,7 @@ func TestIsEIPOwned_MatchingENI(t *testing.T) { } func TestIsEIPOwned_NonMatchingENI(t *testing.T) { + t.Parallel() svc, kv := setupEIPTestService(t) putEIPRecord(t, kv, testAccountID+".eipalloc-001", "eni-222") @@ -1246,6 +1302,7 @@ func TestIsEIPOwned_NonMatchingENI(t *testing.T) { } func TestIsEIPOwned_WrongAccountPrefix(t *testing.T) { + t.Parallel() svc, kv := setupEIPTestService(t) putEIPRecord(t, kv, "999999999999.eipalloc-001", "eni-111") @@ -1255,6 +1312,7 @@ func TestIsEIPOwned_WrongAccountPrefix(t *testing.T) { } func TestIsEIPOwned_MalformedJSON(t *testing.T) { + t.Parallel() svc, kv := setupEIPTestService(t) _, err := kv.Put(t.Context(), testAccountID+".eipalloc-001", []byte("not json")) require.NoError(t, err) @@ -1265,6 +1323,7 @@ func TestIsEIPOwned_MalformedJSON(t *testing.T) { } func TestIsEIPOwned_MultipleRecords_OneMatches(t *testing.T) { + t.Parallel() svc, kv := setupEIPTestService(t) putEIPRecord(t, kv, testAccountID+".eipalloc-001", "eni-aaa") putEIPRecord(t, kv, testAccountID+".eipalloc-002", "eni-target") @@ -1278,6 +1337,7 @@ func TestIsEIPOwned_MultipleRecords_OneMatches(t *testing.T) { // --- validateSGAttachment --- func TestValidateSGAttachment_OK(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sg := createTestSG(t, svc, vpcID, "ok") @@ -1287,6 +1347,7 @@ func TestValidateSGAttachment_OK(t *testing.T) { } func TestValidateSGAttachment_EmptyList(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1295,6 +1356,7 @@ func TestValidateSGAttachment_EmptyList(t *testing.T) { } func TestValidateSGAttachment_TooMany(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgs := make([]string, 6) @@ -1307,12 +1369,14 @@ func TestValidateSGAttachment_TooMany(t *testing.T) { } func TestValidateSGAttachment_UnknownVPC(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) err := svc.validateSGAttachment(t.Context(), testAccountID, []string{"sg-aaa"}, "vpc-missing") assert.ErrorContains(t, err, "InvalidVpcID.NotFound") } func TestValidateSGAttachment_SGNotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1321,6 +1385,7 @@ func TestValidateSGAttachment_SGNotFound(t *testing.T) { } func TestValidateSGAttachment_CrossVPC(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcA := createTestVPC(t, svc, "10.0.0.0/16") vpcB := createTestVPC(t, svc, "10.1.0.0/16") @@ -1334,6 +1399,7 @@ func TestValidateSGAttachment_CrossVPC(t *testing.T) { // caller knows OVN port-group reconciliation didn't happen. The KV record // already changed by this point — that's intentional (reconciler converges). func TestModifyNetworkInterfaceAttribute_VpcdError_Propagated(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -1357,6 +1423,7 @@ func TestModifyNetworkInterfaceAttribute_VpcdError_Propagated(t *testing.T) { // the ENI record so DescribeNetworkInterfaces shows the auto-assigned public // IP after RunInstances and EIP associate-address. func TestUpdateENIPublicIP_Success(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -1374,6 +1441,7 @@ func TestUpdateENIPublicIP_Success(t *testing.T) { } func TestUpdateENIPublicIP_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) err := svc.UpdateENIPublicIP(testAccountID, "eni-missing", "203.0.113.8", "amazon") diff --git a/spinifex/handlers/ec2/vpc/external_ipam_test.go b/spinifex/handlers/ec2/vpc/external_ipam_test.go index 3ded19b2d..e5724d7d8 100644 --- a/spinifex/handlers/ec2/vpc/external_ipam_test.go +++ b/spinifex/handlers/ec2/vpc/external_ipam_test.go @@ -33,6 +33,7 @@ func testPool() external.ExternalPoolConfig { } func TestExternalIPAM_AllocateSequential(t *testing.T) { + t.Parallel() pool := testPool() ipam := setupTestExternalIPAM(t, []external.ExternalPoolConfig{pool}) @@ -52,6 +53,7 @@ func TestExternalIPAM_AllocateSequential(t *testing.T) { } func TestExternalIPAM_GatewayIPReserved(t *testing.T) { + t.Parallel() pool := testPool() ipam := setupTestExternalIPAM(t, []external.ExternalPoolConfig{pool}) @@ -69,6 +71,7 @@ func TestExternalIPAM_GatewayIPReserved(t *testing.T) { } func TestExternalIPAM_ExplicitGatewayIP(t *testing.T) { + t.Parallel() pool := testPool() pool.GatewayIP = "192.168.1.155" ipam := setupTestExternalIPAM(t, []external.ExternalPoolConfig{pool}) @@ -89,6 +92,7 @@ func TestExternalIPAM_ExplicitGatewayIP(t *testing.T) { } func TestExternalIPAM_Release(t *testing.T) { + t.Parallel() pool := testPool() ipam := setupTestExternalIPAM(t, []external.ExternalPoolConfig{pool}) @@ -112,6 +116,7 @@ func TestExternalIPAM_Release(t *testing.T) { } func TestExternalIPAM_Exhaustion(t *testing.T) { + t.Parallel() pool := external.ExternalPoolConfig{ Name: "tiny", RangeStart: "10.0.0.1", @@ -136,6 +141,7 @@ func TestExternalIPAM_Exhaustion(t *testing.T) { } func TestExternalIPAM_CASConflict(t *testing.T) { + t.Parallel() pool := testPool() ipam := setupTestExternalIPAM(t, []external.ExternalPoolConfig{pool}) @@ -169,6 +175,7 @@ func TestExternalIPAM_CASConflict(t *testing.T) { } func TestExternalIPAM_MultiPool(t *testing.T) { + t.Parallel() pools := []external.ExternalPoolConfig{ { Name: "us-east", @@ -205,6 +212,7 @@ func TestExternalIPAM_MultiPool(t *testing.T) { } func TestExternalIPAM_PoolFallback(t *testing.T) { + t.Parallel() pools := []external.ExternalPoolConfig{ { Name: "az-pool", @@ -253,6 +261,7 @@ func TestExternalIPAM_PoolFallback(t *testing.T) { } func TestExternalIPAM_SpecificPool(t *testing.T) { + t.Parallel() pools := []external.ExternalPoolConfig{ { Name: "pool-a", @@ -278,6 +287,7 @@ func TestExternalIPAM_SpecificPool(t *testing.T) { } func TestExternalIPAM_RangeValidation(t *testing.T) { + t.Parallel() tests := []struct { name string pool external.ExternalPoolConfig @@ -337,6 +347,7 @@ func TestExternalIPAM_RangeValidation(t *testing.T) { } func TestExternalIPAM_InitFromConfig(t *testing.T) { + t.Parallel() pool := testPool() // Create IPAM twice — second init should be idempotent _, nc, _ := testutil.StartTestJetStream(t) @@ -362,6 +373,7 @@ func TestExternalIPAM_InitFromConfig(t *testing.T) { } func TestExternalIPAM_ReleaseNotAllocated(t *testing.T) { + t.Parallel() pool := testPool() ipam := setupTestExternalIPAM(t, []external.ExternalPoolConfig{pool}) @@ -370,6 +382,7 @@ func TestExternalIPAM_ReleaseNotAllocated(t *testing.T) { } func TestExternalIPAM_NoPoolAvailable(t *testing.T) { + t.Parallel() pool := external.ExternalPoolConfig{ Name: "us-only", RangeStart: "10.0.0.1", @@ -390,6 +403,7 @@ func TestExternalIPAM_NoPoolAvailable(t *testing.T) { } func TestExternalIPAM_FindPoolByName_NotFound(t *testing.T) { + t.Parallel() pool := testPool() ipam := setupTestExternalIPAM(t, []external.ExternalPoolConfig{pool}) @@ -402,6 +416,7 @@ func TestExternalIPAM_FindPoolByName_NotFound(t *testing.T) { } func TestValidatePoolConfig(t *testing.T) { + t.Parallel() base := func() external.ExternalPoolConfig { return external.ExternalPoolConfig{ Name: "wan", diff --git a/spinifex/handlers/ec2/vpc/ipam_test.go b/spinifex/handlers/ec2/vpc/ipam_test.go index 7f4a46c90..a24e280dd 100644 --- a/spinifex/handlers/ec2/vpc/ipam_test.go +++ b/spinifex/handlers/ec2/vpc/ipam_test.go @@ -22,6 +22,7 @@ func setupTestIPAM(t *testing.T) *IPAM { } func TestIPAM_AllocateFirst(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) ip, err := ipam.AllocateIP(t.Context(), "subnet-1", "10.0.1.0/24", PurposeENIPrimary, "eni-1") @@ -31,6 +32,7 @@ func TestIPAM_AllocateFirst(t *testing.T) { } func TestIPAM_AllocateSequential(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) ip1, err := ipam.AllocateIP(t.Context(), "subnet-seq", "10.0.2.0/24", PurposeENIPrimary, "eni-seq") @@ -47,6 +49,7 @@ func TestIPAM_AllocateSequential(t *testing.T) { } func TestIPAM_Release(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) ip1, err := ipam.AllocateIP(t.Context(), "subnet-rel", "10.0.3.0/24", PurposeENIPrimary, "eni-rel") @@ -68,6 +71,7 @@ func TestIPAM_Release(t *testing.T) { } func TestIPAM_ReleaseNotAllocated(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) _, err := ipam.AllocateIP(t.Context(), "subnet-rna", "10.0.4.0/24", PurposeENIPrimary, "eni-rna") @@ -78,6 +82,7 @@ func TestIPAM_ReleaseNotAllocated(t *testing.T) { } func TestIPAM_ReleaseNoRecord(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) err := ipam.ReleaseIP(t.Context(), "subnet-nonexistent", "10.0.0.4") @@ -85,6 +90,7 @@ func TestIPAM_ReleaseNoRecord(t *testing.T) { } func TestIPAM_Exhaustion(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) // /28 = 16 IPs total. Reserved: .0, .1, .2, .3, .15 = 5. Available: 11 @@ -108,6 +114,7 @@ func TestIPAM_Exhaustion(t *testing.T) { } func TestIPAM_ReservedIPs(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) cidr := "10.0.6.0/24" @@ -123,6 +130,7 @@ func TestIPAM_ReservedIPs(t *testing.T) { } func TestIPAM_AllocatedIPs(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) // No allocations yet @@ -144,6 +152,7 @@ func TestIPAM_AllocatedIPs(t *testing.T) { } func TestIPAM_MultipleSubnets(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) ip1, err := ipam.AllocateIP(t.Context(), "subnet-a", "10.0.10.0/24", PurposeENIPrimary, "eni-a") @@ -161,6 +170,7 @@ func TestIPAM_MultipleSubnets(t *testing.T) { } func TestIPAM_LargerSubnet(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) // /20 subnet — first allocable is still .4 @@ -170,6 +180,7 @@ func TestIPAM_LargerSubnet(t *testing.T) { } func TestIPAM_NewIPAMWithKV(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) js := testutil.NewJetStream(t, nc) @@ -188,6 +199,7 @@ func TestIPAM_NewIPAMWithKV(t *testing.T) { } func TestIPAM_InvalidCIDR(t *testing.T) { + t.Parallel() ipam := setupTestIPAM(t) _, err := ipam.AllocateIP(t.Context(), "subnet-bad", "not-a-cidr", PurposeENIPrimary, "eni-bad") assert.Error(t, err) @@ -195,6 +207,7 @@ func TestIPAM_InvalidCIDR(t *testing.T) { } func TestCompareIPs_NilSortsFirst(t *testing.T) { + t.Parallel() assert.Negative(t, compareIPs(nil, net.ParseIP("10.0.0.1"))) assert.Zero(t, compareIPs(net.ParseIP("10.0.0.1"), net.ParseIP("10.0.0.1"))) assert.Positive(t, compareIPs(net.ParseIP("10.0.0.2"), net.ParseIP("10.0.0.1"))) diff --git a/spinifex/handlers/ec2/vpc/lease_owner_test.go b/spinifex/handlers/ec2/vpc/lease_owner_test.go index 0bec51c8e..208c26f08 100644 --- a/spinifex/handlers/ec2/vpc/lease_owner_test.go +++ b/spinifex/handlers/ec2/vpc/lease_owner_test.go @@ -11,6 +11,7 @@ import ( ) func TestVPCExists(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -22,6 +23,7 @@ func TestVPCExists(t *testing.T) { // A gw-lrp lease outliving its VPC is exactly the leak the reaper is for, so a // deleted VPC has to read as absent. func TestVPCExistsFalseAfterDelete(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") _, err := svc.DeleteVpc(context.Background(), &ec2.DeleteVpcInput{VpcId: aws.String(vpcID)}, testAccountID) @@ -33,6 +35,7 @@ func TestVPCExistsFalseAfterDelete(t *testing.T) { } func TestVPCExistsUnknownID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) exists, err := svc.VPCExists(t.Context(), "vpc-missing") @@ -41,6 +44,7 @@ func TestVPCExistsUnknownID(t *testing.T) { } func TestENIExists(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -52,6 +56,7 @@ func TestENIExists(t *testing.T) { } func TestENIExistsUnknownID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) exists, err := svc.ENIExists(t.Context(), "eni-missing") @@ -60,6 +65,7 @@ func TestENIExistsUnknownID(t *testing.T) { } func TestLeaseOwnerLookupsRejectEmptyIDs(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.VPCExists(t.Context(), "") diff --git a/spinifex/handlers/ec2/vpc/lifecycle_invariants_test.go b/spinifex/handlers/ec2/vpc/lifecycle_invariants_test.go index 0fe7b8588..8e49c317a 100644 --- a/spinifex/handlers/ec2/vpc/lifecycle_invariants_test.go +++ b/spinifex/handlers/ec2/vpc/lifecycle_invariants_test.go @@ -18,6 +18,7 @@ import ( // is why unit tests on each operation individually all passed while it // existed — this asserts the end state across the ordering that matters. func TestRLC5_NoOrphanedRouteTableAfterSubnetThenVpcTeardown(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.70.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.70.1.0/24") @@ -51,6 +52,7 @@ func TestRLC5_NoOrphanedRouteTableAfterSubnetThenVpcTeardown(t *testing.T) { // compatible so SDK callers and account-scoping checks see the real error. // Every VPC-family delete endpoint must have a case here. func TestRLC1_VPCDeleteNotFoundOnAbsent(t *testing.T) { + t.Parallel() cases := []struct { name string wantErr string @@ -88,6 +90,7 @@ func TestRLC1_VPCDeleteNotFoundOnAbsent(t *testing.T) { // and the in-use guard then blocks delete forever, so the instance can never // finish terminating. func TestRLC_ENINonDeadlock(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") subnetId := createTestSubnet(t, svc, vpcId, "10.0.1.0/24") @@ -125,6 +128,7 @@ func TestRLC_ENINonDeadlock(t *testing.T) { // detached/available (orphan) child must never pin its parent undeletable — // otherwise tofu destroy deadlocks on a child the GC backstop already reaps. func TestRLC3_VPCFamilyDeleteGuardsLiveDependents(t *testing.T) { + t.Parallel() t.Run("DeleteSubnet blocked by an attached ENI", func(t *testing.T) { svc := setupTestVPCService(t) vpcId := createTestVPC(t, svc, "10.0.0.0/16") diff --git a/spinifex/handlers/ec2/vpc/security_group_test.go b/spinifex/handlers/ec2/vpc/security_group_test.go index 7b951c5ed..2e986b75c 100644 --- a/spinifex/handlers/ec2/vpc/security_group_test.go +++ b/spinifex/handlers/ec2/vpc/security_group_test.go @@ -30,6 +30,7 @@ func createTestSG(t *testing.T, svc *VPCServiceImpl, vpcID, name string) string // --- CreateSecurityGroup --- func TestCreateSecurityGroup_Success(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -43,6 +44,7 @@ func TestCreateSecurityGroup_Success(t *testing.T) { } func TestCreateSecurityGroup_MissingGroupName(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateSecurityGroup(context.Background(), &ec2.CreateSecurityGroupInput{ @@ -52,6 +54,7 @@ func TestCreateSecurityGroup_MissingGroupName(t *testing.T) { } func TestCreateSecurityGroup_MissingVpcId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateSecurityGroup(context.Background(), &ec2.CreateSecurityGroupInput{ @@ -61,6 +64,7 @@ func TestCreateSecurityGroup_MissingVpcId(t *testing.T) { } func TestCreateSecurityGroup_InvalidVpc(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateSecurityGroup(context.Background(), &ec2.CreateSecurityGroupInput{ @@ -72,6 +76,7 @@ func TestCreateSecurityGroup_InvalidVpc(t *testing.T) { } func TestCreateSecurityGroup_DuplicateName(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -92,6 +97,7 @@ func TestCreateSecurityGroup_DuplicateName(t *testing.T) { // --- DeleteSecurityGroup --- func TestDeleteSecurityGroup_Success(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "delete-me") @@ -110,6 +116,7 @@ func TestDeleteSecurityGroup_Success(t *testing.T) { } func TestDeleteSecurityGroup_MissingGroupId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DeleteSecurityGroup(context.Background(), &ec2.DeleteSecurityGroupInput{}, testAccountID) @@ -119,6 +126,7 @@ func TestDeleteSecurityGroup_MissingGroupId(t *testing.T) { // --- DescribeSecurityGroups --- func TestDescribeSecurityGroups_All(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSG(t, svc, vpcID, "sg-a") @@ -131,6 +139,7 @@ func TestDescribeSecurityGroups_All(t *testing.T) { } func TestDescribeSecurityGroups_ByGroupId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "target-sg") @@ -145,6 +154,7 @@ func TestDescribeSecurityGroups_ByGroupId(t *testing.T) { } func TestDescribeSecurityGroups_ByGroupName(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSG(t, svc, vpcID, "find-me") @@ -161,6 +171,7 @@ func TestDescribeSecurityGroups_ByGroupName(t *testing.T) { } func TestDescribeSecurityGroups_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DescribeSecurityGroups(context.Background(), &ec2.DescribeSecurityGroupsInput{ @@ -173,6 +184,7 @@ func TestDescribeSecurityGroups_NotFound(t *testing.T) { // --- AuthorizeSecurityGroupIngress --- func TestAuthorizeSecurityGroupIngress_Success(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "ingress-sg") @@ -200,6 +212,7 @@ func TestAuthorizeSecurityGroupIngress_Success(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.AuthorizeSecurityGroupIngress(context.Background(), &ec2.AuthorizeSecurityGroupIngressInput{ @@ -210,6 +223,7 @@ func TestAuthorizeSecurityGroupIngress_NotFound(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_MissingGroupId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.AuthorizeSecurityGroupIngress(context.Background(), &ec2.AuthorizeSecurityGroupIngressInput{}, testAccountID) @@ -219,6 +233,7 @@ func TestAuthorizeSecurityGroupIngress_MissingGroupId(t *testing.T) { // --- AuthorizeSecurityGroupEgress --- func TestAuthorizeSecurityGroupEgress_Success(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "egress-sg") @@ -239,6 +254,7 @@ func TestAuthorizeSecurityGroupEgress_Success(t *testing.T) { } func TestAuthorizeSecurityGroupEgress_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.AuthorizeSecurityGroupEgress(context.Background(), &ec2.AuthorizeSecurityGroupEgressInput{ @@ -250,6 +266,7 @@ func TestAuthorizeSecurityGroupEgress_NotFound(t *testing.T) { // The AWS provider reads SecurityGroupRules[0].SecurityGroupRuleId on create; // an empty ruleset panics the plugin. Authorize must echo the created rules. func TestAuthorizeSecurityGroupIngress_ReturnsRuleSet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "ingress-ruleset-sg") @@ -277,6 +294,7 @@ func TestAuthorizeSecurityGroupIngress_ReturnsRuleSet(t *testing.T) { } func TestAuthorizeSecurityGroupEgress_ReturnsRuleSet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "egress-ruleset-sg") @@ -301,6 +319,7 @@ func TestAuthorizeSecurityGroupEgress_ReturnsRuleSet(t *testing.T) { // --- RevokeSecurityGroupIngress --- func TestRevokeSecurityGroupIngress_Success(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "revoke-ingress-sg") @@ -329,6 +348,7 @@ func TestRevokeSecurityGroupIngress_Success(t *testing.T) { } func TestRevokeSecurityGroupIngress_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.RevokeSecurityGroupIngress(context.Background(), &ec2.RevokeSecurityGroupIngressInput{ @@ -341,6 +361,7 @@ func TestRevokeSecurityGroupIngress_NotFound(t *testing.T) { // rule returns InvalidPermission.NotFound, matching AWS non-idempotent // revoke behavior. func TestRevokeSecurityGroupIngress_RuleNotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "rule-notfound-ingress") @@ -362,6 +383,7 @@ func TestRevokeSecurityGroupIngress_RuleNotFound(t *testing.T) { // --- RevokeSecurityGroupEgress --- func TestRevokeSecurityGroupEgress_Success(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "revoke-egress-sg") @@ -381,6 +403,7 @@ func TestRevokeSecurityGroupEgress_Success(t *testing.T) { } func TestRevokeSecurityGroupEgress_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.RevokeSecurityGroupEgress(context.Background(), &ec2.RevokeSecurityGroupEgressInput{ @@ -393,6 +416,7 @@ func TestRevokeSecurityGroupEgress_NotFound(t *testing.T) { // IPv6-only permission succeeds as a no-op; Terraform auto-revokes ::/0 IPv6 // egress and must not abort when spinifex stores no IPv6 rules. func TestRevokeSecurityGroupEgress_IPv6OnlyIsNoOp(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "ipv6-revoke-noop") @@ -413,6 +437,7 @@ func TestRevokeSecurityGroupEgress_IPv6OnlyIsNoOp(t *testing.T) { // TestRevokeSecurityGroupIngress_IPv6OnlyIsNoOp mirrors the egress no-op test // — the ingress path shares the same parsing code and must behave the same. func TestRevokeSecurityGroupIngress_IPv6OnlyIsNoOp(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "ipv6-revoke-ingress-noop") @@ -433,6 +458,7 @@ func TestRevokeSecurityGroupIngress_IPv6OnlyIsNoOp(t *testing.T) { // TestAuthorizeSecurityGroupEgress_IPv6Rejected asserts that authorizing // IPv6 sources is rejected; spinifex cannot program IPv6 OVN ACLs. func TestAuthorizeSecurityGroupEgress_IPv6Rejected(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "ipv6-authorize-rejected") @@ -452,6 +478,7 @@ func TestAuthorizeSecurityGroupEgress_IPv6Rejected(t *testing.T) { // TestRevokeSecurityGroupEgress_RuleNotFound: egress counterpart — revoking a // non-existent egress rule returns InvalidPermission.NotFound. func TestRevokeSecurityGroupEgress_RuleNotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "rule-notfound-egress") @@ -507,6 +534,7 @@ func ingressRuleIDReferencing(t *testing.T, svc *VPCServiceImpl, sgID, srcSG str // with empty IpPermissions; if the handler ignores SecurityGroupRuleIds the // cross-ref rule survives and DeleteSecurityGroup deadlocks on DependencyViolation. func TestRevokeSecurityGroupIngress_ByRuleID_BreaksMutualReferenceTeardown(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgA := createTestSG(t, svc, vpcID, "tf-sg-a") @@ -537,6 +565,7 @@ func TestRevokeSecurityGroupIngress_ByRuleID_BreaksMutualReferenceTeardown(t *te } func TestRevokeSecurityGroupEgress_ByRuleID_RemovesRule(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "tf-egress-byid") @@ -569,6 +598,7 @@ func TestRevokeSecurityGroupEgress_ByRuleID_RemovesRule(t *testing.T) { } func TestRevokeSecurityGroupIngress_ByRuleID_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "tf-byid-notfound") @@ -581,6 +611,7 @@ func TestRevokeSecurityGroupIngress_ByRuleID_NotFound(t *testing.T) { } func TestRevokeSecurityGroupIngress_ByRuleID_Malformed(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "tf-byid-malformed") @@ -595,6 +626,7 @@ func TestRevokeSecurityGroupIngress_ByRuleID_Malformed(t *testing.T) { // --- Helper function tests --- func TestIpPermissionsToSGRules_TCP(t *testing.T) { + t.Parallel() proto := "tcp" perms := []*ec2.IpPermission{ { @@ -615,6 +647,7 @@ func TestIpPermissionsToSGRules_TCP(t *testing.T) { } func TestIpPermissionsToSGRules_AllTraffic(t *testing.T) { + t.Parallel() allProto := "-1" perms := []*ec2.IpPermission{ { @@ -630,6 +663,7 @@ func TestIpPermissionsToSGRules_AllTraffic(t *testing.T) { } func TestIpPermissionsToSGRules_SourceSG(t *testing.T) { + t.Parallel() proto := "-1" srcSG := "sg-0123456789abcdef0" perms := []*ec2.IpPermission{ @@ -648,6 +682,7 @@ func TestIpPermissionsToSGRules_SourceSG(t *testing.T) { // TestIpPermissionsToSGRules_IPv6OnlyAuthorize rejects authorize calls whose // only source is Ipv6Ranges (OVN ACL builder is IPv4-only). func TestIpPermissionsToSGRules_IPv6OnlyAuthorize(t *testing.T) { + t.Parallel() allProto := "-1" perms := []*ec2.IpPermission{ { @@ -665,6 +700,7 @@ func TestIpPermissionsToSGRules_IPv6OnlyAuthorize(t *testing.T) { // revoke (returns zero rules, no error), matching Terraform's auto-revoke of // the default ::/0 IPv6 egress rule. func TestIpPermissionsToSGRules_IPv6OnlyRevoke(t *testing.T) { + t.Parallel() allProto := "-1" perms := []*ec2.IpPermission{ { @@ -681,6 +717,7 @@ func TestIpPermissionsToSGRules_IPv6OnlyRevoke(t *testing.T) { // TestIpPermissionsToSGRules_MixedV4V6Revoke keeps the v4 rule and drops the // v6 part on a mixed-source permission on revoke. func TestIpPermissionsToSGRules_MixedV4V6Revoke(t *testing.T) { + t.Parallel() proto := "tcp" perms := []*ec2.IpPermission{ { @@ -699,6 +736,7 @@ func TestIpPermissionsToSGRules_MixedV4V6Revoke(t *testing.T) { } func TestSGRulesToIpPermissions_Conversion(t *testing.T) { + t.Parallel() rules := []SGRule{ {IpProtocol: "tcp", FromPort: 443, ToPort: 443, CidrIp: "0.0.0.0/0"}, {IpProtocol: "-1", SourceSG: "sg-other"}, @@ -728,6 +766,7 @@ func TestSGRulesToIpPermissions_Conversion(t *testing.T) { } func TestSGRuleKey(t *testing.T) { + t.Parallel() rule := SGRule{IpProtocol: "tcp", FromPort: 80, ToPort: 80, CidrIp: "10.0.0.0/8"} key := sgRuleKey(rule) assert.NotEmpty(t, key) @@ -743,6 +782,7 @@ func TestSGRuleKey(t *testing.T) { } func TestSGRecordToEC2_Basic(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) record := &SecurityGroupRecord{ @@ -770,6 +810,7 @@ func TestSGRecordToEC2_Basic(t *testing.T) { } func TestRemoveSGRules_MatchingRule(t *testing.T) { + t.Parallel() existing := []SGRule{ {IpProtocol: "tcp", FromPort: 22, ToPort: 22, CidrIp: "10.0.0.0/8"}, {IpProtocol: "tcp", FromPort: 80, ToPort: 80, CidrIp: "0.0.0.0/0"}, @@ -784,6 +825,7 @@ func TestRemoveSGRules_MatchingRule(t *testing.T) { } func TestRemoveSGRules_NoMatch(t *testing.T) { + t.Parallel() existing := []SGRule{ {IpProtocol: "tcp", FromPort: 80, ToPort: 80, CidrIp: "0.0.0.0/0"}, } @@ -798,6 +840,7 @@ func TestRemoveSGRules_NoMatch(t *testing.T) { // --- SG-rule input validation (OVN ACL match-expression injection) --- func TestValidateSGRule(t *testing.T) { + t.Parallel() cases := []struct { name string rule SGRule @@ -843,6 +886,7 @@ func TestValidateSGRule(t *testing.T) { // validateSGRule is the last gate before the OVN ACL builder, which emits no L4 // predicate for a protocol it does not recognise. Only canonical names pass. func TestValidateSGRule_Protocol(t *testing.T) { + t.Parallel() for _, proto := range []string{"tcp", "udp", "icmp", "-1"} { assert.NoError(t, validateSGRule(SGRule{IpProtocol: proto, CidrIp: "10.0.0.0/8"}), "protocol %q", proto) } @@ -852,6 +896,7 @@ func TestValidateSGRule_Protocol(t *testing.T) { } func TestNormalizeIPProtocol(t *testing.T) { + t.Parallel() cases := map[string]string{ "": "-1", "-1": "-1", @@ -880,6 +925,7 @@ func TestNormalizeIPProtocol(t *testing.T) { // full payload table lives in TestValidateSGRule above. func TestAuthorizeSecurityGroupIngress_RejectsInvalidRule(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "inj-sg") @@ -899,6 +945,7 @@ func TestAuthorizeSecurityGroupIngress_RejectsInvalidRule(t *testing.T) { } func TestAuthorizeSecurityGroupEgress_RejectsInvalidRule(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "inj-sg-egress") @@ -916,6 +963,7 @@ func TestAuthorizeSecurityGroupEgress_RejectsInvalidRule(t *testing.T) { } func TestRevokeSecurityGroupIngress_RejectsInvalidRule(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "inj-sg-revoke") @@ -935,6 +983,7 @@ func TestRevokeSecurityGroupIngress_RejectsInvalidRule(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_AcceptsValidSourceSG(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "valid-src-sg") @@ -954,6 +1003,7 @@ func TestAuthorizeSecurityGroupIngress_AcceptsValidSourceSG(t *testing.T) { // --protocol 6 must be stored as tcp, so it builds the same ACL as // --protocol tcp instead of an L4-less match that allows every IP protocol. func TestAuthorizeSecurityGroupIngress_NormalizesNumericProtocol(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "numeric-proto-sg") @@ -998,6 +1048,7 @@ func TestAuthorizeSecurityGroupIngress_NormalizesNumericProtocol(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_RejectsUnsupportedProtocol(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "bad-proto-sg") @@ -1018,6 +1069,7 @@ func TestAuthorizeSecurityGroupIngress_RejectsUnsupportedProtocol(t *testing.T) // --- DescribeSecurityGroups filter tests --- func TestDescribeSecurityGroups_FilterByGroupId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "target-sg") @@ -1034,6 +1086,7 @@ func TestDescribeSecurityGroups_FilterByGroupId(t *testing.T) { } func TestDescribeSecurityGroups_FilterByDescription(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1062,6 +1115,7 @@ func TestDescribeSecurityGroups_FilterByDescription(t *testing.T) { } func TestDescribeSecurityGroups_FilterByVpcId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpc1 := createTestVPC(t, svc, "10.0.0.0/16") vpc2 := createTestVPC(t, svc, "172.16.0.0/16") @@ -1082,6 +1136,7 @@ func TestDescribeSecurityGroups_FilterByVpcId(t *testing.T) { } func TestDescribeSecurityGroups_FilterByIpPermissionCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "cidr-sg") @@ -1114,6 +1169,7 @@ func TestDescribeSecurityGroups_FilterByIpPermissionCidr(t *testing.T) { } func TestDescribeSecurityGroups_FilterMultipleValues_OR(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSG(t, svc, vpcID, "sg-alpha") @@ -1130,6 +1186,7 @@ func TestDescribeSecurityGroups_FilterMultipleValues_OR(t *testing.T) { } func TestDescribeSecurityGroups_FilterMultipleFilters_AND(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpc1 := createTestVPC(t, svc, "10.0.0.0/16") vpc2 := createTestVPC(t, svc, "172.16.0.0/16") @@ -1148,6 +1205,7 @@ func TestDescribeSecurityGroups_FilterMultipleFilters_AND(t *testing.T) { } func TestDescribeSecurityGroups_FilterUnknownName_Error(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DescribeSecurityGroups(context.Background(), &ec2.DescribeSecurityGroupsInput{ @@ -1159,6 +1217,7 @@ func TestDescribeSecurityGroups_FilterUnknownName_Error(t *testing.T) { } func TestDescribeSecurityGroups_FilterWildcard(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSG(t, svc, vpcID, "prod-web") @@ -1175,6 +1234,7 @@ func TestDescribeSecurityGroups_FilterWildcard(t *testing.T) { } func TestDescribeSecurityGroups_FilterByTag(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1204,6 +1264,7 @@ func TestDescribeSecurityGroups_FilterByTag(t *testing.T) { } func TestDescribeSecurityGroups_FilterNoResults(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSG(t, svc, vpcID, "my-sg") @@ -1243,6 +1304,7 @@ func findDefaultSGInVPC(t *testing.T, svc *VPCServiceImpl, vpcID string) string } func TestCreateVpc_ProvisionsDefaultSG(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1264,6 +1326,7 @@ func TestCreateVpc_ProvisionsDefaultSG(t *testing.T) { } func TestCreateSecurityGroup_RejectsReservedDefaultName(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1277,6 +1340,7 @@ func TestCreateSecurityGroup_RejectsReservedDefaultName(t *testing.T) { } func TestDeleteSecurityGroup_RejectsDefault(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := findDefaultSGInVPC(t, svc, vpcID) @@ -1289,6 +1353,7 @@ func TestDeleteSecurityGroup_RejectsDefault(t *testing.T) { } func TestDeleteSecurityGroup_RejectsAttachedToENI(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1308,6 +1373,7 @@ func TestDeleteSecurityGroup_RejectsAttachedToENI(t *testing.T) { } func TestDeleteSecurityGroup_RejectsReferencedFromOtherSG(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") srcSG := createTestSG(t, svc, vpcID, "src-sg") @@ -1331,6 +1397,7 @@ func TestDeleteSecurityGroup_RejectsReferencedFromOtherSG(t *testing.T) { } func TestDeleteVpc_BlocksOnNonDefaultSG(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "user-sg") @@ -1344,6 +1411,7 @@ func TestDeleteVpc_BlocksOnNonDefaultSG(t *testing.T) { } func TestDeleteVpc_CascadesDefaultSG(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") defaultSG := findDefaultSGInVPC(t, svc, vpcID) @@ -1360,6 +1428,7 @@ func TestDeleteVpc_CascadesDefaultSG(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_RuleLimit(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "rule-limit-sg") @@ -1392,6 +1461,7 @@ func TestAuthorizeSecurityGroupIngress_RuleLimit(t *testing.T) { } func TestEnsureDefaultVPC_CreatesDefaultSG(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) info, err := svc.EnsureDefaultVPC(testAccountID) require.NoError(t, err) @@ -1410,6 +1480,7 @@ func TestEnsureDefaultVPC_CreatesDefaultSG(t *testing.T) { // --- SourceSG existence + same-VPC validation on Authorize --- func TestAuthorizeSecurityGroupIngress_SourceSG_SameVPC(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") ownerSG := createTestSG(t, svc, vpcID, "owner-sg") @@ -1427,6 +1498,7 @@ func TestAuthorizeSecurityGroupIngress_SourceSG_SameVPC(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_SourceSG_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") ownerSG := createTestSG(t, svc, vpcID, "owner-sg-nf") @@ -1445,6 +1517,7 @@ func TestAuthorizeSecurityGroupIngress_SourceSG_NotFound(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_SourceSG_CrossVPC(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcA := createTestVPC(t, svc, "10.0.0.0/16") vpcB := createTestVPC(t, svc, "10.1.0.0/16") @@ -1465,6 +1538,7 @@ func TestAuthorizeSecurityGroupIngress_SourceSG_CrossVPC(t *testing.T) { } func TestAuthorizeSecurityGroupEgress_SourceSG_CrossVPC(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcA := createTestVPC(t, svc, "10.0.0.0/16") vpcB := createTestVPC(t, svc, "10.1.0.0/16") @@ -1486,6 +1560,7 @@ func TestAuthorizeSecurityGroupEgress_SourceSG_CrossVPC(t *testing.T) { // --- Egress dependency check (mirror of ingress coverage) --- func TestDeleteSecurityGroup_RejectsReferencedFromOtherSGEgress(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") srcSG := createTestSG(t, svc, vpcID, "egress-src-sg") @@ -1511,6 +1586,7 @@ func TestDeleteSecurityGroup_RejectsReferencedFromOtherSGEgress(t *testing.T) { // --- Egress rule-count limit (mirror of ingress) --- func TestAuthorizeSecurityGroupEgress_RuleLimit(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "egress-rule-limit-sg") @@ -1550,6 +1626,7 @@ func TestAuthorizeSecurityGroupEgress_RuleLimit(t *testing.T) { // persists on vpcd error — the orphan-PG reconciler is the safety net. This // asserts both the error is surfaced AND the KV-first contract is held. func TestCreateSecurityGroup_VpcdError_RecordPersists(t *testing.T) { + t.Parallel() svc, _ := setupTestVPCServiceWithFailingVpcd(t, "forced-create-sg-error") // CreateVpc also publishes vpc.create-sg and would fail; seed the VPC @@ -1575,6 +1652,7 @@ func TestCreateSecurityGroup_VpcdError_RecordPersists(t *testing.T) { } func TestDeleteSecurityGroup_VpcdError_Propagated(t *testing.T) { + t.Parallel() // Build the SG using a temporary success stub, then swap to failing for // the delete call. svc, nc := setupTestVPCServiceWithNC(t) @@ -1601,6 +1679,7 @@ func TestDeleteSecurityGroup_VpcdError_Propagated(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_VpcdError_Propagated(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "to-authorize") @@ -1630,6 +1709,7 @@ func TestAuthorizeSecurityGroupIngress_VpcdError_Propagated(t *testing.T) { } func TestRevokeSecurityGroupIngress_VpcdError_Propagated(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "to-revoke") @@ -1660,6 +1740,7 @@ func TestRevokeSecurityGroupIngress_VpcdError_Propagated(t *testing.T) { // TestAuthorizeSecurityGroupEgress_VpcdError_Propagated asserts that vpcd // failures on the egress path are surfaced to the caller. func TestAuthorizeSecurityGroupEgress_VpcdError_Propagated(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "egress-vpcd-fail") @@ -1681,6 +1762,7 @@ func TestAuthorizeSecurityGroupEgress_VpcdError_Propagated(t *testing.T) { } func TestRevokeSecurityGroupEgress_VpcdError_Propagated(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "egress-revoke-fail") @@ -1704,6 +1786,7 @@ func TestRevokeSecurityGroupEgress_VpcdError_Propagated(t *testing.T) { // TestFindDefaultSGForVPC_NoMatch asserts that a lookup for vpcB's default SG // returns "" (not an error) when only vpcA has SGs. func TestFindDefaultSGForVPC_NoMatch(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcA := createTestVPC(t, svc, "10.0.0.0/16") _ = createTestSG(t, svc, vpcA, "non-default-a") @@ -1716,6 +1799,7 @@ func TestFindDefaultSGForVPC_NoMatch(t *testing.T) { // TestFindDefaultSGForVPC_SkipsMalformedRecord asserts that a corrupt SG entry // is skipped rather than aborting the scan. func TestFindDefaultSGForVPC_SkipsMalformedRecord(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1732,6 +1816,7 @@ func TestFindDefaultSGForVPC_SkipsMalformedRecord(t *testing.T) { // --- Fix #1: DeleteVpc cascade failure must leave VPC record intact --- func TestDeleteVpc_VpcdError_VPCNotDeleted(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1753,6 +1838,7 @@ func TestDeleteVpc_VpcdError_VPCNotDeleted(t *testing.T) { // --- Fix #3: checkSGDependencies fails closed on KV read error --- func TestDeleteSecurityGroup_FailsClosedOnCorruptENI(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "to-delete-corrupt") @@ -1831,6 +1917,7 @@ func authorizeIngressTCP(t *testing.T, svc *VPCServiceImpl, sgID string, port in } func TestDescribeSecurityGroupRules_All(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgA := createTestSG(t, svc, vpcID, "rules-a") @@ -1866,6 +1953,7 @@ func TestDescribeSecurityGroupRules_All(t *testing.T) { } func TestDescribeSecurityGroupRules_FilterByGroupID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgA := createTestSG(t, svc, vpcID, "filter-a") @@ -1884,6 +1972,7 @@ func TestDescribeSecurityGroupRules_FilterByGroupID(t *testing.T) { } func TestDescribeSecurityGroupRules_FilterByRuleID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "by-rule-id") @@ -1898,6 +1987,7 @@ func TestDescribeSecurityGroupRules_FilterByRuleID(t *testing.T) { } func TestDescribeSecurityGroupRules_ByRuleIDsExplicit(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "explicit-ids") @@ -1912,6 +2002,7 @@ func TestDescribeSecurityGroupRules_ByRuleIDsExplicit(t *testing.T) { } func TestDescribeSecurityGroupRules_RuleIDNotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSG(t, svc, vpcID, "any") @@ -1924,6 +2015,7 @@ func TestDescribeSecurityGroupRules_RuleIDNotFound(t *testing.T) { } func TestDescribeSecurityGroupRules_NilInput(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSG(t, svc, vpcID, "nil-input") @@ -1934,6 +2026,7 @@ func TestDescribeSecurityGroupRules_NilInput(t *testing.T) { } func TestDescribeSecurityGroupRules_TagFiltersReturnNothing(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "tag-filter") @@ -1947,6 +2040,7 @@ func TestDescribeSecurityGroupRules_TagFiltersReturnNothing(t *testing.T) { } func TestDescribeSecurityGroupRules_ReferencedGroupInfo(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") srcSG := createTestSG(t, svc, vpcID, "source") @@ -1986,6 +2080,7 @@ func TestDescribeSecurityGroupRules_ReferencedGroupInfo(t *testing.T) { } func TestAuthorizeSecurityGroupIngress_AssignsRuleIDs(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "assigns-ids") @@ -2015,6 +2110,7 @@ func TestAuthorizeSecurityGroupIngress_AssignsRuleIDs(t *testing.T) { // TestAuthorizeSecurityGroupIngress_RejectsContentDuplicate verifies key-based // dedup catches duplicate-content rules regardless of generated RuleId values. func TestAuthorizeSecurityGroupIngress_RejectsContentDuplicate(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") sgID := createTestSG(t, svc, vpcID, "dup-rule") @@ -2041,6 +2137,7 @@ func TestAuthorizeSecurityGroupIngress_RejectsContentDuplicate(t *testing.T) { } func TestDescribeSecurityGroupRules_InvalidFilter(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSG(t, svc, vpcID, "invalid-filter") @@ -2059,6 +2156,7 @@ func TestDescribeSecurityGroupRules_InvalidFilter(t *testing.T) { // cannot match its rules, never revokes them, and the backend SG is pinned by // DependencyViolation — hanging tofu destroy with orphaned security groups. func TestSecurityGroupRule_DescriptionRoundTrips(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") nodeSG := createTestSG(t, svc, vpcID, "node-sg") diff --git a/spinifex/handlers/ec2/vpc/service_impl_test.go b/spinifex/handlers/ec2/vpc/service_impl_test.go index e29f7d8ae..0b4340e9d 100644 --- a/spinifex/handlers/ec2/vpc/service_impl_test.go +++ b/spinifex/handlers/ec2/vpc/service_impl_test.go @@ -67,6 +67,7 @@ func createTestSubnet(t *testing.T, svc *VPCServiceImpl, vpcID, cidr string) str // --- VPC Tests --- func TestCreateVpc(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) out, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ CidrBlock: aws.String("10.0.0.0/16"), @@ -80,12 +81,14 @@ func TestCreateVpc(t *testing.T) { } func TestCreateVpc_MissingCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{}, testAccountID) assert.ErrorContains(t, err, "MissingParameter") } func TestCreateVpc_EmptyCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ CidrBlock: aws.String(""), @@ -94,6 +97,7 @@ func TestCreateVpc_EmptyCidr(t *testing.T) { } func TestCreateVpc_InvalidCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ CidrBlock: aws.String("not-a-cidr"), @@ -102,6 +106,7 @@ func TestCreateVpc_InvalidCidr(t *testing.T) { } func TestCreateVpc_CidrTooLarge(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ CidrBlock: aws.String("10.0.0.0/8"), @@ -110,6 +115,7 @@ func TestCreateVpc_CidrTooLarge(t *testing.T) { } func TestCreateVpc_CidrTooSmall(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ CidrBlock: aws.String("10.0.0.0/29"), @@ -118,6 +124,7 @@ func TestCreateVpc_CidrTooSmall(t *testing.T) { } func TestCreateVpc_WithTags(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) out, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ CidrBlock: aws.String("10.0.0.0/16"), @@ -144,6 +151,7 @@ func TestCreateVpc_WithTags(t *testing.T) { } func TestCreateVpc_TagsWrongResourceType(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) out, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ CidrBlock: aws.String("10.0.0.0/16"), @@ -161,6 +169,7 @@ func TestCreateVpc_TagsWrongResourceType(t *testing.T) { } func TestCreateVpc_VNIIncrement(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) // Create two VPCs and verify they get different VNIs @@ -174,6 +183,7 @@ func TestCreateVpc_VNIIncrement(t *testing.T) { } func TestDeleteVpc(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -191,12 +201,14 @@ func TestDeleteVpc(t *testing.T) { } func TestDeleteVpc_MissingID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DeleteVpc(context.Background(), &ec2.DeleteVpcInput{}, testAccountID) assert.ErrorContains(t, err, "MissingParameter") } func TestDeleteVpc_WithSubnets(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -212,6 +224,7 @@ func TestDeleteVpc_WithSubnets(t *testing.T) { } func TestDescribeVpcs_All(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") createTestVPC(t, svc, "10.1.0.0/16") @@ -222,6 +235,7 @@ func TestDescribeVpcs_All(t *testing.T) { } func TestDescribeVpcs_ByID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestVPC(t, svc, "10.1.0.0/16") @@ -235,6 +249,7 @@ func TestDescribeVpcs_ByID(t *testing.T) { } func TestDescribeVpcs_Empty(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) desc, err := svc.DescribeVpcs(context.Background(), &ec2.DescribeVpcsInput{}, testAccountID) require.NoError(t, err) @@ -242,6 +257,7 @@ func TestDescribeVpcs_Empty(t *testing.T) { } func TestDescribeVpcs_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DescribeVpcs(context.Background(), &ec2.DescribeVpcsInput{ VpcIds: []*string{aws.String("vpc-nonexistent")}, @@ -252,6 +268,7 @@ func TestDescribeVpcs_NotFound(t *testing.T) { // --- Subnet Tests --- func TestCreateSubnet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -270,6 +287,7 @@ func TestCreateSubnet(t *testing.T) { } func TestCreateSubnet_MissingVpcId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateSubnet(context.Background(), &ec2.CreateSubnetInput{ CidrBlock: aws.String("10.0.1.0/24"), @@ -278,6 +296,7 @@ func TestCreateSubnet_MissingVpcId(t *testing.T) { } func TestCreateSubnet_MissingCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") _, err := svc.CreateSubnet(context.Background(), &ec2.CreateSubnetInput{ @@ -287,6 +306,7 @@ func TestCreateSubnet_MissingCidr(t *testing.T) { } func TestCreateSubnet_InvalidVpcId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.CreateSubnet(context.Background(), &ec2.CreateSubnetInput{ VpcId: aws.String("vpc-nonexistent"), @@ -296,6 +316,7 @@ func TestCreateSubnet_InvalidVpcId(t *testing.T) { } func TestCreateSubnet_InvalidCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") _, err := svc.CreateSubnet(context.Background(), &ec2.CreateSubnetInput{ @@ -306,6 +327,7 @@ func TestCreateSubnet_InvalidCidr(t *testing.T) { } func TestCreateSubnet_OutsideVpcCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") _, err := svc.CreateSubnet(context.Background(), &ec2.CreateSubnetInput{ @@ -316,6 +338,7 @@ func TestCreateSubnet_OutsideVpcCidr(t *testing.T) { } func TestCreateSubnet_ConflictingCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -329,6 +352,7 @@ func TestCreateSubnet_ConflictingCidr(t *testing.T) { } func TestCreateSubnet_WithTags(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -349,6 +373,7 @@ func TestCreateSubnet_WithTags(t *testing.T) { } func TestCreateSubnet_WithAZ(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -362,6 +387,7 @@ func TestCreateSubnet_WithAZ(t *testing.T) { } func TestDeleteSubnet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -380,12 +406,14 @@ func TestDeleteSubnet(t *testing.T) { } func TestDeleteSubnet_MissingID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DeleteSubnet(context.Background(), &ec2.DeleteSubnetInput{}, testAccountID) assert.ErrorContains(t, err, "MissingParameter") } func TestDescribeSubnets_All(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -397,6 +425,7 @@ func TestDescribeSubnets_All(t *testing.T) { } func TestDescribeSubnets_ByID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -411,6 +440,7 @@ func TestDescribeSubnets_ByID(t *testing.T) { } func TestDescribeSubnets_ByVpcId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpc1 := createTestVPC(t, svc, "10.0.0.0/16") vpc2 := createTestVPC(t, svc, "10.1.0.0/16") @@ -431,6 +461,7 @@ func TestDescribeSubnets_ByVpcId(t *testing.T) { } func TestDescribeSubnets_Empty(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) desc, err := svc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) require.NoError(t, err) @@ -438,6 +469,7 @@ func TestDescribeSubnets_Empty(t *testing.T) { } func TestDescribeSubnets_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{ SubnetIds: []*string{aws.String("subnet-nonexistent")}, @@ -446,6 +478,7 @@ func TestDescribeSubnets_NotFound(t *testing.T) { } func TestCreateMultipleSubnetsInVpc(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -467,6 +500,7 @@ func TestCreateMultipleSubnetsInVpc(t *testing.T) { } func TestDeleteVpcAfterSubnetsDeleted(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -485,6 +519,7 @@ func TestDeleteVpcAfterSubnetsDeleted(t *testing.T) { } func TestCreateSubnet_CidrRanges(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -509,6 +544,7 @@ func TestCreateSubnet_CidrRanges(t *testing.T) { // --- Default VPC Tests --- func TestEnsureDefaultVPC(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) info, err := svc.EnsureDefaultVPC(testAccountID) @@ -536,6 +572,7 @@ func TestEnsureDefaultVPC(t *testing.T) { } func TestEnsureDefaultVPC_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) // Call twice — should be idempotent @@ -555,6 +592,7 @@ func TestEnsureDefaultVPC_Idempotent(t *testing.T) { } func TestEnsureDefaultVPC_SkipsWhenDefaultExists(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) // Create default VPC first @@ -586,6 +624,7 @@ func TestEnsureDefaultVPC_SkipsWhenDefaultExists(t *testing.T) { // call for the same VPC is a no-op. Concurrent calls otherwise create duplicate // IsMain=true records, corrupting route-table resolution. func TestCreateMainRouteTable_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.99.0.0/16") // CreateVpc auto-calls createMainRouteTable @@ -608,6 +647,7 @@ func TestCreateMainRouteTable_Idempotent(t *testing.T) { // (AWS-faithful), so without DeleteVpc reaping it the rtbKV bucket leaks one // orphaned main RT per deleted VPC. func TestDeleteVpc_ReapsMainRouteTable(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.77.0.0/16") // auto-creates the main RT @@ -720,6 +760,7 @@ func getTestRouteTableAssociations(t *testing.T, svc *VPCServiceImpl, accountID, // is removed out from under the route table, orphaning it permanently since // DeleteRouteTable can never resolve a VpcId that no longer exists. func TestDeleteVpc_RejectsNonMainRouteTable(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.60.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.60.1.0/24") @@ -743,6 +784,7 @@ func TestDeleteVpc_RejectsNonMainRouteTable(t *testing.T) { // strips the only id that can detach it, leaving a gateway that can never be // detached or deleted and an account teardown that can never finish. func TestDeleteVpc_RejectsAttachedInternetGateway(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.64.0.0/16") @@ -762,6 +804,7 @@ func TestDeleteVpc_RejectsAttachedInternetGateway(t *testing.T) { // A gateway attached to some other VPC must not block this one. func TestDeleteVpc_IgnoresInternetGatewayOnAnotherVPC(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.65.0.0/16") @@ -778,6 +821,7 @@ func TestDeleteVpc_IgnoresInternetGatewayOnAnotherVPC(t *testing.T) { // a transient/corrupt read must never let DeleteVpc orphan a route table it // could not evaluate. func TestDeleteVpc_RouteTableCheckFailsClosedOnCorruptRTB(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.61.0.0/16") @@ -793,6 +837,7 @@ func TestDeleteVpc_RouteTableCheckFailsClosedOnCorruptRTB(t *testing.T) { // every association naming the deleted subnet, so the route table it leaves // behind never carries a reference to a subnet that no longer exists. func TestDeleteSubnet_ClearsRouteTableAssociations(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.62.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.62.1.0/24") @@ -810,6 +855,7 @@ func TestDeleteSubnet_ClearsRouteTableAssociations(t *testing.T) { // it cannot be typed here; a mirror struct would silently erase every field // added to RouteTableRecord that the mirror had not caught up with. func TestDeleteSubnet_PreservesUnknownRouteTableFields(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.63.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.63.1.0/24") @@ -845,6 +891,7 @@ func TestDeleteSubnet_PreservesUnknownRouteTableFields(t *testing.T) { // associations for one subnet does not touch a route table association // belonging to a different subnet/VPC. func TestDeleteSubnet_LeavesOtherVPCsAssociationsAlone(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcA := createTestVPC(t, svc, "10.63.0.0/16") @@ -868,6 +915,7 @@ func TestDeleteSubnet_LeavesOtherVPCsAssociationsAlone(t *testing.T) { // operation retryable, rather than deleting the subnet with a stale // association strand behind it unseen. func TestDeleteSubnet_RouteTableCheckFailsClosedOnCorruptRTB(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.65.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.65.1.0/24") @@ -888,6 +936,7 @@ func TestDeleteSubnet_RouteTableCheckFailsClosedOnCorruptRTB(t *testing.T) { // EnsureDefaultVPC runs before vpcd has subscribed. The SG step is best-effort, // so subnet and RTB must still land in KV when vpcd is absent. func TestEnsureDefaultVPC_NoVpcdResponder(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) svc, err := NewVPCServiceImplWithNATS(t.Context(), nil, nc) require.NoError(t, err) @@ -940,6 +989,7 @@ func TestEnsureDefaultVPC_NoVpcdResponder(t *testing.T) { } func TestGetDefaultSubnet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) // No default subnet yet @@ -957,6 +1007,7 @@ func TestGetDefaultSubnet(t *testing.T) { } func TestGetDefaultSubnet_NotConfusedByNonDefault(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) // Create a non-default VPC + subnet @@ -976,6 +1027,7 @@ func TestGetDefaultSubnet_NotConfusedByNonDefault(t *testing.T) { } func TestCreateSubnet_CidrTooSmall(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") _, err := svc.CreateSubnet(context.Background(), &ec2.CreateSubnetInput{ @@ -986,6 +1038,7 @@ func TestCreateSubnet_CidrTooSmall(t *testing.T) { } func TestVpcCidrBlockAssociation(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) out, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ CidrBlock: aws.String("10.0.0.0/16"), @@ -999,6 +1052,7 @@ func TestVpcCidrBlockAssociation(t *testing.T) { // --- Filter tests --- func TestDescribeVpcs_NilFields(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") @@ -1012,6 +1066,7 @@ func TestDescribeVpcs_NilFields(t *testing.T) { } func TestDescribeSubnets_FilterByVpcId_NoMatch(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1032,6 +1087,7 @@ func TestDescribeSubnets_FilterByVpcId_NoMatch(t *testing.T) { // --- NATS event tests --- func TestCreateVpc_PublishesEvent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) eventCh := make(chan *nats.Msg, 1) @@ -1057,6 +1113,7 @@ func TestCreateVpc_PublishesEvent(t *testing.T) { } func TestDeleteVpc_PublishesEvent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1081,6 +1138,7 @@ func TestDeleteVpc_PublishesEvent(t *testing.T) { } func TestCreateSubnet_PublishesEvent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1108,6 +1166,7 @@ func TestCreateSubnet_PublishesEvent(t *testing.T) { } func TestDeleteSubnet_PublishesEvent(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1136,6 +1195,7 @@ func TestDeleteSubnet_PublishesEvent(t *testing.T) { // --- Additional coverage tests --- func TestEnsureDefaultVPC_WithConfigAZ(t *testing.T) { + t.Parallel() // Create a service with custom config that has AZ set _, nc, _ := testutil.StartTestJetStream(t) testutil.StubVpcdSGResponder(t, nc) @@ -1155,6 +1215,7 @@ func TestEnsureDefaultVPC_WithConfigAZ(t *testing.T) { } func TestCreateVpc_NormalizesNetworkCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) // Pass a CIDR with host bits set — should be normalized to network address out, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ @@ -1166,6 +1227,7 @@ func TestCreateVpc_NormalizesNetworkCidr(t *testing.T) { } func TestDeleteVpc_WithENIs(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1188,6 +1250,7 @@ func TestDeleteVpc_WithENIs(t *testing.T) { } func TestCreateNetworkInterface_WithExplicitIP(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1201,12 +1264,14 @@ func TestCreateNetworkInterface_WithExplicitIP(t *testing.T) { } func TestAttachENI_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.AttachENI(testAccountID, "eni-nonexistent", "i-test", 0) assert.ErrorContains(t, err, "InvalidNetworkInterfaceID.NotFound") } func TestDetachENI_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) err := svc.DetachENI(context.Background(), testAccountID, "eni-nonexistent") assert.ErrorContains(t, err, "InvalidNetworkInterfaceID.NotFound") @@ -1215,6 +1280,7 @@ func TestDetachENI_NotFound(t *testing.T) { // --- Per-account isolation tests --- func TestEnsureDefaultVPC_PerAccountIsolation(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) accountA := "111111111111" accountB := "222222222222" @@ -1240,6 +1306,7 @@ func TestEnsureDefaultVPC_PerAccountIsolation(t *testing.T) { } func TestEnsureDefaultVPC_IndependentVNIs(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) accountA := "111111111111" accountB := "222222222222" @@ -1275,6 +1342,7 @@ func TestEnsureDefaultVPC_IndependentVNIs(t *testing.T) { } func TestDescribeVpcs_NoGlobalSharing(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) globalAccount := "000000000000" otherAccount := "111111111111" @@ -1290,6 +1358,7 @@ func TestDescribeVpcs_NoGlobalSharing(t *testing.T) { } func TestGetDefaultSubnet_PerAccount(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) accountA := "111111111111" accountB := "222222222222" @@ -1312,6 +1381,7 @@ func TestGetDefaultSubnet_PerAccount(t *testing.T) { // --- EnsureDefaultVPC event test --- func TestEnsureDefaultVPC_PublishesEvents(t *testing.T) { + t.Parallel() svc, nc := setupTestVPCServiceWithNC(t) vpcCh := make(chan *nats.Msg, 1) @@ -1346,6 +1416,7 @@ func TestEnsureDefaultVPC_PublishesEvents(t *testing.T) { // --- MapPublicIpOnLaunch tests --- func TestSubnet_MapPublicIpOnLaunch(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1360,6 +1431,7 @@ func TestSubnet_MapPublicIpOnLaunch(t *testing.T) { } func TestSubnet_ModifyAttribute(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1385,6 +1457,7 @@ func TestSubnet_ModifyAttribute(t *testing.T) { // --- VPC Attribute Tests --- func TestVpc_DescribeVpcAttribute_Defaults(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1415,6 +1488,7 @@ func TestVpc_DescribeVpcAttribute_Defaults(t *testing.T) { } func TestVpc_ModifyVpcAttribute_EnableDnsHostnames(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1435,6 +1509,7 @@ func TestVpc_ModifyVpcAttribute_EnableDnsHostnames(t *testing.T) { } func TestVpc_ModifyVpcAttribute_EnableDnsSupport(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1455,6 +1530,7 @@ func TestVpc_ModifyVpcAttribute_EnableDnsSupport(t *testing.T) { } func TestVpc_ModifyVpcAttribute_IndependentFields(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1474,6 +1550,7 @@ func TestVpc_ModifyVpcAttribute_IndependentFields(t *testing.T) { } func TestVpc_DescribeVpcAttribute_InvalidVpcID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DescribeVpcAttribute(context.Background(), &ec2.DescribeVpcAttributeInput{ @@ -1484,6 +1561,7 @@ func TestVpc_DescribeVpcAttribute_InvalidVpcID(t *testing.T) { } func TestVpc_DescribeVpcAttribute_InvalidAttribute(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1495,6 +1573,7 @@ func TestVpc_DescribeVpcAttribute_InvalidAttribute(t *testing.T) { } func TestVpc_DescribeVpcAttribute_MissingAttribute(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1505,6 +1584,7 @@ func TestVpc_DescribeVpcAttribute_MissingAttribute(t *testing.T) { } func TestVpc_ModifyVpcAttribute_EnableNetworkAddressUsageMetrics(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1523,6 +1603,7 @@ func TestVpc_ModifyVpcAttribute_EnableNetworkAddressUsageMetrics(t *testing.T) { } func TestVpc_ModifyVpcAttribute_NoAttributes(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1533,6 +1614,7 @@ func TestVpc_ModifyVpcAttribute_NoAttributes(t *testing.T) { } func TestVpc_ModifyVpcAttribute_InvalidVpcID(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.ModifyVpcAttribute(context.Background(), &ec2.ModifyVpcAttributeInput{ @@ -1545,6 +1627,7 @@ func TestVpc_ModifyVpcAttribute_InvalidVpcID(t *testing.T) { // --- DescribeVpcs filter tests --- func TestDescribeVpcs_FilterByCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") createTestVPC(t, svc, "172.16.0.0/16") @@ -1560,6 +1643,7 @@ func TestDescribeVpcs_FilterByCidr(t *testing.T) { } func TestDescribeVpcs_FilterByState(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") @@ -1582,6 +1666,7 @@ func TestDescribeVpcs_FilterByState(t *testing.T) { } func TestDescribeVpcs_FilterByIsDefault(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") @@ -1603,6 +1688,7 @@ func TestDescribeVpcs_FilterByIsDefault(t *testing.T) { } func TestDescribeVpcs_FilterMultipleValues_OR(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") createTestVPC(t, svc, "172.16.0.0/16") @@ -1618,6 +1704,7 @@ func TestDescribeVpcs_FilterMultipleValues_OR(t *testing.T) { } func TestDescribeVpcs_FilterMultipleFilters_AND(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") @@ -1643,6 +1730,7 @@ func TestDescribeVpcs_FilterMultipleFilters_AND(t *testing.T) { } func TestDescribeVpcs_FilterUnknownName_Error(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DescribeVpcs(context.Background(), &ec2.DescribeVpcsInput{ Filters: []*ec2.Filter{ @@ -1653,6 +1741,7 @@ func TestDescribeVpcs_FilterUnknownName_Error(t *testing.T) { } func TestDescribeVpcs_FilterWildcard(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") createTestVPC(t, svc, "10.1.0.0/16") @@ -1668,6 +1757,7 @@ func TestDescribeVpcs_FilterWildcard(t *testing.T) { } func TestDescribeVpcs_FilterNoResults(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") @@ -1681,6 +1771,7 @@ func TestDescribeVpcs_FilterNoResults(t *testing.T) { } func TestDescribeVpcs_FilterNoFilters(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") createTestVPC(t, svc, "172.16.0.0/16") @@ -1691,6 +1782,7 @@ func TestDescribeVpcs_FilterNoFilters(t *testing.T) { } func TestDescribeVpcs_FilterByTag(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) out, err := svc.CreateVpc(context.Background(), &ec2.CreateVpcInput{ @@ -1720,6 +1812,7 @@ func TestDescribeVpcs_FilterByTag(t *testing.T) { } func TestDescribeVpcs_FilterByVpcId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) id1 := createTestVPC(t, svc, "10.0.0.0/16") createTestVPC(t, svc, "172.16.0.0/16") @@ -1735,6 +1828,7 @@ func TestDescribeVpcs_FilterByVpcId(t *testing.T) { } func TestDescribeVpcs_FilterByOwnerId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) createTestVPC(t, svc, "10.0.0.0/16") @@ -1758,6 +1852,7 @@ func TestDescribeVpcs_FilterByOwnerId(t *testing.T) { // --- DescribeSubnets filter tests --- func TestDescribeSubnets_FilterByVpcId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpc1 := createTestVPC(t, svc, "10.0.0.0/16") vpc2 := createTestVPC(t, svc, "172.16.0.0/16") @@ -1775,6 +1870,7 @@ func TestDescribeSubnets_FilterByVpcId(t *testing.T) { } func TestDescribeSubnets_FilterByCidr(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1791,6 +1887,7 @@ func TestDescribeSubnets_FilterByCidr(t *testing.T) { } func TestDescribeSubnets_FilterByState(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1813,6 +1910,7 @@ func TestDescribeSubnets_FilterByState(t *testing.T) { } func TestDescribeSubnets_FilterBySubnetId(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1829,6 +1927,7 @@ func TestDescribeSubnets_FilterBySubnetId(t *testing.T) { } func TestDescribeSubnets_FilterByDefaultForAz(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1843,6 +1942,7 @@ func TestDescribeSubnets_FilterByDefaultForAz(t *testing.T) { } func TestDescribeSubnets_FilterMultipleValues_OR(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1859,6 +1959,7 @@ func TestDescribeSubnets_FilterMultipleValues_OR(t *testing.T) { } func TestDescribeSubnets_FilterMultipleFilters_AND(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpc1 := createTestVPC(t, svc, "10.0.0.0/16") vpc2 := createTestVPC(t, svc, "172.16.0.0/16") @@ -1887,6 +1988,7 @@ func TestDescribeSubnets_FilterMultipleFilters_AND(t *testing.T) { } func TestDescribeSubnets_FilterUnknownName_Error(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{ @@ -1898,6 +2000,7 @@ func TestDescribeSubnets_FilterUnknownName_Error(t *testing.T) { } func TestDescribeSubnets_FilterWildcard(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1913,6 +2016,7 @@ func TestDescribeSubnets_FilterWildcard(t *testing.T) { } func TestDescribeSubnets_FilterNoResults(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1927,6 +2031,7 @@ func TestDescribeSubnets_FilterNoResults(t *testing.T) { } func TestDescribeSubnets_FilterByTag(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") @@ -1959,6 +2064,7 @@ func TestDescribeSubnets_FilterByTag(t *testing.T) { // --- SetExternalIPAM / GetSubnet --- func TestGetSubnet_Success(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -1971,6 +2077,7 @@ func TestGetSubnet_Success(t *testing.T) { } func TestGetSubnet_NotFound(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) _, err := svc.GetSubnet(testAccountID, "subnet-missing") @@ -1981,6 +2088,7 @@ func TestGetSubnet_NotFound(t *testing.T) { // --- CreateTags write-through --- func TestApplyRecordTags_SubnetTagFilteredDescribe(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.0.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") @@ -2013,6 +2121,7 @@ func TestApplyRecordTags_SubnetTagFilteredDescribe(t *testing.T) { } func TestApplyRecordTags_VpcMergePreservesRecord(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.1.0.0/16") @@ -2033,6 +2142,7 @@ func TestApplyRecordTags_VpcMergePreservesRecord(t *testing.T) { } func TestRemoveRecordTags_Subnet(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.2.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.2.1.0/24") @@ -2064,6 +2174,7 @@ func TestRemoveRecordTags_Subnet(t *testing.T) { } func TestApplyRecordTags_SecurityGroupTagFilteredDescribe(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.3.0.0/16") sgID := createTestSG(t, svc, vpcID, "mirror-sg") @@ -2086,6 +2197,7 @@ func TestApplyRecordTags_SecurityGroupTagFilteredDescribe(t *testing.T) { } func TestRemoveRecordTags_SecurityGroup(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.4.0.0/16") sgID := createTestSG(t, svc, vpcID, "mirror-sg-del") @@ -2116,6 +2228,7 @@ func TestRemoveRecordTags_SecurityGroup(t *testing.T) { } func TestApplyRecordTags_ENITagFilteredDescribe(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) vpcID := createTestVPC(t, svc, "10.5.0.0/16") subnetID := createTestSubnet(t, svc, vpcID, "10.5.1.0/24") @@ -2139,6 +2252,7 @@ func TestApplyRecordTags_ENITagFilteredDescribe(t *testing.T) { } func TestApplyRecordTags_UnknownResourceNoError(t *testing.T) { + t.Parallel() svc := setupTestVPCService(t) // Absent subnet + non-VPC-owned resource id: both skipped without error. err := svc.ApplyRecordTags(&ec2.CreateTagsInput{ diff --git a/spinifex/handlers/ec2/vpc/service_nats_test.go b/spinifex/handlers/ec2/vpc/service_nats_test.go index 64a8cc63a..363a2d0b5 100644 --- a/spinifex/handlers/ec2/vpc/service_nats_test.go +++ b/spinifex/handlers/ec2/vpc/service_nats_test.go @@ -63,6 +63,7 @@ func handleNATSMsg[In any, Out any](msg *nats.Msg, fn func(context.Context, *In, } func TestNATSVPCService_CreateVpc(t *testing.T) { + t.Parallel() client, _, _ := setupNATSVPCServiceTest(t) out, err := client.CreateVpc(context.Background(), &ec2.CreateVpcInput{ @@ -75,6 +76,7 @@ func TestNATSVPCService_CreateVpc(t *testing.T) { } func TestNATSVPCService_DescribeVpcs(t *testing.T) { + t.Parallel() client, _, _ := setupNATSVPCServiceTest(t) // Create a VPC first @@ -98,6 +100,7 @@ func TestNATSVPCService_DescribeVpcs(t *testing.T) { } func TestNATSVPCService_DeleteVpc(t *testing.T) { + t.Parallel() client, _, _ := setupNATSVPCServiceTest(t) createOut, err := client.CreateVpc(context.Background(), &ec2.CreateVpcInput{ @@ -112,6 +115,7 @@ func TestNATSVPCService_DeleteVpc(t *testing.T) { } func TestNATSVPCService_CreateAndDeleteSubnet(t *testing.T) { + t.Parallel() client, _, _ := setupNATSVPCServiceTest(t) vpcOut, err := client.CreateVpc(context.Background(), &ec2.CreateVpcInput{ @@ -134,6 +138,7 @@ func TestNATSVPCService_CreateAndDeleteSubnet(t *testing.T) { } func TestNATSVPCService_DescribeSubnets(t *testing.T) { + t.Parallel() client, _, _ := setupNATSVPCServiceTest(t) vpcOut, err := client.CreateVpc(context.Background(), &ec2.CreateVpcInput{ @@ -153,6 +158,7 @@ func TestNATSVPCService_DescribeSubnets(t *testing.T) { } func TestNATSVPCService_CreateAndDeleteENI(t *testing.T) { + t.Parallel() client, _, _ := setupNATSVPCServiceTest(t) vpcOut, err := client.CreateVpc(context.Background(), &ec2.CreateVpcInput{ @@ -179,6 +185,7 @@ func TestNATSVPCService_CreateAndDeleteENI(t *testing.T) { } func TestNATSVPCService_DescribeNetworkInterfaces(t *testing.T) { + t.Parallel() client, _, _ := setupNATSVPCServiceTest(t) vpcOut, err := client.CreateVpc(context.Background(), &ec2.CreateVpcInput{ diff --git a/spinifex/handlers/elbv2/agent_types_test.go b/spinifex/handlers/elbv2/agent_types_test.go index e42d37780..89564041d 100644 --- a/spinifex/handlers/elbv2/agent_types_test.go +++ b/spinifex/handlers/elbv2/agent_types_test.go @@ -11,6 +11,7 @@ import ( // TestToHealthReport verifies the LBAgentHeartbeatInput.toHealthReport conversion, // in particular that aws.StringValue handles nil pointers without panicking. func TestToHealthReport(t *testing.T) { + t.Parallel() tests := []struct { name string in *LBAgentHeartbeatInput diff --git a/spinifex/handlers/elbv2/arn_test.go b/spinifex/handlers/elbv2/arn_test.go index 77ecf9192..a8afc0c39 100644 --- a/spinifex/handlers/elbv2/arn_test.go +++ b/spinifex/handlers/elbv2/arn_test.go @@ -19,6 +19,7 @@ import ( // TestBuildLBAgentEnv verifies that buildLBAgentEnv produces a KEY=value blob // containing all five env vars with the correct values. func TestBuildLBAgentEnv(t *testing.T) { + t.Parallel() svc := &ELBv2ServiceImpl{ GatewayURL: "https://10.0.0.1:9999", SystemAccessKey: "AKIAIOSFODNN7EXAMPLE", @@ -47,6 +48,7 @@ func TestBuildLBAgentEnv(t *testing.T) { // (staticCreds=false) the static keys are dropped so the lb-agent signs with // IMDS instance-role credentials via the SDK chain. func TestBuildLBAgentEnv_IMDSModeOmitsKeys(t *testing.T) { + t.Parallel() svc := &ELBv2ServiceImpl{ GatewayURL: "https://10.0.0.1:9999", SystemAccessKey: "AKIAIOSFODNN7EXAMPLE", @@ -64,6 +66,7 @@ func TestBuildLBAgentEnv_IMDSModeOmitsKeys(t *testing.T) { // system) heartbeats over the on-link mgmt-bridge URL, not the WAN GatewayURL, // so the control-plane heartbeat survives a reboot that strands the data plane. func TestBuildLBAgentEnv_UsesMgmtGateway(t *testing.T) { + t.Parallel() svc := &ELBv2ServiceImpl{ GatewayURL: "https://10.0.0.1:9999", MgmtBridgeIP: "192.168.50.1", @@ -82,12 +85,14 @@ func TestBuildLBAgentEnv_UsesMgmtGateway(t *testing.T) { // TestSubnetCIDRForIP and TestSubnetGatewayIP cover the CIDR helpers. func TestSubnetCIDRForIP(t *testing.T) { + t.Parallel() assert.Equal(t, "10.0.1.5/24", subnetCIDRForIP("10.0.1.5", "10.0.1.0/24")) assert.Equal(t, "172.16.2.10/20", subnetCIDRForIP("172.16.2.10", "172.16.0.0/20")) assert.Empty(t, subnetCIDRForIP("10.0.1.5", "bad-cidr")) } func TestSubnetGatewayIP(t *testing.T) { + t.Parallel() assert.Equal(t, "10.0.1.1", subnetGatewayIP("10.0.1.0/24")) assert.Equal(t, "172.16.0.1", subnetGatewayIP("172.16.0.0/20")) assert.Empty(t, subnetGatewayIP("not-a-cidr")) @@ -139,6 +144,7 @@ func setupMicrovmTestService(t *testing.T) (*ELBv2ServiceImpl, *handlers_ec2_vpc // TestCreateLoadBalancer_DeliversCACert asserts the CACert plumbed into the // service is forwarded to the launcher for fw_cfg delivery. func TestCreateLoadBalancer_DeliversCACert(t *testing.T) { + t.Parallel() svc, _, subnetID := setupMicrovmTestService(t) mock := &mockSystemInstanceLauncher{ @@ -164,6 +170,7 @@ func TestCreateLoadBalancer_DeliversCACert(t *testing.T) { // TestCreateLoadBalancer_Microvm_LBAgentEnv asserts all five lb-agent env vars // appear in LBAgentEnv with correct values. func TestCreateLoadBalancer_Microvm_LBAgentEnv(t *testing.T) { + t.Parallel() svc, _, subnetID := setupMicrovmTestService(t) mock := &mockSystemInstanceLauncher{ @@ -192,6 +199,7 @@ func TestCreateLoadBalancer_Microvm_LBAgentEnv(t *testing.T) { // TestCreateLoadBalancer_Microvm_NICs asserts NIC[0].IsDefault=true and // NIC[1].IsDefault=false, and that CIDR/Gateway are derived from the subnet. func TestCreateLoadBalancer_Microvm_NICs(t *testing.T) { + t.Parallel() svc, _, subnetID := setupMicrovmTestService(t) mock := &mockSystemInstanceLauncher{ @@ -238,6 +246,7 @@ func parseEnvBlob(t *testing.T, blob string) map[string]string { // TestBuildMicrovmNICs_NilVPC verifies buildMicrovmNICs works when VPCService // is nil — CIDR and gateway remain empty, NIC structure is still correct. func TestBuildMicrovmNICs_NilVPC(t *testing.T) { + t.Parallel() svc := &ELBv2ServiceImpl{VPCService: nil} nics := svc.buildMicrovmNICs("10.0.1.5", "02:aa:bb:cc:dd:01", "subnet-abc", "eni-abc", SchemeInternal, nil, testAccountID) require.Len(t, nics, 2, "primary ENI NIC + mgmt NIC") @@ -249,6 +258,7 @@ func TestBuildMicrovmNICs_NilVPC(t *testing.T) { // TestBuildMicrovmNICs_ExtraENIs verifies NIC[2+] are appended for multi-subnet ALBs. func TestBuildMicrovmNICs_ExtraENIs(t *testing.T) { + t.Parallel() svc := &ELBv2ServiceImpl{VPCService: nil} extras := []ExtraENIInput{ {ENIID: "eni-extra1", ENIMac: "02:aa:bb:cc:dd:02", ENIIP: "10.0.2.5", SubnetID: "subnet-extra1"}, @@ -263,6 +273,7 @@ func TestBuildMicrovmNICs_ExtraENIs(t *testing.T) { // internet-facing single-node must not emit a /32 via mgmt to AdvertiseIP, as that // would steal the host's WAN return path and break same-chassis ingress. func TestBuildMicrovmNICs_MgmtRoute(t *testing.T) { + t.Parallel() mk := func() *ELBv2ServiceImpl { return &ELBv2ServiceImpl{ VPCService: nil, diff --git a/spinifex/handlers/elbv2/cert_inuse_test.go b/spinifex/handlers/elbv2/cert_inuse_test.go index adee05016..d48662c26 100644 --- a/spinifex/handlers/elbv2/cert_inuse_test.go +++ b/spinifex/handlers/elbv2/cert_inuse_test.go @@ -50,6 +50,7 @@ func httpsListenerInput(lbArn, certArn string, port int64) *elbv2.CreateListener } func TestCreateListener_AddsToInUseByIndex(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-idx1", "idx-lb1") @@ -62,6 +63,7 @@ func TestCreateListener_AddsToInUseByIndex(t *testing.T) { } func TestCreateListener_TwoListenersSameCert_SingleInUseByEntry(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-idx2", "idx-lb2") @@ -77,6 +79,7 @@ func TestCreateListener_TwoListenersSameCert_SingleInUseByEntry(t *testing.T) { } func TestDeleteListener_RemovesFromInUseByIndex(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-idx3", "idx-lb3") @@ -94,6 +97,7 @@ func TestDeleteListener_RemovesFromInUseByIndex(t *testing.T) { } func TestDeleteListener_KeepsInUseByWhenAnotherListenerSharesCert(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-idx4", "idx-lb4") @@ -113,6 +117,7 @@ func TestDeleteListener_KeepsInUseByWhenAnotherListenerSharesCert(t *testing.T) } func TestModifyListener_SwitchesCertInInUseByIndex(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-idx5", "idx-lb5") @@ -135,6 +140,7 @@ func TestModifyListener_SwitchesCertInInUseByIndex(t *testing.T) { } func TestDeleteLoadBalancer_RemovesFromInUseByIndex(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-idx6", "idx-lb6") @@ -152,6 +158,7 @@ func TestDeleteLoadBalancer_RemovesFromInUseByIndex(t *testing.T) { } func TestAddRemoveListenerCertificates_MaintainInUseByIndex(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-idx7", "idx-lb7") @@ -186,11 +193,13 @@ func TestAddRemoveListenerCertificates_MaintainInUseByIndex(t *testing.T) { } func TestUpdateStoredConfigForCert_ZeroInUseBy_NoOp(t *testing.T) { + t.Parallel() svc := setupTestService(t) require.NoError(t, svc.UpdateStoredConfigForCert(context.Background(), testCertArn)) } func TestUpdateStoredConfigForCert_UnknownCert_NoOp(t *testing.T) { + t.Parallel() svc := setupTestService(t) require.NoError(t, svc.UpdateStoredConfigForCert(context.Background(), "arn:aws:acm:ap-southeast-2:000000000001:certificate/does-not-exist")) } @@ -200,6 +209,7 @@ func TestUpdateStoredConfigForCert_UnknownCert_NoOp(t *testing.T) { // LB was deleted out from under the index, and one whose LB exists but never // went active (empty InstanceID, so updateStoredConfig itself no-ops). func TestUpdateStoredConfigForCert_SkipsMissingOrInactiveLB(t *testing.T) { + t.Parallel() svc := setupTestService(t) require.NoError(t, svc.acmStore.AddInUseBy(context.Background(), testCertArn, @@ -233,6 +243,7 @@ func clearInUseBy(t *testing.T, svc *ELBv2ServiceImpl, certArn, lbArn string) { } func TestReconcileCertInUseIndex_BackfillsPreExistingListener(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-rec1", "rec-lb1") @@ -249,6 +260,7 @@ func TestReconcileCertInUseIndex_BackfillsPreExistingListener(t *testing.T) { } func TestReconcileCertInUseIndex_IsIdempotent(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-rec2", "rec-lb2") @@ -265,6 +277,7 @@ func TestReconcileCertInUseIndex_IsIdempotent(t *testing.T) { } func TestReconcileCertInUseIndex_RemovesEntryWithNoListener(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-rec3", "rec-lb3") @@ -279,6 +292,7 @@ func TestReconcileCertInUseIndex_RemovesEntryWithNoListener(t *testing.T) { } func TestReconcileCertInUseIndex_RemovesEntryForDeletedLB(t *testing.T) { + t.Parallel() svc := setupTestService(t) require.NoError(t, svc.acmStore.AddInUseBy(context.Background(), testCertArn, @@ -292,6 +306,7 @@ func TestReconcileCertInUseIndex_RemovesEntryForDeletedLB(t *testing.T) { } func TestReconcileCertInUseIndex_TwoListenersSameLB_SingleEntry(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := activeLB(t, svc, "lb-rec4", "rec-lb4") @@ -311,6 +326,7 @@ func TestReconcileCertInUseIndex_TwoListenersSameLB_SingleEntry(t *testing.T) { // A nil acmStore means HTTPS is unavailable, not that the index is broken, so // the reconcile has to no-op rather than panic on daemon startup. func TestReconcileCertInUseIndex_NilACMStore_NoOp(t *testing.T) { + t.Parallel() require.NoError(t, (&ELBv2ServiceImpl{}).ReconcileCertInUseIndex(context.Background())) } @@ -319,6 +335,7 @@ func TestReconcileCertInUseIndex_NilACMStore_NoOp(t *testing.T) { // re-import reaches no load balancer and the served leaf goes stale silently. // After a reconcile the same re-import must fan out again. func TestReconcileCertInUseIndex_RestoresRenewalFanOut(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) masterKey, err := handlers_iam.GenerateMasterKey() @@ -416,6 +433,7 @@ func genLeafCertPEM(t *testing.T, cn string, dnsNames ...string) (certPEM, keyPE // CreateListener path (which builds the InUseBy index), and the real // UpdateStoredConfigForCert fan-out. func TestACMReimport_FansOutToInUseLoadBalancer(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) // Both services read the same bucket, so they must share one key or the diff --git a/spinifex/handlers/elbv2/coverage_test.go b/spinifex/handlers/elbv2/coverage_test.go index 4558bf14e..9ce58959b 100644 --- a/spinifex/handlers/elbv2/coverage_test.go +++ b/spinifex/handlers/elbv2/coverage_test.go @@ -16,6 +16,7 @@ import ( // --- DescribeLoadBalancers: ARN filter (service_impl_test.go covers FilterByName) --- func TestDescribeLoadBalancers_FilterByArn(t *testing.T) { + t.Parallel() svc := setupTestService(t) out1, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("lb-arn-a")}, testAccountID) @@ -32,6 +33,7 @@ func TestDescribeLoadBalancers_FilterByArn(t *testing.T) { // --- DescribeTargetGroups: by name and by ARN (service_impl_test.go only covers FilterByLBArn) --- func TestDescribeTargetGroups_FilterByName(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, _ = svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("tg-alpha")}, testAccountID) @@ -46,6 +48,7 @@ func TestDescribeTargetGroups_FilterByName(t *testing.T) { } func TestDescribeTargetGroups_FilterByArn(t *testing.T) { + t.Parallel() svc := setupTestService(t) out1, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("tg-arn-a")}, testAccountID) @@ -62,6 +65,7 @@ func TestDescribeTargetGroups_FilterByArn(t *testing.T) { // --- DescribeListeners: filter by listener ARN (service_impl_test.go covers FilterByLBArn) --- func TestDescribeListeners_FilterByListenerArn(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("lb-larn")}, testAccountID) @@ -89,6 +93,7 @@ func TestDescribeListeners_FilterByListenerArn(t *testing.T) { // --- RegisterTargets edge cases --- func TestRegisterTargets_NilTargetSkipped(t *testing.T) { + t.Parallel() svc := setupTestService(t) tg, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("tg-nil"), Port: aws.Int64(80)}, testAccountID) @@ -110,6 +115,7 @@ func TestRegisterTargets_NilTargetSkipped(t *testing.T) { } func TestRegisterTargets_TGNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.RegisterTargets(context.Background(), &elbv2.RegisterTargetsInput{ TargetGroupArn: aws.String("arn:nonexistent"), @@ -119,6 +125,7 @@ func TestRegisterTargets_TGNotFound(t *testing.T) { } func TestDeregisterTargets_TGNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.DeregisterTargets(context.Background(), &elbv2.DeregisterTargetsInput{ TargetGroupArn: aws.String("arn:nonexistent"), @@ -129,6 +136,7 @@ func TestDeregisterTargets_TGNotFound(t *testing.T) { // --- Missing-ARN error paths across the service surface --- func TestMissingArnReturnsError(t *testing.T) { + t.Parallel() svc := setupTestService(t) tests := []struct { @@ -198,6 +206,7 @@ func TestMissingArnReturnsError(t *testing.T) { // --- CreateListener: missing actions (separate from missing-ARN path) --- func TestCreateListener_MissingActions(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("lb-noact")}, testAccountID) diff --git a/spinifex/handlers/elbv2/dns_register_test.go b/spinifex/handlers/elbv2/dns_register_test.go index 17ba85395..fb006f91b 100644 --- a/spinifex/handlers/elbv2/dns_register_test.go +++ b/spinifex/handlers/elbv2/dns_register_test.go @@ -9,6 +9,7 @@ import ( ) func TestLBFrontendIP(t *testing.T) { + t.Parallel() // internet-facing → the AZ-0 public IP. inet := &LoadBalancerRecord{ Scheme: SchemeInternetFacing, @@ -35,6 +36,7 @@ func TestLBFrontendIP(t *testing.T) { } func TestPublishLBDNS_NoopWhenDisabled(t *testing.T) { + t.Parallel() rec := &LoadBalancerRecord{ Scheme: SchemeInternal, DNSName: "internal-web-abc.ap-southeast-2.elb.spx3.net", @@ -48,6 +50,7 @@ func TestPublishLBDNS_NoopWhenDisabled(t *testing.T) { } func TestDesiredDNSChanges_IncludesEndpointReadyProvisioningLoadBalancers(t *testing.T) { + t.Parallel() svc := setupTestService(t) svc.dnsBaseDomain = "spx3.net" diff --git a/spinifex/handlers/elbv2/haproxy_certs_test.go b/spinifex/handlers/elbv2/haproxy_certs_test.go index 4180c3cb3..525cd5760 100644 --- a/spinifex/handlers/elbv2/haproxy_certs_test.go +++ b/spinifex/handlers/elbv2/haproxy_certs_test.go @@ -39,6 +39,7 @@ func httpsListener() *ListenerRecord { } func TestGenerateHAProxyConfigWithCerts_HTTPSRendersSslCrt(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-abc123", Name: "my-alb"} listeners := []*ListenerRecord{httpsListener()} certPEM := "CERTPEM\nKEYPEM\n" @@ -56,6 +57,7 @@ func TestGenerateHAProxyConfigWithCerts_HTTPSRendersSslCrt(t *testing.T) { } func TestGenerateHAProxyConfigWithCerts_HTTPHasNoSslCrt(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-abc123", Name: "my-alb"} listeners := []*ListenerRecord{{ ListenerArn: "arn:aws:elasticloadbalancing:us-east-1:123:listener/app/my-alb/lb-abc123/lst-http", @@ -75,6 +77,7 @@ func TestGenerateHAProxyConfigWithCerts_HTTPHasNoSslCrt(t *testing.T) { // A secure listener whose cert ARN is unresolved renders without ssl crt — the // gap surfaces at HAProxy bind time rather than silently serving cleartext. func TestGenerateHAProxyConfigWithCerts_MissingCertRendersPlain(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-abc123", Name: "my-alb"} config, certFiles, err := GenerateHAProxyConfigWithCerts( lb, []*ListenerRecord{httpsListener()}, nil, nil, "0.0.0.0", nil, @@ -85,6 +88,7 @@ func TestGenerateHAProxyConfigWithCerts_MissingCertRendersPlain(t *testing.T) { } func TestConfigCertHash_ChangesOnRotation(t *testing.T) { + t.Parallel() const cfg = "frontend ft\n bind *:443 ssl crt /etc/haproxy/certs/x.pem\n" path := "/etc/haproxy/certs/x.pem" @@ -112,6 +116,7 @@ func putTestCert(t *testing.T, svc *ELBv2ServiceImpl, arn, account, leaf, chain, } func TestResolveCertPEM_ConcatOrderAndOwnership(t *testing.T) { + t.Parallel() svc := setupTestService(t) require.NotNil(t, svc.acmStore) putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "CHAIN", "KEY") @@ -139,6 +144,7 @@ func TestResolveCertPEM_ConcatOrderAndOwnership(t *testing.T) { // ACMServiceImpl and ELBv2ServiceImpl each open their own Store over the // same JetStream bucket and must agree on the same key. func TestResolveCertPEM_CrossesACMServiceKeyBoundary(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) masterKey, err := handlers_iam.GenerateMasterKey() @@ -175,6 +181,7 @@ func TestResolveCertPEM_CrossesACMServiceKeyBoundary(t *testing.T) { } func TestValidateListenerCerts_RejectsUnknownAndWrongAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "", "KEY") @@ -199,6 +206,7 @@ func TestValidateListenerCerts_RejectsUnknownAndWrongAccount(t *testing.T) { } func TestResolveCertPEM_NoChain(t *testing.T) { + t.Parallel() svc := setupTestService(t) putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "", "KEY") @@ -208,6 +216,7 @@ func TestResolveCertPEM_NoChain(t *testing.T) { } func TestResolveListenerCerts_DedupAndResolve(t *testing.T) { + t.Parallel() svc := setupTestService(t) putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "", "KEY") @@ -224,6 +233,7 @@ func TestResolveListenerCerts_DedupAndResolve(t *testing.T) { } func TestGetLBConfig_DeliversCertFiles(t *testing.T) { + t.Parallel() svc := setupTestService(t) rec := &LoadBalancerRecord{ LoadBalancerID: "lb-deliver1", @@ -258,6 +268,7 @@ func TestGetLBConfig_DeliversCertFiles(t *testing.T) { } func TestCertFilesToSDK_SortedAndNilSafe(t *testing.T) { + t.Parallel() assert.Nil(t, certFilesToSDK(nil)) out := certFilesToSDK(map[string]string{"/b.pem": "B", "/a.pem": "A"}) diff --git a/spinifex/handlers/elbv2/haproxy_test.go b/spinifex/handlers/elbv2/haproxy_test.go index f7a69e980..6af8676e0 100644 --- a/spinifex/handlers/elbv2/haproxy_test.go +++ b/spinifex/handlers/elbv2/haproxy_test.go @@ -9,6 +9,7 @@ import ( ) func TestGenerateHAProxyConfig_SingleListenerAndBackend(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{ LoadBalancerID: "lb-abc123", Name: "my-alb", @@ -68,6 +69,7 @@ func TestGenerateHAProxyConfig_SingleListenerAndBackend(t *testing.T) { // own check and proxied traffic both speak TLS. Without it the check fails and // the server is marked DOWN, returning 503. func TestGenerateHAProxyConfig_HTTPSBackendReencrypts(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-tls"} tgArn := "arn:aws:elasticloadbalancing:us-east-1:123:targetgroup/tls-tg/tg-tls" listeners := []*ListenerRecord{ @@ -98,6 +100,7 @@ func TestGenerateHAProxyConfig_HTTPSBackendReencrypts(t *testing.T) { } func TestGenerateHAProxyConfig_MultipleListeners(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-multi"} tgArn1 := "arn:tg1" @@ -141,6 +144,7 @@ func TestGenerateHAProxyConfig_MultipleListeners(t *testing.T) { } func TestGenerateHAProxyConfig_SkipsDrainingTargets(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-drain"} tgArn := "arn:tg-drain" @@ -172,6 +176,7 @@ func TestGenerateHAProxyConfig_SkipsDrainingTargets(t *testing.T) { } func TestGenerateHAProxyConfig_SharedTargetGroup(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-shared"} tgArn := "arn:shared-tg" @@ -199,6 +204,7 @@ func TestGenerateHAProxyConfig_SharedTargetGroup(t *testing.T) { // with host-header rules forwarding to target groups. The generator must synthesize a // default backend; a dangling `default_backend bk_` makes HAProxy fail to start. func TestGenerateHAProxyConfig_FixedResponseDefault(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-ingress"} listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/wd-ingress/lb-ingress/lst-616760baf6a3031c3" appTG := "arn:aws:elasticloadbalancing:ap-southeast-2:1:targetgroup/wd-identity/tg-app1" @@ -255,6 +261,7 @@ func TestGenerateHAProxyConfig_FixedResponseDefault(t *testing.T) { // TestGenerateHAProxyConfig_FixedResponseRejectsUnsafeBody falls back to a bare // status when the body or content-type contains injection bytes. func TestGenerateHAProxyConfig_FixedResponseRejectsUnsafeBody(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-evil"} listeners := []*ListenerRecord{ { @@ -282,6 +289,7 @@ func TestGenerateHAProxyConfig_FixedResponseRejectsUnsafeBody(t *testing.T) { // HTTP→HTTPS redirect (scheme-only change, all other fields default) as a // `redirect scheme https` directive so HAProxy preserves host/path/query. func TestGenerateHAProxyConfig_RedirectSchemeDefault(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-redir"} listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/r/lb-redir/lst-aa" listeners := []*ListenerRecord{ @@ -312,6 +320,7 @@ func TestGenerateHAProxyConfig_RedirectSchemeDefault(t *testing.T) { // TestGenerateHAProxyConfig_RedirectLocation renders a redirect that changes // the host as a rebuilt `location` with HAProxy placeholders preserved. func TestGenerateHAProxyConfig_RedirectLocation(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-redir2"} listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/r/lb-redir2/lst-bb" listeners := []*ListenerRecord{ @@ -341,6 +350,7 @@ func TestGenerateHAProxyConfig_RedirectLocation(t *testing.T) { // a placeholder protocol (resolved from the listener), an explicit port, and a // custom literal path + query. func TestGenerateHAProxyConfig_RedirectCustomAll(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-redir3"} listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/r/lb-redir3/lst-dd" listeners := []*ListenerRecord{ @@ -370,6 +380,7 @@ func TestGenerateHAProxyConfig_RedirectCustomAll(t *testing.T) { // TestGenerateHAProxyConfig_RedirectRule renders a per-rule redirect action via // a synthetic backend reached by use_backend. func TestGenerateHAProxyConfig_RedirectRule(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-rr"} listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/r/lb-rr/lst-cc" appTG := "arn:aws:elasticloadbalancing:ap-southeast-2:1:targetgroup/app/tg-app" @@ -412,6 +423,7 @@ func TestGenerateHAProxyConfig_RedirectRule(t *testing.T) { // TestGenerateHAProxyConfig_RedirectRejectsInjection fails the render when a // redirect field carries HAProxy meta-characters that survived to the store. func TestGenerateHAProxyConfig_RedirectRejectsInjection(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-evil2"} listeners := []*ListenerRecord{ { @@ -432,6 +444,7 @@ func TestGenerateHAProxyConfig_RedirectRejectsInjection(t *testing.T) { } func TestGenerateHAProxyConfig_NoListeners(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-empty"} config, _, err := GenerateHAProxyConfigWithCerts(lb, nil, nil, nil, "0.0.0.0", nil) require.NoError(t, err) @@ -444,6 +457,7 @@ func TestGenerateHAProxyConfig_NoListeners(t *testing.T) { } func TestSanitizeName(t *testing.T) { + t.Parallel() tests := []struct { prefix string input string @@ -464,6 +478,7 @@ func TestSanitizeName(t *testing.T) { } func TestGenerateALBConfig_StillWorks(t *testing.T) { + t.Parallel() // Regression: ALB (no Type set) should still generate HTTP-mode config lb := &LoadBalancerRecord{ LoadBalancerID: "lb-alb-regression", diff --git a/spinifex/handlers/elbv2/health_checker_test.go b/spinifex/handlers/elbv2/health_checker_test.go index aaffb00cd..26dc82b5f 100644 --- a/spinifex/handlers/elbv2/health_checker_test.go +++ b/spinifex/handlers/elbv2/health_checker_test.go @@ -13,6 +13,7 @@ import ( // --- evaluateHealth --- func TestEvaluateHealth_InitialToHealthy(t *testing.T) { + t.Parallel() cfg := DefaultHealthCheck() ctr := &targetCounter{consecutiveHealthy: 1} @@ -22,6 +23,7 @@ func TestEvaluateHealth_InitialToHealthy(t *testing.T) { } func TestEvaluateHealth_InitialToUnhealthy(t *testing.T) { + t.Parallel() cfg := DefaultHealthCheck() ctr := &targetCounter{consecutiveUnhealthy: cfg.UnhealthyThreshold} @@ -30,6 +32,7 @@ func TestEvaluateHealth_InitialToUnhealthy(t *testing.T) { } func TestEvaluateHealth_InitialStaysInitial(t *testing.T) { + t.Parallel() cfg := DefaultHealthCheck() ctr := &targetCounter{consecutiveUnhealthy: 1} // below threshold @@ -38,6 +41,7 @@ func TestEvaluateHealth_InitialStaysInitial(t *testing.T) { } func TestEvaluateHealth_HealthyToUnhealthy(t *testing.T) { + t.Parallel() cfg := DefaultHealthCheck() ctr := &targetCounter{consecutiveUnhealthy: cfg.UnhealthyThreshold} @@ -46,6 +50,7 @@ func TestEvaluateHealth_HealthyToUnhealthy(t *testing.T) { } func TestEvaluateHealth_HealthyStaysHealthy(t *testing.T) { + t.Parallel() cfg := DefaultHealthCheck() ctr := &targetCounter{consecutiveUnhealthy: 1} // below threshold @@ -54,6 +59,7 @@ func TestEvaluateHealth_HealthyStaysHealthy(t *testing.T) { } func TestEvaluateHealth_UnhealthyToHealthy(t *testing.T) { + t.Parallel() cfg := DefaultHealthCheck() ctr := &targetCounter{consecutiveHealthy: cfg.HealthyThreshold} @@ -62,6 +68,7 @@ func TestEvaluateHealth_UnhealthyToHealthy(t *testing.T) { } func TestEvaluateHealth_UnhealthyStaysUnhealthy(t *testing.T) { + t.Parallel() cfg := DefaultHealthCheck() ctr := &targetCounter{consecutiveHealthy: cfg.HealthyThreshold - 1} @@ -70,6 +77,7 @@ func TestEvaluateHealth_UnhealthyStaysUnhealthy(t *testing.T) { } func TestEvaluateHealth_DrainingUnchanged(t *testing.T) { + t.Parallel() cfg := DefaultHealthCheck() ctr := &targetCounter{consecutiveHealthy: 100} @@ -111,6 +119,7 @@ func setupLBWithTG(t *testing.T, store *Store, lbID string, tg *TargetGroupRecor } func TestHandleHealthReport_TransitionsInitialToHealthy(t *testing.T) { + t.Parallel() store := setupTestNATS(t) hc := newHealthChecker(store) @@ -141,6 +150,7 @@ func TestHandleHealthReport_TransitionsInitialToHealthy(t *testing.T) { } func TestHandleHealthReport_UnhealthyAfterThreshold(t *testing.T) { + t.Parallel() store := setupTestNATS(t) hc := newHealthChecker(store) @@ -179,6 +189,7 @@ func TestHandleHealthReport_UnhealthyAfterThreshold(t *testing.T) { } func TestHandleHealthReport_SkipsDrainingTargets(t *testing.T) { + t.Parallel() store := setupTestNATS(t) hc := newHealthChecker(store) @@ -209,6 +220,7 @@ func TestHandleHealthReport_SkipsDrainingTargets(t *testing.T) { } func TestRemoveTarget(t *testing.T) { + t.Parallel() hc := newHealthChecker(nil) hc.mu.Lock() @@ -224,6 +236,7 @@ func TestRemoveTarget(t *testing.T) { } func TestHandleHealthReport_TargetPortZeroUsesTGPort(t *testing.T) { + t.Parallel() store := setupTestNATS(t) hc := newHealthChecker(store) @@ -259,6 +272,7 @@ func TestHandleHealthReport_TargetPortZeroUsesTGPort(t *testing.T) { } func TestHandleHealthReportDirect_TransitionsInitialToHealthy(t *testing.T) { + t.Parallel() store := setupTestNATS(t) hc := newHealthChecker(store) @@ -288,6 +302,7 @@ func TestHandleHealthReportDirect_TransitionsInitialToHealthy(t *testing.T) { } func TestHandleHealthReport_OnlyProcessesTGsForReportingLB(t *testing.T) { + t.Parallel() store := setupTestNATS(t) hc := newHealthChecker(store) @@ -335,6 +350,7 @@ func TestHandleHealthReport_OnlyProcessesTGsForReportingLB(t *testing.T) { } func TestHandleHealthReport_FallbackListTargetGroups(t *testing.T) { + t.Parallel() store := setupTestNATS(t) hc := newHealthChecker(store) @@ -366,6 +382,7 @@ func TestHandleHealthReport_FallbackListTargetGroups(t *testing.T) { } func TestEvaluateHealth_ZeroThresholdsUsesDefaults(t *testing.T) { + t.Parallel() cfg := HealthCheckConfig{} // all zeros // Unhealthy→healthy should require DefaultHealthyThreshold consecutive healthy diff --git a/spinifex/handlers/elbv2/lb_role_test.go b/spinifex/handlers/elbv2/lb_role_test.go index 5ecb6d3b3..dedf1b21e 100644 --- a/spinifex/handlers/elbv2/lb_role_test.go +++ b/spinifex/handlers/elbv2/lb_role_test.go @@ -13,6 +13,7 @@ import ( // the lazy IAMProvider when the eager IAM field is unset — the daemon wires only // the provider so the IAM build cannot race the NATS KV backend at startup. func TestEnsureLBInstanceProfile_UsesLazyProvider(t *testing.T) { + t.Parallel() f := iammock.New() s := &ELBv2ServiceImpl{IAMProvider: func() handlers_iam.SystemInstanceRoleEnsurer { return f }} @@ -25,6 +26,7 @@ func TestEnsureLBInstanceProfile_UsesLazyProvider(t *testing.T) { // resolves the profile under the instance's account, so a role created in the LB // owner account would be invisible to it and the lb-agent would get no creds. func TestEnsureLBInstanceProfile_CreatesInSystemAccount(t *testing.T) { + t.Parallel() f := iammock.New() s := &ELBv2ServiceImpl{IAM: f} @@ -37,6 +39,7 @@ func TestEnsureLBInstanceProfile_CreatesInSystemAccount(t *testing.T) { // provider returns nil because the KV backend is not up yet) yields "" so the LB // VM falls back to baked static creds and retries on the next launch. func TestEnsureLBInstanceProfile_NotReadyFallsBack(t *testing.T) { + t.Parallel() s := &ELBv2ServiceImpl{IAMProvider: func() handlers_iam.SystemInstanceRoleEnsurer { return nil }} assert.Empty(t, s.ensureLBInstanceProfile(utils.GlobalAccountID)) } diff --git a/spinifex/handlers/elbv2/lifecycle_invariants_test.go b/spinifex/handlers/elbv2/lifecycle_invariants_test.go index cb144b558..870664ef8 100644 --- a/spinifex/handlers/elbv2/lifecycle_invariants_test.go +++ b/spinifex/handlers/elbv2/lifecycle_invariants_test.go @@ -17,6 +17,7 @@ import ( // deleting an absent ELBv2 resource is success, not NotFound. Every delete endpoint // must have a case here — a missing case is an idempotency gap. func TestRLC1_ELBv2DeleteIdempotentOnAbsent(t *testing.T) { + t.Parallel() const arnBase = "arn:aws:elasticloadbalancing:us-east-1:123456789012:" cases := []struct { @@ -59,6 +60,7 @@ func TestRLC1_ELBv2DeleteIdempotentOnAbsent(t *testing.T) { // after DeleteLoadBalancer no listener or rule owned by the LB may remain. Two // listeners are used so a single-listener cascade can't pass by accident. func TestRLC2_ELBv2NoOrphanAfterDeleteLB(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("rlc2-lb")}, testAccountID) @@ -103,6 +105,7 @@ func TestRLC2_ELBv2NoOrphanAfterDeleteLB(t *testing.T) { // cascade: DeleteLoadBalancer must use deleteListenerCascade, not store.DeleteListener // directly (a direct call orphans rules). Enforced structurally against source. func TestRLC3_ELBv2DeleteLBDoesNotBypassListenerCascade(t *testing.T) { + t.Parallel() src, err := os.ReadFile("service_impl.go") require.NoError(t, err) @@ -145,6 +148,7 @@ func stripComments(src string) string { // after LB+listener+rule teardown, the target group must not remain pinned as // ResourceInUse by an orphaned rule or stale listener default action. func TestRLC4_ELBv2TGDeletableAfterLBTeardown(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("rlc4-lb")}, testAccountID) @@ -185,6 +189,7 @@ func TestRLC4_ELBv2TGDeletableAfterLBTeardown(t *testing.T) { // trap this guard prevents. Locks the liveLB/liveListener skip both ways so a // maintainer cannot regress the in-use scan back to a global rule sweep. func TestRLC3_ELBv2TGInUseGuardGatesOnLiveRefsOnly(t *testing.T) { + t.Parallel() svc := setupTestService(t) // Orphan-rule TG: forwarded to by a rule whose owning LB/listener is gone. diff --git a/spinifex/handlers/elbv2/name_claim_test.go b/spinifex/handlers/elbv2/name_claim_test.go index ac1cb7b81..5c5ce2aa7 100644 --- a/spinifex/handlers/elbv2/name_claim_test.go +++ b/spinifex/handlers/elbv2/name_claim_test.go @@ -16,6 +16,7 @@ import ( // one success and one DuplicateLoadBalancerName. The atomic name claim is the // barrier; under -race a double-claim would surface as a launcher/store race. func TestCreateLoadBalancer_ConcurrentSameNameSingleOwner(t *testing.T) { + t.Parallel() svc := setupTestService(t) const n = 2 @@ -55,6 +56,7 @@ func TestCreateLoadBalancer_ConcurrentSameNameSingleOwner(t *testing.T) { // window: a claim with no persisted LB record yet — the gap a real create // leaves open — must not be stealable by a second claimer within the TTL. func TestClaimLBName_PendingClaimBlocksSecondClaimer(t *testing.T) { + t.Parallel() svc := setupTestService(t) ok1, dup1, err := svc.store.ClaimLBName(t.Context(), "pending-lb", testAccountID, "lb-first") @@ -74,6 +76,7 @@ func TestClaimLBName_PendingClaimBlocksSecondClaimer(t *testing.T) { // crashed prior create. A fresh CreateLoadBalancer must reclaim it and succeed. // The injectable clock ages the claim so the test never sleeps. func TestCreateLoadBalancer_ReclaimsCrashOrphanNameClaim(t *testing.T) { + t.Parallel() svc := setupTestService(t) // Seed a name claim pointing at a non-existent LB (crashed create left no @@ -97,6 +100,7 @@ func TestCreateLoadBalancer_ReclaimsCrashOrphanNameClaim(t *testing.T) { // Deleting a load balancer releases its name claim so the name is immediately // reusable. func TestDeleteLoadBalancer_ReleasesNameForReuse(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -121,6 +125,7 @@ func TestDeleteLoadBalancer_ReleasesNameForReuse(t *testing.T) { // provisioning on a nonexistent subnet) must release the claim on its way out, so // a retry with the same name is not permanently locked out by the failed attempt. func TestCreateLoadBalancer_FailureAfterClaimReleasesNameForRetry(t *testing.T) { + t.Parallel() svc, _ := setupTestServiceWithVPC(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ diff --git a/spinifex/handlers/elbv2/nginx_test.go b/spinifex/handlers/elbv2/nginx_test.go index 8af034112..3e51786f2 100644 --- a/spinifex/handlers/elbv2/nginx_test.go +++ b/spinifex/handlers/elbv2/nginx_test.go @@ -42,6 +42,7 @@ func nlbTG(arn string, targets ...Target) *TargetGroupRecord { } func TestGenerateNLBStream_TCP(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-tcp", Type: LoadBalancerTypeNetwork} tgArn := "arn:aws:elasticloadbalancing:us-east-1:1:targetgroup/db/tg-db" listeners := []*ListenerRecord{tcpListener("arn:lst-tcp", "lst-tcp", ProtocolTCP, 5432, tgArn)} @@ -67,6 +68,7 @@ func TestGenerateNLBStream_TCP(t *testing.T) { } func TestGenerateNLBStream_UDP(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-udp", Type: LoadBalancerTypeNetwork} tgArn := "arn:tg-dns" listeners := []*ListenerRecord{tcpListener("arn:lst-udp", "lst-udp", ProtocolUDP, 53, tgArn)} @@ -83,6 +85,7 @@ func TestGenerateNLBStream_UDP(t *testing.T) { } func TestGenerateNLBStream_TLS(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-tls", Type: LoadBalancerTypeNetwork} tgArn := "arn:tg-tls" lst := tcpListener("arn:lst-tls", "lst-tls", ProtocolTLS, 443, tgArn) @@ -104,6 +107,7 @@ func TestGenerateNLBStream_TLS(t *testing.T) { } func TestGenerateNLBStream_TCPUDP(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-both", Type: LoadBalancerTypeNetwork} tgArn := "arn:tg-both" listeners := []*ListenerRecord{tcpListener("arn:lst-both", "lst-both", ProtocolTCPUDP, 5000, tgArn)} @@ -121,6 +125,7 @@ func TestGenerateNLBStream_TCPUDP(t *testing.T) { } func TestGenerateNLBStream_SkipsDrainingAndNoIP(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-drain", Type: LoadBalancerTypeNetwork} tgArn := "arn:tg-drain" listeners := []*ListenerRecord{tcpListener("arn:lst-drain", "lst-drain", ProtocolTCP, 3306, tgArn)} @@ -140,6 +145,7 @@ func TestGenerateNLBStream_SkipsDrainingAndNoIP(t *testing.T) { } func TestGenerateNLBStream_EmptyUpstreamPlaceholder(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb-empty", Type: LoadBalancerTypeNetwork} tgArn := "arn:tg-empty" listeners := []*ListenerRecord{tcpListener("arn:lst-empty", "lst-empty", ProtocolTCP, 80, tgArn)} @@ -153,6 +159,7 @@ func TestGenerateNLBStream_EmptyUpstreamPlaceholder(t *testing.T) { } func TestBuildNLBHealthTargets_Resolution(t *testing.T) { + t.Parallel() tgArn := "arn:aws:elasticloadbalancing:us-east-1:1:targetgroup/db/tg-db" tgByArn := map[string]*TargetGroupRecord{ tgArn: nlbTG(tgArn, @@ -174,6 +181,7 @@ func TestBuildNLBHealthTargets_Resolution(t *testing.T) { } func TestBuildNLBHealthTargets_ExplicitHCPortAndHTTP(t *testing.T) { + t.Parallel() tgArn := "arn:tg-http" tg := nlbTG(tgArn, Target{Id: "i-1", Port: 8080, PrivateIP: "10.0.0.9", HealthState: TargetHealthHealthy}) tg.HealthCheck.Protocol = ProtocolHTTP @@ -215,6 +223,7 @@ func combinedPEM(t *testing.T, cn string, dnsNames ...string) string { } func TestGenerateNLBStream_SNICertGetsItsOwnMapEntry(t *testing.T) { + t.Parallel() lb, lst, tgByArn := nlbTLSFixture("lst-sni", "arn:cert-1", "arn:cert-2") certPEM := map[string]string{ "arn:cert-1": combinedPEM(t, "default.example.com", "default.example.com"), @@ -244,6 +253,7 @@ func TestGenerateNLBStream_SNICertGetsItsOwnMapEntry(t *testing.T) { } func TestGenerateNLBStream_WildcardSANBecomesMapKey(t *testing.T) { + t.Parallel() lb, lst, tgByArn := nlbTLSFixture("lst-wild", "arn:cert-1", "arn:cert-2") certPEM := map[string]string{ "arn:cert-1": combinedPEM(t, "example.com", "example.com"), @@ -259,6 +269,7 @@ func TestGenerateNLBStream_WildcardSANBecomesMapKey(t *testing.T) { // A single certificate must keep rendering a literal path: a variable makes nginx // re-read the PEM on every handshake. func TestGenerateNLBStream_SingleCertRendersLiteralPath(t *testing.T) { + t.Parallel() lb, lst, tgByArn := nlbTLSFixture("lst-one", "arn:cert-1") certPEM := map[string]string{"arn:cert-1": combinedPEM(t, "example.com", "example.com")} @@ -272,6 +283,7 @@ func TestGenerateNLBStream_SingleCertRendersLiteralPath(t *testing.T) { // The default certificate already answers unmatched names, so a second cert that // only repeats them cannot be selected — and its key must not be shipped. func TestGenerateNLBStream_UnselectableSNICertNotDelivered(t *testing.T) { + t.Parallel() lb, lst, tgByArn := nlbTLSFixture("lst-dup", "arn:cert-1", "arn:cert-2") certPEM := map[string]string{ "arn:cert-1": combinedPEM(t, "example.com", "example.com"), @@ -289,6 +301,7 @@ func TestGenerateNLBStream_UnselectableSNICertNotDelivered(t *testing.T) { // A subject is caller-supplied on import, so a name that could break the config // must never reach a map key. func TestCertDNSNames_DropsNamesThatAreNotHostnames(t *testing.T) { + t.Parallel() pemText := combinedPEM(t, "ok.example.com", "ok.example.com", "bad name; }", "-leading-hyphen.com", "UPPER.example.com") assert.Equal(t, []string{"ok.example.com", "upper.example.com"}, certDNSNames(pemText)) diff --git a/spinifex/handlers/elbv2/reaper_test.go b/spinifex/handlers/elbv2/reaper_test.go index 0f3d65039..f53151593 100644 --- a/spinifex/handlers/elbv2/reaper_test.go +++ b/spinifex/handlers/elbv2/reaper_test.go @@ -23,6 +23,7 @@ func testLBRecord(id, state string, createdAt, lastHeartbeat time.Time) *LoadBal } func TestReapStuckProvisioningLBs(t *testing.T) { + t.Parallel() svc := setupTestService(t) now := time.Now().UTC() @@ -61,6 +62,7 @@ func TestReapStuckProvisioningLBs(t *testing.T) { // TestStartLifecycleReaper drives the ticker goroutine with a tiny interval and // confirms it reaps a stuck LB, then cancels to exercise the ctx.Done exit. func TestStartLifecycleReaper(t *testing.T) { + t.Parallel() svc := setupTestService(t) svc.reaperInterval = 5 * time.Millisecond @@ -74,7 +76,7 @@ func TestStartLifecycleReaper(t *testing.T) { require.Eventually(t, func() bool { got, err := svc.store.GetLoadBalancer(t.Context(), stuck.LoadBalancerID) return err == nil && got != nil && got.State == StateFailed - }, time.Second, 10*time.Millisecond, "reaper goroutine should mark the stuck LB failed") + }, 3*time.Second, 10*time.Millisecond, "reaper goroutine should mark the stuck LB failed") cancel() } diff --git a/spinifex/handlers/elbv2/service_impl_health_test.go b/spinifex/handlers/elbv2/service_impl_health_test.go index 4c337b888..fb5637fe0 100644 --- a/spinifex/handlers/elbv2/service_impl_health_test.go +++ b/spinifex/handlers/elbv2/service_impl_health_test.go @@ -59,6 +59,7 @@ func setupTestServiceWithInstance(t *testing.T, instanceID, instanceIP string) ( } func TestRegisterTargets_ResolvesPrivateIP(t *testing.T) { + t.Parallel() svc, _, _ := setupTestServiceWithInstance(t, "i-web001", "10.0.1.50") // Create target group @@ -91,6 +92,7 @@ func TestRegisterTargets_ResolvesPrivateIP(t *testing.T) { } func TestRegisterTargets_UnresolvableIP(t *testing.T) { + t.Parallel() svc, _, _ := setupTestServiceWithInstance(t, "i-web001", "10.0.1.50") tgOut, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -112,6 +114,7 @@ func TestRegisterTargets_UnresolvableIP(t *testing.T) { } func TestRegisterTargets_WithoutVPCService(t *testing.T) { + t.Parallel() // When VPC service is nil, IP resolution is skipped gracefully svc := setupTestService(t) @@ -132,6 +135,7 @@ func TestRegisterTargets_WithoutVPCService(t *testing.T) { } func TestRegisterTargets_MultipleInstances(t *testing.T) { + t.Parallel() svc, vpcSvc, _ := setupTestServiceWithInstance(t, "i-web001", "10.0.1.50") // Create a second instance ENI @@ -169,6 +173,7 @@ func TestRegisterTargets_MultipleInstances(t *testing.T) { // startup resets non-draining targets to "initial", preventing stale "healthy" // claims before the lb-agent has posted a fresh report after a daemon restart. func TestResetTargetHealthOnStartup_TransitionsAllNonDrainingToInitial(t *testing.T) { + t.Parallel() store := setupTestNATS(t) svc := &ELBv2ServiceImpl{store: store} @@ -204,6 +209,7 @@ func TestResetTargetHealthOnStartup_TransitionsAllNonDrainingToInitial(t *testin } func TestResetTargetHealthOnStartup_NilSafe(t *testing.T) { + t.Parallel() var svc *ELBv2ServiceImpl assert.NoError(t, svc.ResetTargetHealthOnStartup(t.Context())) @@ -214,6 +220,7 @@ func TestResetTargetHealthOnStartup_NilSafe(t *testing.T) { // A target group not forwarded to by any listener serves no traffic, so its // targets report "unused" (Target.NotInUse) instead of stalling in "initial". func TestDescribeTargetHealth_UnusedWhenNoListener(t *testing.T) { + t.Parallel() svc, _, _ := setupTestServiceWithInstance(t, "i-web001", "10.0.1.50") tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -239,6 +246,7 @@ func TestDescribeTargetHealth_UnusedWhenNoListener(t *testing.T) { // Once a listener forwards to the target group it is in use, so DescribeTargetHealth // reports the live health state ("initial" until a health report lands), not "unused". func TestDescribeTargetHealth_InUseWhenListenerForwards(t *testing.T) { + t.Parallel() svc, _, _ := setupTestServiceWithInstance(t, "i-web001", "10.0.1.50") tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ diff --git a/spinifex/handlers/elbv2/service_impl_lb_network_test.go b/spinifex/handlers/elbv2/service_impl_lb_network_test.go index 261557cd2..771d0a2b4 100644 --- a/spinifex/handlers/elbv2/service_impl_lb_network_test.go +++ b/spinifex/handlers/elbv2/service_impl_lb_network_test.go @@ -35,6 +35,7 @@ func describeLB(t *testing.T, svc *ELBv2ServiceImpl, arn string) *elbv2.LoadBala } func TestSetIpAddressType_IPv4Idempotent(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "ipt-lb") @@ -48,6 +49,7 @@ func TestSetIpAddressType_IPv4Idempotent(t *testing.T) { } func TestSetIpAddressType_DualstackRejected(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "ipt-ds") @@ -60,6 +62,7 @@ func TestSetIpAddressType_DualstackRejected(t *testing.T) { } func TestSetIpAddressType_MissingParams(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "ipt-mp") @@ -77,6 +80,7 @@ func TestSetIpAddressType_MissingParams(t *testing.T) { } func TestSetIpAddressType_NotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.SetIpAddressType(context.Background(), &elbv2.SetIpAddressTypeInput{ LoadBalancerArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/missing/lb-deadbeef"), @@ -87,6 +91,7 @@ func TestSetIpAddressType_NotFound(t *testing.T) { } func TestSetSecurityGroups_UpdatesRecord(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "sg-lb") @@ -100,6 +105,7 @@ func TestSetSecurityGroups_UpdatesRecord(t *testing.T) { } func TestSetSecurityGroups_EmptyRejected(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "sg-empty") @@ -111,6 +117,7 @@ func TestSetSecurityGroups_EmptyRejected(t *testing.T) { } func TestSetSecurityGroups_NLBRejected(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("sg-nlb"), @@ -128,6 +135,7 @@ func TestSetSecurityGroups_NLBRejected(t *testing.T) { } func TestSetSecurityGroups_NLBWithSGs_Replaces(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("sg-nlb-repl"), @@ -150,6 +158,7 @@ func TestSetSecurityGroups_NLBWithSGs_Replaces(t *testing.T) { } func TestSetSecurityGroups_TooManyRejected(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "sg-too-many") @@ -162,6 +171,7 @@ func TestSetSecurityGroups_TooManyRejected(t *testing.T) { } func TestSetSecurityGroups_CrossAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "sg-xacct") @@ -187,6 +197,7 @@ func frontendPublicIP(lb *elbv2.LoadBalancer) string { } func TestCreateLoadBalancerSync_ReturnsFrontendIP(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) mock.launchResult.PublicIP = "203.0.113.9" vid := vpcID(t, vpcSvc) @@ -207,6 +218,7 @@ func TestCreateLoadBalancerSync_ReturnsFrontendIP(t *testing.T) { } func TestCreateLoadBalancer_AsyncDefersFrontendIP(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) mock.launchResult.PublicIP = "203.0.113.9" vid := vpcID(t, vpcSvc) @@ -265,6 +277,7 @@ func vpcID(t *testing.T, vpcSvc *handlers_ec2_vpc.VPCServiceImpl) string { } func TestSetSubnets_AddSubnet(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) vid := vpcID(t, vpcSvc) sub1 := getTestSubnetID(t, vpcSvc, vid, "10.0.20.0/24", "us-east-1a") @@ -298,6 +311,7 @@ func TestSetSubnets_AddSubnet(t *testing.T) { } func TestSetSubnets_RemoveSubnet(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) vid := vpcID(t, vpcSvc) sub1 := getTestSubnetID(t, vpcSvc, vid, "10.0.22.0/24", "us-east-1a") @@ -332,6 +346,7 @@ func TestSetSubnets_RemoveSubnet(t *testing.T) { // yet caught up with the detach saw the ENI in use, logged, and left it behind. // An ENI still marked attached at delete time is that state, made deterministic. func TestSetSubnets_RemovedENIStillAttachedIsDeleted(t *testing.T) { + t.Parallel() svc, vpcSvc, _ := setupSubnetTestService(t) vid := vpcID(t, vpcSvc) sub1 := getTestSubnetID(t, vpcSvc, vid, "10.0.30.0/24", "us-east-1a") @@ -370,6 +385,7 @@ func TestSetSubnets_RemovedENIStillAttachedIsDeleted(t *testing.T) { } func TestSetSubnets_Replace(t *testing.T) { + t.Parallel() svc, vpcSvc, _ := setupSubnetTestService(t) vid := vpcID(t, vpcSvc) sub1 := getTestSubnetID(t, vpcSvc, vid, "10.0.24.0/24", "us-east-1a") @@ -396,6 +412,7 @@ func TestSetSubnets_Replace(t *testing.T) { } func TestSetSubnets_TerminateFailureRollsBackNewENIs(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) vid := vpcID(t, vpcSvc) sub1 := getTestSubnetID(t, vpcSvc, vid, "10.0.26.0/24", "us-east-1a") @@ -428,6 +445,7 @@ func TestSetSubnets_TerminateFailureRollsBackNewENIs(t *testing.T) { } func TestSetSubnets_Idempotent(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) vid := vpcID(t, vpcSvc) sub1 := getTestSubnetID(t, vpcSvc, vid, "10.0.26.0/24", "us-east-1a") @@ -453,6 +471,7 @@ func TestSetSubnets_Idempotent(t *testing.T) { } func TestSetSubnets_SubnetMappings(t *testing.T) { + t.Parallel() svc, vpcSvc, _ := setupSubnetTestService(t) vid := vpcID(t, vpcSvc) sub1 := getTestSubnetID(t, vpcSvc, vid, "10.0.27.0/24", "us-east-1a") @@ -478,6 +497,7 @@ func TestSetSubnets_SubnetMappings(t *testing.T) { } func TestSetSubnets_WithoutVPCService(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "novpc-subnets") @@ -491,6 +511,7 @@ func TestSetSubnets_WithoutVPCService(t *testing.T) { } func TestSetSubnets_MissingParams(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "subnets-mp") @@ -508,6 +529,7 @@ func TestSetSubnets_MissingParams(t *testing.T) { } func TestSetSubnets_NotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.SetSubnets(context.Background(), &elbv2.SetSubnetsInput{ LoadBalancerArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/missing/lb-deadbeef"), @@ -518,6 +540,7 @@ func TestSetSubnets_NotFound(t *testing.T) { } func TestSetSubnets_CrossAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createLBArn(t, svc, "subnets-xacct") diff --git a/spinifex/handlers/elbv2/service_impl_listener_certs_test.go b/spinifex/handlers/elbv2/service_impl_listener_certs_test.go index 3efc69632..768f2dc5e 100644 --- a/spinifex/handlers/elbv2/service_impl_listener_certs_test.go +++ b/spinifex/handlers/elbv2/service_impl_listener_certs_test.go @@ -40,6 +40,7 @@ func createHTTPSListener(t *testing.T, svc *ELBv2ServiceImpl) string { } func TestCreateListener_HTTPSRequiresCert(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbArn := createLBArn(t, svc, "https-nocert") @@ -54,6 +55,7 @@ func TestCreateListener_HTTPSRequiresCert(t *testing.T) { } func TestCreateListener_HTTPSDefaultsSslPolicy(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbArn := createLBArn(t, svc, "https-default-policy") @@ -83,6 +85,7 @@ func TestCreateListener_HTTPSDefaultsSslPolicy(t *testing.T) { } func TestCreateListener_HTTPRejectsCert(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbArn := createLBArn(t, svc, "http-withcert") @@ -98,6 +101,7 @@ func TestCreateListener_HTTPRejectsCert(t *testing.T) { } func TestCreateListener_UnknownSslPolicy(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbArn := createLBArn(t, svc, "https-badpolicy") @@ -114,6 +118,7 @@ func TestCreateListener_UnknownSslPolicy(t *testing.T) { } func TestModifyListener_SwitchToHTTPSRequiresCert(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbArn := createLBArn(t, svc, "switch-lb") lst, err := svc.CreateListener(context.Background(), &elbv2.CreateListenerInput{ @@ -145,6 +150,7 @@ func TestModifyListener_SwitchToHTTPSRequiresCert(t *testing.T) { } func TestModifyListener_SwitchAwayClearsCerts(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createHTTPSListener(t, svc) @@ -158,6 +164,7 @@ func TestModifyListener_SwitchAwayClearsCerts(t *testing.T) { } func TestListenerCertificates_AddRemoveDescribe(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createHTTPSListener(t, svc) @@ -208,6 +215,7 @@ func TestListenerCertificates_AddRemoveDescribe(t *testing.T) { } func TestAddListenerCertificates_HTTPRejected(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbArn := createLBArn(t, svc, "http-addcert") lst, err := svc.CreateListener(context.Background(), &elbv2.CreateListenerInput{ @@ -227,6 +235,7 @@ func TestAddListenerCertificates_HTTPRejected(t *testing.T) { } func TestListenerCertificates_ValidationAndNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) arn := createHTTPSListener(t, svc) const otherAccount = "999999999999" @@ -285,6 +294,7 @@ func TestListenerCertificates_ValidationAndNotFound(t *testing.T) { } func TestDescribeSSLPolicies_EmptyName(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.DescribeSSLPolicies(context.Background(), &elbv2.DescribeSSLPoliciesInput{ Names: []*string{aws.String("")}, @@ -293,6 +303,7 @@ func TestDescribeSSLPolicies_EmptyName(t *testing.T) { } func TestDescribeSSLPolicies(t *testing.T) { + t.Parallel() svc := setupTestService(t) // No filter → full catalog. @@ -331,6 +342,7 @@ func attachedCertListener(t *testing.T, svc *ELBv2ServiceImpl, id, name string) } func TestAddListenerCertificates_RerendersConfig(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbID, listenerArn := attachedCertListener(t, svc, "lb-rerender1", "rerender-lb1") @@ -358,6 +370,7 @@ func TestAddListenerCertificates_RerendersConfig(t *testing.T) { } func TestRemoveListenerCertificates_RerendersConfig(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbID, listenerArn := attachedCertListener(t, svc, "lb-rerender2", "rerender-lb2") @@ -392,6 +405,7 @@ func TestRemoveListenerCertificates_RerendersConfig(t *testing.T) { // move an existing deployment's PEM, and it must render first so a client that // sends no SNI still gets it. func TestListenerCerts_DefaultCertRendersFirstAndKeepsItsPath(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbID, listenerArn := attachedCertListener(t, svc, "lb-rerender3", "rerender-lb3") diff --git a/spinifex/handlers/elbv2/service_impl_nlb_sg_test.go b/spinifex/handlers/elbv2/service_impl_nlb_sg_test.go index 2047be507..17af6774f 100644 --- a/spinifex/handlers/elbv2/service_impl_nlb_sg_test.go +++ b/spinifex/handlers/elbv2/service_impl_nlb_sg_test.go @@ -128,6 +128,7 @@ func createTCPListener(t *testing.T, svc *ELBv2ServiceImpl, lbArn *string, port // dedicated internal SG (not the VPC default) attached to its ENI, recorded in // NLBManagedSGID, while DescribeLoadBalancers still reports no customer SGs. func TestCreateNLB_MintsManagedSGAttachedToENI(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, vpcID := firstSubnet(t, vpcSvc) @@ -152,6 +153,7 @@ func TestCreateNLB_MintsManagedSGAttachedToENI(t *testing.T) { // customer SGs over the managed SG, falls back to the managed SG without them, and // an ALB always uses its customer SGs. func TestLBENIGroups_Precedence(t *testing.T) { + t.Parallel() assert.Equal(t, []string{"sg-a"}, lbENIGroups(&LoadBalancerRecord{ Type: LoadBalancerTypeNetwork, SecurityGroups: []string{"sg-a"}, NLBManagedSGID: "sg-mgd", })) @@ -167,6 +169,7 @@ func TestLBENIGroups_Precedence(t *testing.T) { // with customer SGs joins those SGs on its ENI and skips the managed SG entirely; // the caller then owns the listener-port ingress rules. func TestCreateNLB_WithCustomerSGs_AttachesThemNoManagedSG(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, vpcID := firstSubnet(t, vpcSvc) @@ -200,6 +203,7 @@ func TestCreateNLB_WithCustomerSGs_AttachesThemNoManagedSG(t *testing.T) { // TestCreateALB_NoManagedSG verifies the managed-SG behavior is NLB-only: an ALB // keeps the existing customer-SG / default-SG semantics. func TestCreateALB_NoManagedSG(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -217,6 +221,7 @@ func TestCreateALB_NoManagedSG(t *testing.T) { // TestCreateListener_Internal_OpensPortFromVPCCIDR verifies an internal NLB's // listener port is authorized on the managed SG from the VPC CIDR. func TestCreateListener_Internal_OpensPortFromVPCCIDR(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -234,6 +239,7 @@ func TestCreateListener_Internal_OpensPortFromVPCCIDR(t *testing.T) { // TestCreateListener_InternetFacing_OpensPortFromAnywhere verifies an // internet-facing NLB's listener port is authorized from 0.0.0.0/0. func TestCreateListener_InternetFacing_OpensPortFromAnywhere(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -250,6 +256,7 @@ func TestCreateListener_InternetFacing_OpensPortFromAnywhere(t *testing.T) { // TestCreateListener_TCPUDP_OpensBothProtocols verifies a TCP_UDP listener opens // both tcp and udp on the listener port. func TestCreateListener_TCPUDP_OpensBothProtocols(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -279,6 +286,7 @@ func TestCreateListener_TCPUDP_OpensBothProtocols(t *testing.T) { // swaps the scheme-default rule for the supplied CIDRs across existing listeners // and is idempotent on re-invocation. func TestSetLoadBalancerIngressCIDRs_RewritesListenerRules(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -310,6 +318,7 @@ func TestSetLoadBalancerIngressCIDRs_RewritesListenerRules(t *testing.T) { } func TestSetLoadBalancerIngressCIDRs_RejectsBadInput(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -330,6 +339,7 @@ func TestSetLoadBalancerIngressCIDRs_RejectsBadInput(t *testing.T) { // TestDeleteListener_RevokesPort verifies removing a listener closes its port on // the managed SG. func TestDeleteListener_RevokesPort(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -354,6 +364,7 @@ func TestDeleteListener_RevokesPort(t *testing.T) { // TestDeleteNLB_DeletesManagedSG verifies the managed SG is removed on LB // teardown. func TestDeleteNLB_DeletesManagedSG(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -380,6 +391,7 @@ func TestDeleteNLB_DeletesManagedSG(t *testing.T) { // record, no managed ENI, no managed SG, and the name claim released. The // leaked managed SG is what pinned the EKS control-plane VPC against DeleteVpc. func TestCreateLoadBalancerSync_LaunchFailure_RollsBackEverything(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -407,6 +419,7 @@ func TestCreateLoadBalancerSync_LaunchFailure_RollsBackEverything(t *testing.T) // code, while an unrecognised cause stays ServerInternal rather than inventing a // client error. func TestCreateLoadBalancerSync_LaunchFailure_SurfacesCause(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -428,6 +441,7 @@ func TestCreateLoadBalancerSync_LaunchFailure_SurfacesCause(t *testing.T) { // launching, so its failed record and managed SG are kept — the caller can // reclaim them via DeleteLoadBalancer. Only the sync path rolls back fully. func TestCreateLoadBalancer_AsyncLaunchFailure_KeepsFailedRecord(t *testing.T) { + t.Parallel() svc, vpcSvc, mock := setupSubnetTestService(t) subnetID, _ := firstSubnet(t, vpcSvc) mock.launchErr = errors.New("allocate public IP: " + awserrors.ErrorInsufficientAddressCapacity) diff --git a/spinifex/handlers/elbv2/service_impl_ownership_test.go b/spinifex/handlers/elbv2/service_impl_ownership_test.go index e32a9c60f..33fae65a3 100644 --- a/spinifex/handlers/elbv2/service_impl_ownership_test.go +++ b/spinifex/handlers/elbv2/service_impl_ownership_test.go @@ -42,6 +42,7 @@ func storedTargets(t *testing.T, svc *ELBv2ServiceImpl, tgArn string) []Target { } func TestRegisterTargets_CrossAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgArn := ownedTargetGroup(t, svc, "reg-xacct-tg") @@ -65,6 +66,7 @@ func TestRegisterTargets_CrossAccount(t *testing.T) { } func TestDeregisterTargets_CrossAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgArn := ownedTargetGroup(t, svc, "dereg-xacct-tg") @@ -92,6 +94,7 @@ func TestDeregisterTargets_CrossAccount(t *testing.T) { } func TestDescribeTargetHealth_CrossAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgArn := ownedTargetGroup(t, svc, "health-xacct-tg") @@ -115,6 +118,7 @@ func TestDescribeTargetHealth_CrossAccount(t *testing.T) { } func TestCreateListener_CrossAccountLoadBalancer(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbArn := ownedLoadBalancer(t, svc, "lst-xacct-lb", testAccountID) @@ -152,6 +156,7 @@ func TestCreateListener_CrossAccountLoadBalancer(t *testing.T) { } func TestCreateListener_CrossAccountTargetGroup(t *testing.T) { + t.Parallel() svc := setupTestService(t) victimTGArn := ownedTargetGroup(t, svc, "lst-xacct-victim-tg") attackerLBArn := ownedLoadBalancer(t, svc, "lst-xacct-att-lb", attackerAccountID) @@ -173,6 +178,7 @@ func TestCreateListener_CrossAccountTargetGroup(t *testing.T) { } func TestModifyListener_CrossAccountTargetGroup(t *testing.T) { + t.Parallel() svc := setupTestService(t) victimTGArn := ownedTargetGroup(t, svc, "mod-xacct-victim-tg") attackerLBArn := ownedLoadBalancer(t, svc, "mod-xacct-att-lb", attackerAccountID) @@ -207,6 +213,7 @@ func TestModifyListener_CrossAccountTargetGroup(t *testing.T) { } func TestCreateRule_CrossAccountTargetGroup(t *testing.T) { + t.Parallel() svc := setupTestService(t) victimTGArn := ownedTargetGroup(t, svc, "rule-xacct-victim-tg") attackerLBArn := ownedLoadBalancer(t, svc, "rule-xacct-att-lb", attackerAccountID) diff --git a/spinifex/handlers/elbv2/service_impl_protocolversion_test.go b/spinifex/handlers/elbv2/service_impl_protocolversion_test.go index c888227ca..ccad71807 100644 --- a/spinifex/handlers/elbv2/service_impl_protocolversion_test.go +++ b/spinifex/handlers/elbv2/service_impl_protocolversion_test.go @@ -15,6 +15,7 @@ import ( // controller always sends ProtocolVersion and recreates the TG (DuplicateTargetGroupName // loop) if Describe reads it back empty. func TestCreateTargetGroup_ProtocolVersionDefaultsAndRoundTrips(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -38,6 +39,7 @@ func TestCreateTargetGroup_ProtocolVersionDefaultsAndRoundTrips(t *testing.T) { // An explicit ProtocolVersion is preserved, not overwritten by the default. func TestCreateTargetGroup_ProtocolVersionExplicitPreserved(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -53,6 +55,7 @@ func TestCreateTargetGroup_ProtocolVersionExplicitPreserved(t *testing.T) { // An unknown ProtocolVersion is rejected. func TestCreateTargetGroup_ProtocolVersionInvalidRejected(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -66,6 +69,7 @@ func TestCreateTargetGroup_ProtocolVersionInvalidRejected(t *testing.T) { // NLB (TCP/UDP/TLS) target groups have no ProtocolVersion; AWS omits it and so // must Spinifex, otherwise the controller sees spurious drift on NLB TGs. func TestCreateTargetGroup_ProtocolVersionOmittedForNLB(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ diff --git a/spinifex/handlers/elbv2/service_impl_rollback_test.go b/spinifex/handlers/elbv2/service_impl_rollback_test.go index 352aa78fe..be7ce6717 100644 --- a/spinifex/handlers/elbv2/service_impl_rollback_test.go +++ b/spinifex/handlers/elbv2/service_impl_rollback_test.go @@ -30,6 +30,7 @@ func managedENIIDs(t *testing.T, vpcSvc *handlers_ec2_vpc.VPCServiceImpl) []stri // PutLoadBalancer-failure path runs leaves no orphan: ENIs deleted, managed SG // deleted, name claim released (so the name is immediately reclaimable). func TestRollbackLBInfra_RemovesAllInfra(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -69,6 +70,7 @@ func TestRollbackLBInfra_RemovesAllInfra(t *testing.T) { // updateStoredConfig-failure path: the listener port was already authorized, so // rollback must revoke it AND remove the persisted listener record. func TestRollbackListener_RevokesPortAndDeletesRecord(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) @@ -100,6 +102,7 @@ func TestRollbackListener_RevokesPortAndDeletesRecord(t *testing.T) { // the port was never successfully opened, so rollback deletes the listener // record but must not touch SG authorizations (authorizedCIDRs is nil). func TestRollbackListener_NilCIDRsSkipsRevoke(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnetID, _ := firstSubnet(t, vpcSvc) diff --git a/spinifex/handlers/elbv2/service_impl_rules_extra_test.go b/spinifex/handlers/elbv2/service_impl_rules_extra_test.go index a51d83e49..d9eb23514 100644 --- a/spinifex/handlers/elbv2/service_impl_rules_extra_test.go +++ b/spinifex/handlers/elbv2/service_impl_rules_extra_test.go @@ -11,6 +11,7 @@ import ( ) func TestCreateRule_InputValidation(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-val") cases := []struct { @@ -33,6 +34,7 @@ func TestCreateRule_InputValidation(t *testing.T) { } func TestCreateRule_WrongAccount(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-acct") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ ListenerArn: aws.String(env.listenerArn), @@ -45,6 +47,7 @@ func TestCreateRule_WrongAccount(t *testing.T) { } func TestModifyRule_InputValidation(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "mod-val") _, err := env.svc.ModifyRule(context.Background(), nil, testAccountID) require.Error(t, err) @@ -60,6 +63,7 @@ func TestModifyRule_InputValidation(t *testing.T) { } func TestModifyRule_RewriteActions(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "mod-act") cr, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ ListenerArn: aws.String(env.listenerArn), @@ -78,6 +82,7 @@ func TestModifyRule_RewriteActions(t *testing.T) { } func TestDeleteRule_InputValidation(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "del-val") _, err := env.svc.DeleteRule(context.Background(), nil, testAccountID) require.Error(t, err) @@ -94,6 +99,7 @@ func TestDeleteRule_InputValidation(t *testing.T) { } func TestDescribeRules_InputValidation(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "desc-val") _, err := env.svc.DescribeRules(context.Background(), nil, testAccountID) require.Error(t, err) @@ -105,6 +111,7 @@ func TestDescribeRules_InputValidation(t *testing.T) { } func TestDescribeRules_ByRuleArns(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "desc-arns") cr, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ ListenerArn: aws.String(env.listenerArn), @@ -129,6 +136,7 @@ func TestDescribeRules_ByRuleArns(t *testing.T) { } func TestSetRulePriorities_InputValidation(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "spri-val") _, err := env.svc.SetRulePriorities(context.Background(), nil, testAccountID) require.Error(t, err) @@ -146,6 +154,7 @@ func TestSetRulePriorities_InputValidation(t *testing.T) { } func TestSetRulePriorities_InvalidPriority(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "spri-bad") cr, _ := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ ListenerArn: aws.String(env.listenerArn), @@ -172,6 +181,7 @@ func TestSetRulePriorities_InvalidPriority(t *testing.T) { } func TestValidateConditions_TooMany(t *testing.T) { + t.Parallel() in := make([]*elbv2.RuleCondition, MaxConditionsPerRule+1) for i := range in { in[i] = &elbv2.RuleCondition{Field: aws.String("path-pattern"), Values: aws.StringSlice([]string{"/a"})} @@ -182,6 +192,7 @@ func TestValidateConditions_TooMany(t *testing.T) { } func TestValidateConditions_Empty(t *testing.T) { + t.Parallel() _, err := validateAndConvertConditions(nil) require.Error(t, err) assert.Contains(t, err.Error(), "MissingParameter") @@ -192,6 +203,7 @@ func TestValidateConditions_Empty(t *testing.T) { } func TestValidateConditions_InvalidField(t *testing.T) { + t.Parallel() _, err := validateAndConvertConditions([]*elbv2.RuleCondition{ {Field: aws.String("unknown-field"), Values: aws.StringSlice([]string{"x"})}, }) @@ -200,6 +212,7 @@ func TestValidateConditions_InvalidField(t *testing.T) { } func TestValidateConditions_HTTPHeader(t *testing.T) { + t.Parallel() // Missing HttpHeaderConfig. _, err := validateAndConvertConditions([]*elbv2.RuleCondition{ {Field: aws.String("http-header")}, @@ -228,6 +241,7 @@ func TestValidateConditions_HTTPHeader(t *testing.T) { } func TestValidateConditions_Method(t *testing.T) { + t.Parallel() _, err := validateAndConvertConditions([]*elbv2.RuleCondition{ {Field: aws.String("http-request-method")}, }) @@ -246,6 +260,7 @@ func TestValidateConditions_Method(t *testing.T) { } func TestValidateConditions_QueryString(t *testing.T) { + t.Parallel() _, err := validateAndConvertConditions([]*elbv2.RuleCondition{ {Field: aws.String("query-string")}, }) @@ -270,6 +285,7 @@ func TestValidateConditions_QueryString(t *testing.T) { } func TestValidateConditions_SourceIP(t *testing.T) { + t.Parallel() _, err := validateAndConvertConditions([]*elbv2.RuleCondition{ {Field: aws.String("source-ip")}, }) @@ -288,6 +304,7 @@ func TestValidateConditions_SourceIP(t *testing.T) { } func TestWildcardMatch(t *testing.T) { + t.Parallel() cases := []struct { in string wantFlag string @@ -310,6 +327,7 @@ func TestWildcardMatch(t *testing.T) { } func TestValidateRenderSafe(t *testing.T) { + t.Parallel() require.NoError(t, validateRenderSafe("/api/v1")) for _, bad := range []string{"", "a b", "a\tb", "a\nb", "a\rb", "a#b", `a"b`} { err := validateRenderSafe(bad) @@ -321,6 +339,7 @@ func TestValidateRenderSafe(t *testing.T) { // ACL emission path in one render. Each rule uses a distinct backend so the // match expressions can be located in the generated config. func TestHAProxyRender_AllConditionFields(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb1", LoadBalancerArn: "arn:lb1", Type: LoadBalancerTypeApplication} listener := &ListenerRecord{ ListenerArn: "arn:lst1", ListenerID: "lst1", LoadBalancerArn: "arn:lb1", @@ -374,11 +393,13 @@ func TestHAProxyRender_AllConditionFields(t *testing.T) { } func TestHAProxyRender_UnsupportedField(t *testing.T) { + t.Parallel() _, err := buildHAProxyACLExprs(RuleCondition{Field: "nonsense", Values: []string{"x"}}) require.Error(t, err) } func TestBuildHAProxyRule_RoutesToBackend(t *testing.T) { + t.Parallel() rule, err := buildHAProxyRule(&RuleRecord{ RuleID: "r1", Conditions: []RuleCondition{{Field: RuleFieldPathPattern, Values: []string{"/a"}}}, @@ -388,6 +409,7 @@ func TestBuildHAProxyRule_RoutesToBackend(t *testing.T) { } func TestRegisterRuleBackend_RejectsUnknownAction(t *testing.T) { + t.Parallel() noopBackend := func(string) {} noopFixed := func(string, *FixedResponseAction) {} noopRedirect := func(string, *HAProxyRedirect) {} @@ -402,6 +424,7 @@ func TestRegisterRuleBackend_RejectsUnknownAction(t *testing.T) { // without rule-action enumeration, the health checker never resolves rule-only TGs // and they time out at 0/1 healthy (TargetGroupsForLB walked only DefaultActions). func TestTargetGroupsForLB_IncludesRuleTGs(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "tgs-rule") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ ListenerArn: aws.String(env.listenerArn), diff --git a/spinifex/handlers/elbv2/service_impl_rules_test.go b/spinifex/handlers/elbv2/service_impl_rules_test.go index 5c49d9069..d2b952f18 100644 --- a/spinifex/handlers/elbv2/service_impl_rules_test.go +++ b/spinifex/handlers/elbv2/service_impl_rules_test.go @@ -53,6 +53,7 @@ func newRuleTestEnv(t *testing.T, namePrefix string) ruleTestEnv { } func TestCreateRule_PathPattern(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-path") out, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -76,6 +77,7 @@ func TestCreateRule_PathPattern(t *testing.T) { // Controller emits) was rejected with MissingParameter because only the flat // TargetGroupArn field was read. func TestCreateRule_ForwardConfig(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-fwdcfg") out, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -102,6 +104,7 @@ func TestCreateRule_ForwardConfig(t *testing.T) { // DeleteLoadBalancer called store.DeleteListener directly, bypassing rule cascade, // leaving a rule's target group pinned as ResourceInUse permanently. func TestDeleteLoadBalancer_CascadesRuleDeletion(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "del-cascade") // Rule on the listener forwards to the alt TG. @@ -138,6 +141,7 @@ func TestDeleteLoadBalancer_CascadesRuleDeletion(t *testing.T) { } func TestCreateRule_PriorityInUse(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-pri") mkInput := func() *elbv2.CreateRuleInput { @@ -160,6 +164,7 @@ func TestCreateRule_PriorityInUse(t *testing.T) { } func TestCreateRule_InvalidPriority(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-inv") for _, p := range []int64{0, 50001} { @@ -175,6 +180,7 @@ func TestCreateRule_InvalidPriority(t *testing.T) { } func TestCreateRule_RedirectAction(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-redir") out, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -198,6 +204,7 @@ func TestCreateRule_RedirectAction(t *testing.T) { } func TestCreateRule_FixedResponseAction(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-fixed") out, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -220,6 +227,7 @@ func TestCreateRule_FixedResponseAction(t *testing.T) { } func TestCreateRule_RejectsBadRedirectStatus(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-badredir") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -236,6 +244,7 @@ func TestCreateRule_RejectsBadRedirectStatus(t *testing.T) { } func TestCreateRule_RejectsUnknownAction(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-rej") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -249,6 +258,7 @@ func TestCreateRule_RejectsUnknownAction(t *testing.T) { } func TestCreateRule_HostHeader(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-host") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -264,6 +274,7 @@ func TestCreateRule_HostHeader(t *testing.T) { } func TestCreateRule_HTTPHeader(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-hdr") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -282,6 +293,7 @@ func TestCreateRule_HTTPHeader(t *testing.T) { } func TestCreateRule_SourceIP(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-src") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -309,6 +321,7 @@ func TestCreateRule_SourceIP(t *testing.T) { } func TestCreateRule_RejectsNewlineInjection(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cr-inj") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -326,6 +339,7 @@ func TestCreateRule_RejectsNewlineInjection(t *testing.T) { } func TestModifyRule(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "mod") out, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -348,6 +362,7 @@ func TestModifyRule(t *testing.T) { } func TestDeleteRule(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "del") out, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -369,6 +384,7 @@ func TestDeleteRule(t *testing.T) { } func TestDeleteListener_CascadesRules(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "cas") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -388,6 +404,7 @@ func TestDeleteListener_CascadesRules(t *testing.T) { } func TestDeleteTargetGroup_BlockedByRule(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "tg-block") _, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -404,6 +421,7 @@ func TestDeleteTargetGroup_BlockedByRule(t *testing.T) { } func TestDescribeRules_ByListener_SortedAndDefaultLast(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "desc") for _, p := range []int64{30, 10, 20} { @@ -430,6 +448,7 @@ func TestDescribeRules_ByListener_SortedAndDefaultLast(t *testing.T) { // DescribeTags with an empty resource and got MissingParameter, aborting the // Ingress reconcile right after listener creation. func TestDefaultRule_HasArnAndIsTaggable(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "defrule") rules, err := env.svc.DescribeRules(context.Background(), &elbv2.DescribeRulesInput{ListenerArn: aws.String(env.listenerArn)}, testAccountID) @@ -464,6 +483,7 @@ func TestDefaultRule_HasArnAndIsTaggable(t *testing.T) { } func TestSetRulePriorities_Reorders(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "spri") r1, err := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -500,6 +520,7 @@ func TestSetRulePriorities_Reorders(t *testing.T) { } func TestSetRulePriorities_DuplicateRejected(t *testing.T) { + t.Parallel() env := newRuleTestEnv(t, "spri-dup") r1, _ := env.svc.CreateRule(context.Background(), &elbv2.CreateRuleInput{ @@ -526,6 +547,7 @@ func TestSetRulePriorities_DuplicateRejected(t *testing.T) { } func TestBuildRuleArn(t *testing.T) { + t.Parallel() listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:123456789012:listener/app/my-alb/abc/lst123" got, err := buildRuleArn(listenerArn, "rule999") require.NoError(t, err) @@ -534,6 +556,7 @@ func TestBuildRuleArn(t *testing.T) { } func TestHAProxyRender_PathPatternRule(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{ LoadBalancerID: "lb1", LoadBalancerArn: "arn:lb1", @@ -568,6 +591,7 @@ func TestHAProxyRender_PathPatternRule(t *testing.T) { } func TestHAProxyRender_HostHeaderWildcardSuffix(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb1", LoadBalancerArn: "arn:lb1", Type: LoadBalancerTypeApplication} listener := &ListenerRecord{ ListenerArn: "arn:lst1", ListenerID: "lst1", LoadBalancerArn: "arn:lb1", @@ -590,6 +614,7 @@ func TestHAProxyRender_HostHeaderWildcardSuffix(t *testing.T) { } func TestHAProxyRender_RulesOrderedByPriority(t *testing.T) { + t.Parallel() lb := &LoadBalancerRecord{LoadBalancerID: "lb1", LoadBalancerArn: "arn:lb1", Type: LoadBalancerTypeApplication} listener := &ListenerRecord{ ListenerArn: "arn:lst1", ListenerID: "lst1", LoadBalancerArn: "arn:lb1", diff --git a/spinifex/handlers/elbv2/service_impl_tags_test.go b/spinifex/handlers/elbv2/service_impl_tags_test.go index 19a43fed0..f7c79dd76 100644 --- a/spinifex/handlers/elbv2/service_impl_tags_test.go +++ b/spinifex/handlers/elbv2/service_impl_tags_test.go @@ -26,6 +26,7 @@ func tagsFor(t *testing.T, svc *ELBv2ServiceImpl, arn string) map[string]string } func TestAddTags_LoadBalancer(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("addtags-lb"), @@ -47,6 +48,7 @@ func TestAddTags_LoadBalancer(t *testing.T) { } func TestAddTags_Listener(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-lst-lb")}, testAccountID) tgOut, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("addtags-lst-tg")}, testAccountID) @@ -71,6 +73,7 @@ func TestAddTags_Listener(t *testing.T) { } func TestAddTags_CreateTimeTagsPreserved(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-tg-lb")}, testAccountID) tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -91,6 +94,7 @@ func TestAddTags_CreateTimeTagsPreserved(t *testing.T) { } func TestAddTags_NotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.AddTags(context.Background(), &elbv2.AddTagsInput{ ResourceArns: []*string{aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/missing/lb-deadbeef")}, @@ -101,6 +105,7 @@ func TestAddTags_NotFound(t *testing.T) { } func TestAddTags_CrossAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-xacct")}, testAccountID) arn := *lbOut.LoadBalancers[0].LoadBalancerArn @@ -117,6 +122,7 @@ func TestAddTags_CrossAccount(t *testing.T) { } func TestAddTags_MissingParams(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-mp")}, testAccountID) arn := lbOut.LoadBalancers[0].LoadBalancerArn @@ -131,6 +137,7 @@ func TestAddTags_MissingParams(t *testing.T) { } func TestAddTags_EmptyKeyRejected(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-ek")}, testAccountID) arn := lbOut.LoadBalancers[0].LoadBalancerArn @@ -144,6 +151,7 @@ func TestAddTags_EmptyKeyRejected(t *testing.T) { } func TestRemoveTags_LoadBalancer(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("rmtags-lb"), @@ -164,6 +172,7 @@ func TestRemoveTags_LoadBalancer(t *testing.T) { } func TestRemoveTags_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("rmtags-idem"), @@ -181,6 +190,7 @@ func TestRemoveTags_Idempotent(t *testing.T) { } func TestRemoveTags_NotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.RemoveTags(context.Background(), &elbv2.RemoveTagsInput{ ResourceArns: []*string{aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/missing/tg-deadbeef")}, @@ -191,6 +201,7 @@ func TestRemoveTags_NotFound(t *testing.T) { } func TestRemoveTags_MissingParams(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("rmtags-mp")}, testAccountID) arn := lbOut.LoadBalancers[0].LoadBalancerArn diff --git a/spinifex/handlers/elbv2/service_impl_test.go b/spinifex/handlers/elbv2/service_impl_test.go index 6310c1768..d638f27cb 100644 --- a/spinifex/handlers/elbv2/service_impl_test.go +++ b/spinifex/handlers/elbv2/service_impl_test.go @@ -37,6 +37,7 @@ func setupTestService(t *testing.T) *ELBv2ServiceImpl { // --- Load Balancer tests --- func TestCreateLoadBalancer(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -57,6 +58,7 @@ func TestCreateLoadBalancer(t *testing.T) { } func TestCreateLoadBalancer_InternalScheme(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -69,6 +71,7 @@ func TestCreateLoadBalancer_InternalScheme(t *testing.T) { } func TestCreateLoadBalancer_InvalidScheme(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -81,6 +84,7 @@ func TestCreateLoadBalancer_InvalidScheme(t *testing.T) { } func TestCreateLoadBalancer_DuplicateName(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -96,6 +100,7 @@ func TestCreateLoadBalancer_DuplicateName(t *testing.T) { } func TestCreateLoadBalancer_MissingName(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{}, testAccountID) @@ -103,6 +108,7 @@ func TestCreateLoadBalancer_MissingName(t *testing.T) { } func TestCreateLoadBalancer_WithTags(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -123,6 +129,7 @@ func TestCreateLoadBalancer_WithTags(t *testing.T) { } func TestCreateLoadBalancer_NetworkType(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -139,6 +146,7 @@ func TestCreateLoadBalancer_NetworkType(t *testing.T) { } func TestCreateLoadBalancer_NetworkType_AcceptsSecurityGroups(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -155,6 +163,7 @@ func TestCreateLoadBalancer_NetworkType_AcceptsSecurityGroups(t *testing.T) { } func TestCreateLoadBalancer_NetworkType_RejectsTooManySecurityGroups(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -171,6 +180,7 @@ func TestCreateLoadBalancer_NetworkType_RejectsTooManySecurityGroups(t *testing. } func TestCreateLoadBalancer_NLBCrossZoneAttribute(t *testing.T) { + t.Parallel() svc := setupTestService(t) // NLB: no stored attributes, Describe should return default cross-zone=false. @@ -195,6 +205,7 @@ func TestCreateLoadBalancer_NLBCrossZoneAttribute(t *testing.T) { } func TestCreateLoadBalancer_ALBCrossZoneAttribute(t *testing.T) { + t.Parallel() svc := setupTestService(t) // ALB: no stored attributes either, Describe should return default cross-zone=true. @@ -218,6 +229,7 @@ func TestCreateLoadBalancer_ALBCrossZoneAttribute(t *testing.T) { } func TestCreateLoadBalancer_InvalidType(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -230,6 +242,7 @@ func TestCreateLoadBalancer_InvalidType(t *testing.T) { } func TestCreateLoadBalancer_ALB_AllowsSecurityGroups(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -243,6 +256,7 @@ func TestCreateLoadBalancer_ALB_AllowsSecurityGroups(t *testing.T) { } func TestDeleteLoadBalancer(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -262,6 +276,7 @@ func TestDeleteLoadBalancer(t *testing.T) { } func TestDeleteLoadBalancer_IdempotentOnAbsent(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.DeleteLoadBalancer(context.Background(), &elbv2.DeleteLoadBalancerInput{ @@ -274,6 +289,7 @@ func TestDeleteLoadBalancer_IdempotentOnAbsent(t *testing.T) { } func TestDeleteLoadBalancer_CleansUpListeners(t *testing.T) { + t.Parallel() svc := setupTestService(t) // Create LB, TG, and listener @@ -301,6 +317,7 @@ func TestDeleteLoadBalancer_CleansUpListeners(t *testing.T) { } func TestDescribeLoadBalancers_FilterByName(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("alb-one")}, testAccountID) @@ -317,6 +334,7 @@ func TestDescribeLoadBalancers_FilterByName(t *testing.T) { } func TestDescribeLoadBalancers_AccountIsolation(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("acct-alb")}, testAccountID) @@ -330,6 +348,7 @@ func TestDescribeLoadBalancers_AccountIsolation(t *testing.T) { // --- Target Group tests --- func TestCreateTargetGroup(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -351,6 +370,7 @@ func TestCreateTargetGroup(t *testing.T) { } func TestCreateTargetGroup_CustomHealthCheck(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -372,6 +392,7 @@ func TestCreateTargetGroup_CustomHealthCheck(t *testing.T) { } func TestCreateTargetGroup_TCPProtocol(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -397,6 +418,7 @@ func TestCreateTargetGroup_TCPProtocol(t *testing.T) { } func TestCreateTargetGroup_NLBProtocols(t *testing.T) { + t.Parallel() for _, proto := range []string{"TCP", "UDP", "TLS", "TCP_UDP"} { t.Run(proto, func(t *testing.T) { svc := setupTestService(t) @@ -417,6 +439,7 @@ func TestCreateTargetGroup_NLBProtocols(t *testing.T) { } func TestCreateTargetGroup_InvalidProtocol(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -429,6 +452,7 @@ func TestCreateTargetGroup_InvalidProtocol(t *testing.T) { } func TestCreateTargetGroup_TCPWithCustomHealthCheck(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -452,6 +476,7 @@ func TestCreateTargetGroup_TCPWithCustomHealthCheck(t *testing.T) { } func TestCreateTargetGroup_RejectsHealthCheckPathInjection(t *testing.T) { + t.Parallel() svc := setupTestService(t) cases := map[string]string{ @@ -485,6 +510,7 @@ func TestCreateTargetGroup_RejectsHealthCheckPathInjection(t *testing.T) { } func TestCreateTargetGroup_RejectsMatcherInjection(t *testing.T) { + t.Parallel() svc := setupTestService(t) cases := map[string]string{ @@ -512,6 +538,7 @@ func TestCreateTargetGroup_RejectsMatcherInjection(t *testing.T) { } func TestCreateTargetGroup_AcceptsValidHealthCheckInputs(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -525,6 +552,7 @@ func TestCreateTargetGroup_AcceptsValidHealthCheckInputs(t *testing.T) { } func TestCreateTargetGroup_AcceptsHealthCheckBoundaryLengths(t *testing.T) { + t.Parallel() svc := setupTestService(t) maxPath := "/" + strings.Repeat("a", maxHealthCheckPathLen-1) @@ -541,6 +569,7 @@ func TestCreateTargetGroup_AcceptsHealthCheckBoundaryLengths(t *testing.T) { } func TestCreateTargetGroup_DuplicateName(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -558,6 +587,7 @@ func TestCreateTargetGroup_DuplicateName(t *testing.T) { } func TestModifyTargetGroup(t *testing.T) { + t.Parallel() svc := setupTestService(t) created, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -595,6 +625,7 @@ func TestModifyTargetGroup(t *testing.T) { } func TestModifyTargetGroup_NotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.ModifyTargetGroup(context.Background(), &elbv2.ModifyTargetGroupInput{ @@ -605,6 +636,7 @@ func TestModifyTargetGroup_NotFound(t *testing.T) { } func TestModifyTargetGroup_MissingArn(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.ModifyTargetGroup(context.Background(), &elbv2.ModifyTargetGroupInput{}, testAccountID) @@ -613,6 +645,7 @@ func TestModifyTargetGroup_MissingArn(t *testing.T) { } func TestModifyTargetGroup_AllHealthCheckFields(t *testing.T) { + t.Parallel() svc := setupTestService(t) created, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -650,6 +683,7 @@ func TestModifyTargetGroup_AllHealthCheckFields(t *testing.T) { } func TestModifyTargetGroup_InvalidPath(t *testing.T) { + t.Parallel() svc := setupTestService(t) created, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -665,6 +699,7 @@ func TestModifyTargetGroup_InvalidPath(t *testing.T) { } func TestModifyTargetGroup_InvalidMatcher(t *testing.T) { + t.Parallel() svc := setupTestService(t) created, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -680,6 +715,7 @@ func TestModifyTargetGroup_InvalidMatcher(t *testing.T) { } func TestModifyTargetGroup_WrongAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) created, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -696,6 +732,7 @@ func TestModifyTargetGroup_WrongAccount(t *testing.T) { } func TestDeleteTargetGroup(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("del-tg")}, testAccountID) @@ -708,6 +745,7 @@ func TestDeleteTargetGroup(t *testing.T) { } func TestDeleteTargetGroup_InUse(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("inuse-tg")}, testAccountID) @@ -730,6 +768,7 @@ func TestDeleteTargetGroup_InUse(t *testing.T) { } func TestDeleteTargetGroup_IdempotentOnAbsent(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.DeleteTargetGroup(context.Background(), &elbv2.DeleteTargetGroupInput{ @@ -741,6 +780,7 @@ func TestDeleteTargetGroup_IdempotentOnAbsent(t *testing.T) { } func TestDescribeTargetGroups_FilterByLBArn(t *testing.T) { + t.Parallel() svc := setupTestService(t) tg1, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("tg-linked")}, testAccountID) @@ -763,6 +803,7 @@ func TestDescribeTargetGroups_FilterByLBArn(t *testing.T) { // --- Target registration tests --- func TestRegisterTargets(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -799,6 +840,7 @@ func TestRegisterTargets(t *testing.T) { } func TestRegisterTargets_IPType(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -839,6 +881,7 @@ func TestRegisterTargets_IPType(t *testing.T) { } func TestRegisterTargets_IPType_RejectsNonIP(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ Name: aws.String("ip-tg-bad"), @@ -854,6 +897,7 @@ func TestRegisterTargets_IPType_RejectsNonIP(t *testing.T) { } func TestRegisterTargets_InstanceType_RejectsIP(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ Name: aws.String("inst-tg-badid"), @@ -868,6 +912,7 @@ func TestRegisterTargets_InstanceType_RejectsIP(t *testing.T) { } func TestCreateTargetGroup_RejectsUnsupportedTargetType(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ Name: aws.String("lambda-tg"), @@ -877,6 +922,7 @@ func TestCreateTargetGroup_RejectsUnsupportedTargetType(t *testing.T) { } func TestCreateTargetGroup_DefaultsToInstanceType(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ Name: aws.String("default-tt"), @@ -886,6 +932,7 @@ func TestCreateTargetGroup_DefaultsToInstanceType(t *testing.T) { } func TestRegisterTargets_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("idem-tg")}, testAccountID) @@ -903,6 +950,7 @@ func TestRegisterTargets_Idempotent(t *testing.T) { } func TestDeregisterTargets(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("dereg-tg"), Port: aws.Int64(80)}, testAccountID) @@ -928,6 +976,7 @@ func TestDeregisterTargets(t *testing.T) { } func TestDescribeTargetHealth_FilterByTarget(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("filter-tg"), Port: aws.Int64(80)}, testAccountID) @@ -951,6 +1000,7 @@ func TestDescribeTargetHealth_FilterByTarget(t *testing.T) { } func TestDescribeTargetHealth_TGNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.DescribeTargetHealth(context.Background(), &elbv2.DescribeTargetHealthInput{ @@ -963,6 +1013,7 @@ func TestDescribeTargetHealth_TGNotFound(t *testing.T) { // --- Listener tests --- func TestCreateListener(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("lst-lb")}, testAccountID) @@ -988,6 +1039,7 @@ func TestCreateListener(t *testing.T) { } func TestCreateListener_RedirectDefault(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("redir-lb")}, testAccountID) @@ -1016,6 +1068,7 @@ func TestCreateListener_RedirectDefault(t *testing.T) { } func TestCreateListener_RedirectFullFields(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("redirfull-lb")}, testAccountID) @@ -1056,6 +1109,7 @@ func TestCreateListener_RedirectFullFields(t *testing.T) { } func TestModifyListener_ToRedirect(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-redir-lb")}, testAccountID) @@ -1091,6 +1145,7 @@ func TestModifyListener_ToRedirect(t *testing.T) { } func TestCreateListener_RejectsBadRedirect(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("badredir-lb")}, testAccountID) @@ -1109,6 +1164,7 @@ func TestCreateListener_RejectsBadRedirect(t *testing.T) { } func TestCreateListener_DuplicatePort(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("dup-port-lb")}, testAccountID) @@ -1133,6 +1189,7 @@ func TestCreateListener_DuplicatePort(t *testing.T) { } func TestCreateListener_LBNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.CreateListener(context.Background(), &elbv2.CreateListenerInput{ @@ -1144,6 +1201,7 @@ func TestCreateListener_LBNotFound(t *testing.T) { } func TestDeleteListener(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("dellst-lb")}, testAccountID) @@ -1168,6 +1226,7 @@ func TestDeleteListener(t *testing.T) { } func TestDeleteListener_IdempotentOnAbsent(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.DeleteListener(context.Background(), &elbv2.DeleteListenerInput{ @@ -1179,6 +1238,7 @@ func TestDeleteListener_IdempotentOnAbsent(t *testing.T) { } func TestModifyListener_Port(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-lb")}, testAccountID) @@ -1210,6 +1270,7 @@ func TestModifyListener_Port(t *testing.T) { } func TestModifyListener_Protocol(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-proto-lb")}, testAccountID) @@ -1233,6 +1294,7 @@ func TestModifyListener_Protocol(t *testing.T) { } func TestModifyListener_DefaultActions(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-act-lb")}, testAccountID) @@ -1257,6 +1319,7 @@ func TestModifyListener_DefaultActions(t *testing.T) { } func TestModifyListener_DuplicatePort(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-dup-lb")}, testAccountID) @@ -1286,6 +1349,7 @@ func TestModifyListener_DuplicatePort(t *testing.T) { } func TestModifyListener_SamePortNoConflict(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-same-lb")}, testAccountID) @@ -1308,6 +1372,7 @@ func TestModifyListener_SamePortNoConflict(t *testing.T) { } func TestModifyListener_NotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.ModifyListener(context.Background(), &elbv2.ModifyListenerInput{ @@ -1319,6 +1384,7 @@ func TestModifyListener_NotFound(t *testing.T) { } func TestModifyListener_WrongAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-acct-lb")}, testAccountID) @@ -1337,6 +1403,7 @@ func TestModifyListener_WrongAccount(t *testing.T) { } func TestModifyListener_TargetGroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-tgnf-lb")}, testAccountID) @@ -1357,6 +1424,7 @@ func TestModifyListener_TargetGroupNotFound(t *testing.T) { } func TestModifyListener_NoOp(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-noop-lb")}, testAccountID) @@ -1378,6 +1446,7 @@ func TestModifyListener_NoOp(t *testing.T) { } func TestModifyListener_InvalidProtocolForLBType(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("mod-bad-proto-lb")}, testAccountID) @@ -1396,6 +1465,7 @@ func TestModifyListener_InvalidProtocolForLBType(t *testing.T) { } func TestModifyListener_NilInput(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.ModifyListener(context.Background(), nil, testAccountID) @@ -1404,6 +1474,7 @@ func TestModifyListener_NilInput(t *testing.T) { } func TestModifyListener_EmptyArn(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.ModifyListener(context.Background(), &elbv2.ModifyListenerInput{ @@ -1418,6 +1489,7 @@ func TestModifyListener_EmptyArn(t *testing.T) { } func TestModifyListener_NLB_AcceptsAllProtocols(t *testing.T) { + t.Parallel() cases := []struct { listenerProto string tgProto string @@ -1464,6 +1536,7 @@ func TestModifyListener_NLB_AcceptsAllProtocols(t *testing.T) { } func TestModifyListener_NLB_RejectsHTTP(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1491,6 +1564,7 @@ func TestModifyListener_NLB_RejectsHTTP(t *testing.T) { } func TestModifyListener_ProtocolOnlyChange_TGIncompatible(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1518,6 +1592,7 @@ func TestModifyListener_ProtocolOnlyChange_TGIncompatible(t *testing.T) { } func TestModifyListener_DefaultActions_IncompatibleProtocol(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1553,6 +1628,7 @@ func TestModifyListener_DefaultActions_IncompatibleProtocol(t *testing.T) { } func TestDescribeListeners_FilterByLBArn(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb1, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("dl-lb1")}, testAccountID) @@ -1575,6 +1651,7 @@ func TestDescribeListeners_FilterByLBArn(t *testing.T) { // LB-level isolation is tested separately; a regression dropping the listener-side // check would not be caught by the LB-level test. func TestDescribeListeners_AccountIsolation(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("iso-lb")}, testAccountID) @@ -1592,6 +1669,7 @@ func TestDescribeListeners_AccountIsolation(t *testing.T) { // --- NLB Listener tests --- func TestCreateListener_NLB_TCPProtocol(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1622,6 +1700,7 @@ func TestCreateListener_NLB_TCPProtocol(t *testing.T) { } func TestCreateListener_NLB_AllProtocols(t *testing.T) { + t.Parallel() for _, proto := range []string{"TCP", "UDP", "TLS", "TCP_UDP"} { t.Run(proto, func(t *testing.T) { svc := setupTestService(t) @@ -1656,6 +1735,7 @@ func TestCreateListener_NLB_AllProtocols(t *testing.T) { } func TestCreateListener_NLB_RejectsHTTPProtocol(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1679,6 +1759,7 @@ func TestCreateListener_NLB_RejectsHTTPProtocol(t *testing.T) { } func TestCreateListener_NLB_RejectsHTTPSProtocol(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1702,6 +1783,7 @@ func TestCreateListener_NLB_RejectsHTTPSProtocol(t *testing.T) { } func TestCreateListener_ALB_RejectsTCPProtocol(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1726,6 +1808,7 @@ func TestCreateListener_ALB_RejectsTCPProtocol(t *testing.T) { } func TestCreateListener_NLB_ProtocolCompatibility_TLSToTCP(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1754,6 +1837,7 @@ func TestCreateListener_NLB_ProtocolCompatibility_TLSToTCP(t *testing.T) { } func TestCreateListener_NLB_ProtocolIncompatible_TCPToUDP(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1781,6 +1865,7 @@ func TestCreateListener_NLB_ProtocolIncompatible_TCPToUDP(t *testing.T) { } func TestCreateListener_NLB_ProtocolIncompatible_UDPToTCP(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1808,6 +1893,7 @@ func TestCreateListener_NLB_ProtocolIncompatible_UDPToTCP(t *testing.T) { } func TestCreateListener_NLB_DefaultProtocol_Rejected(t *testing.T) { + t.Parallel() // When no protocol is specified, it defaults to HTTP which is invalid for NLB svc := setupTestService(t) @@ -1833,6 +1919,7 @@ func TestCreateListener_NLB_DefaultProtocol_Rejected(t *testing.T) { // --- HAProxy sync tests --- func TestCreateListener_PushConfig_NoNATS(t *testing.T) { + t.Parallel() // When NATS conn is nil, CreateListener should still succeed // (updateStoredConfig is a no-op when InstanceID is empty) svc := setupTestService(t) @@ -1862,6 +1949,7 @@ func TestCreateListener_PushConfig_NoNATS(t *testing.T) { // an LB without a systemAMI has InstanceID=="" and must skip TerminateSystemInstance. // The positive case is covered by TestDeleteLoadBalancer_TerminatesVM_WithPublicIP. func TestDeleteLoadBalancer_NoTerminateWhenEmptyInstanceID(t *testing.T) { + t.Parallel() svc := setupTestService(t) mock := &mockTerminateLauncher{} @@ -1897,6 +1985,7 @@ func (m *mockTerminateLauncher) TerminateSystemInstance(instanceID string) error // --- Scheme unit tests --- func TestCreateLoadBalancer_InternetFacingScheme_DNSName(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1913,6 +2002,7 @@ func TestCreateLoadBalancer_InternetFacingScheme_DNSName(t *testing.T) { } func TestCreateLoadBalancer_InternalScheme_DNSPrefix(t *testing.T) { + t.Parallel() svc := setupTestService(t) out, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -1931,6 +2021,7 @@ func TestCreateLoadBalancer_InternalScheme_DNSPrefix(t *testing.T) { // --- LBAgentHeartbeat tests --- func TestLBAgentHeartbeat_TransitionsProvisioningToActive(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -1957,6 +2048,7 @@ func TestLBAgentHeartbeat_TransitionsProvisioningToActive(t *testing.T) { } func TestLBAgentHeartbeat_ReturnsConfigHash(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -1978,6 +2070,7 @@ func TestLBAgentHeartbeat_ReturnsConfigHash(t *testing.T) { } func TestLBAgentHeartbeat_ProcessesHealthReport(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2031,6 +2124,7 @@ func TestLBAgentHeartbeat_ProcessesHealthReport(t *testing.T) { // updateStoredConfig no-ops while InstanceID is empty; the first heartbeat // (provisioning→active) must build the full config so the agent gets a ConfigHash. func TestLBAgentHeartbeat_BuildsConfigOnActivation(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2090,6 +2184,7 @@ func TestLBAgentHeartbeat_BuildsConfigOnActivation(t *testing.T) { } func TestLBAgentHeartbeat_MissingLBID(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.LBAgentHeartbeat(context.Background(), &LBAgentHeartbeatInput{}, testAccountID) @@ -2097,6 +2192,7 @@ func TestLBAgentHeartbeat_MissingLBID(t *testing.T) { } func TestLBAgentHeartbeat_LBNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.LBAgentHeartbeat(context.Background(), &LBAgentHeartbeatInput{ @@ -2108,6 +2204,7 @@ func TestLBAgentHeartbeat_LBNotFound(t *testing.T) { // --- GetLBConfig tests --- func TestGetLBConfig_ReturnsStoredConfig(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2131,6 +2228,7 @@ func TestGetLBConfig_ReturnsStoredConfig(t *testing.T) { } func TestGetLBConfig_DeliversHealthTargetsForNLB(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2158,6 +2256,7 @@ func TestGetLBConfig_DeliversHealthTargetsForNLB(t *testing.T) { } func TestGetLBConfig_HealthTargetsWireShape(t *testing.T) { + t.Parallel() svc := setupTestService(t) require.NoError(t, svc.store.PutLoadBalancer(t.Context(), &LoadBalancerRecord{ LoadBalancerID: "lb-wire", @@ -2195,6 +2294,7 @@ func TestGetLBConfig_HealthTargetsWireShape(t *testing.T) { } func TestGetLBConfig_NoHealthTargetsForALB(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2216,6 +2316,7 @@ func TestGetLBConfig_NoHealthTargetsForALB(t *testing.T) { } func TestGetLBConfig_MissingLBID(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.GetLBConfig(context.Background(), &GetLBConfigInput{}, testAccountID) @@ -2223,6 +2324,7 @@ func TestGetLBConfig_MissingLBID(t *testing.T) { } func TestGetLBConfig_LBNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.GetLBConfig(context.Background(), &GetLBConfigInput{ @@ -2232,6 +2334,7 @@ func TestGetLBConfig_LBNotFound(t *testing.T) { } func TestLBAgentHeartbeat_WrongAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2251,6 +2354,7 @@ func TestLBAgentHeartbeat_WrongAccount(t *testing.T) { } func TestLBAgentHeartbeat_SystemAccountAllowed(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2270,6 +2374,7 @@ func TestLBAgentHeartbeat_SystemAccountAllowed(t *testing.T) { } func TestLBAgentHeartbeat_SkipsWriteWhenHeartbeatFresh(t *testing.T) { + t.Parallel() svc := setupTestService(t) recentHeartbeat := time.Now().UTC().Add(-10 * time.Second) // well within 60s threshold @@ -2295,6 +2400,7 @@ func TestLBAgentHeartbeat_SkipsWriteWhenHeartbeatFresh(t *testing.T) { } func TestLBAgentHeartbeat_PersistsWhenHeartbeatStale(t *testing.T) { + t.Parallel() svc := setupTestService(t) staleHeartbeat := time.Now().UTC().Add(-2 * time.Minute) // beyond 60s threshold @@ -2320,6 +2426,7 @@ func TestLBAgentHeartbeat_PersistsWhenHeartbeatStale(t *testing.T) { } func TestGetLBConfig_WrongAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2341,6 +2448,7 @@ func TestGetLBConfig_WrongAccount(t *testing.T) { } func TestGetLBConfig_SystemAccountAllowed(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2364,6 +2472,7 @@ func TestGetLBConfig_SystemAccountAllowed(t *testing.T) { // --- updateStoredConfig tests --- func TestUpdateStoredConfig_StoresConfigAndHash(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2409,6 +2518,7 @@ func TestUpdateStoredConfig_StoresConfigAndHash(t *testing.T) { } func TestUpdateStoredConfig_SkipsWhenNoInstance(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2433,6 +2543,7 @@ func TestUpdateStoredConfig_SkipsWhenNoInstance(t *testing.T) { // TestGetSystemInstanceType_ColdStart pins the no-resolver-wired path — // cold-start must return empty rather than panic on a nil func. func TestGetSystemInstanceType_ColdStart(t *testing.T) { + t.Parallel() svc := setupTestService(t) assert.Empty(t, svc.getSystemInstanceType()) @@ -2442,6 +2553,7 @@ func TestGetSystemInstanceType_ColdStart(t *testing.T) { } func TestGetSystemInstanceType_RetryOnEmpty(t *testing.T) { + t.Parallel() svc := setupTestService(t) calls := 0 @@ -2465,6 +2577,7 @@ func TestGetSystemInstanceType_RetryOnEmpty(t *testing.T) { } func TestGetSystemInstanceType_Concurrent(t *testing.T) { + t.Parallel() svc := setupTestService(t) svc.SetSystemInstanceTypeFunc(func() string { return "t3.micro" }) @@ -2479,11 +2592,13 @@ func TestGetSystemInstanceType_Concurrent(t *testing.T) { } func TestIsCompatibleProtocol_UnknownListenerProtocol(t *testing.T) { + t.Parallel() assert.False(t, isCompatibleProtocol("SCTP", ProtocolTCP)) assert.False(t, isCompatibleProtocol("", ProtocolHTTP)) } func TestCreateListener_TargetGroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -2507,6 +2622,7 @@ func TestCreateListener_TargetGroupNotFound(t *testing.T) { } func TestUpdateStoredConfig_MissingTargetGroup(t *testing.T) { + t.Parallel() svc := setupTestService(t) lb := &LoadBalancerRecord{ @@ -2541,6 +2657,7 @@ func TestUpdateStoredConfig_MissingTargetGroup(t *testing.T) { // --- Attribute tests --- func TestDescribeTargetGroupAttributes_Defaults(t *testing.T) { + t.Parallel() svc := setupTestService(t) tgOut, err := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("tg-attr-defaults")}, testAccountID) require.NoError(t, err) @@ -2562,6 +2679,7 @@ func TestDescribeTargetGroupAttributes_Defaults(t *testing.T) { } func TestDescribeLoadBalancerAttributes_ALBDefaults(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("alb-attr-defaults")}, testAccountID) require.NoError(t, err) @@ -2586,6 +2704,7 @@ func TestDescribeLoadBalancerAttributes_ALBDefaults(t *testing.T) { } func TestDescribeLoadBalancerAttributes_NLBDefaults(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("nlb-attr-defaults"), @@ -2610,6 +2729,7 @@ func TestDescribeLoadBalancerAttributes_NLBDefaults(t *testing.T) { // attribute keys that Terraform's default ModifyLoadBalancerAttributes call sends, // which would surface as ValidationError. func TestDefaultLoadBalancerAttributes_ALBCoversTerraformKeys(t *testing.T) { + t.Parallel() attrs := DefaultLoadBalancerAttributes(LoadBalancerTypeApplication) expected := map[string]string{ @@ -2644,6 +2764,7 @@ func TestDefaultLoadBalancerAttributes_ALBCoversTerraformKeys(t *testing.T) { // TestDefaultLoadBalancerAttributes_NLBCoversExpectedKeys is the NLB // counterpart guard. NLBs have a smaller but distinct key set. func TestDefaultLoadBalancerAttributes_NLBCoversExpectedKeys(t *testing.T) { + t.Parallel() attrs := DefaultLoadBalancerAttributes(LoadBalancerTypeNetwork) expected := map[string]string{ @@ -2674,6 +2795,7 @@ func TestDefaultLoadBalancerAttributes_NLBCoversExpectedKeys(t *testing.T) { // guard: terraform sends connection_logs.s3.enabled on every aws_lb apply and // the handler must accept it. func TestModifyLoadBalancerAttributes_AcceptsConnectionLogsKey(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("alb-conn-logs"), @@ -2697,6 +2819,7 @@ func TestModifyLoadBalancerAttributes_AcceptsConnectionLogsKey(t *testing.T) { // empty-string Value is treated as a real value, not skipped as invalid. AWS // uses "" to clear access_logs.s3.bucket, so the handler must persist it. func TestModifyLoadBalancerAttributes_EmptyStringClears(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("alb-clear")}, testAccountID) require.NoError(t, err) @@ -2906,6 +3029,7 @@ func attrKinds() []attrKind { } func TestAttributeRoundTrip(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -2933,6 +3057,7 @@ func TestAttributeRoundTrip(t *testing.T) { } func TestAttributeNotFound(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -2947,6 +3072,7 @@ func TestAttributeNotFound(t *testing.T) { } func TestAttributeMissingArn(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -2961,6 +3087,7 @@ func TestAttributeMissingArn(t *testing.T) { } func TestAttributeWrongAccount(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -2985,6 +3112,7 @@ func TestAttributeWrongAccount(t *testing.T) { // resource never see each other's attributes: a Modify by account A must not be // visible to a Describe by account B, even for similarly-named resources. func TestAttributeCrossAccountIsolation(t *testing.T) { + t.Parallel() const accountB = "222222222222" for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { @@ -3013,6 +3141,7 @@ func TestAttributeCrossAccountIsolation(t *testing.T) { // and nil Values are skipped (with a warning) rather than panicking or being // silently dropped. Valid attributes in the same call must still be applied. func TestAttributeSkipsInvalidEntries(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -3041,6 +3170,7 @@ func TestAttributeSkipsInvalidEntries(t *testing.T) { // TestAttributeAllInvalidReturnsError guards against silent success when every // attribute trips the nil guard, returning 200 OK with nothing applied. func TestAttributeAllInvalidReturnsError(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -3060,6 +3190,7 @@ func TestAttributeAllInvalidReturnsError(t *testing.T) { // `rec.Attributes = newMap` would pass single-call tests but silently wipe // previous attributes on every subsequent call. func TestAttributeSequentialMerge(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -3095,6 +3226,7 @@ func TestAttributeSequentialMerge(t *testing.T) { // does not bump the KV revision — Terraform's drift check hits Modify on every // apply, so the steady-state path must be a storage-layer no-op. func TestAttributeNoopSkipsPersist(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -3123,6 +3255,7 @@ func TestAttributeNoopSkipsPersist(t *testing.T) { // AWS rejects unknowns with ValidationError; matching that surfaces typos at plan // time rather than letting them drift into KV. func TestAttributeRejectsUnknownKey(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -3144,6 +3277,7 @@ func TestAttributeRejectsUnknownKey(t *testing.T) { // sorted-by-key order. Go map iteration is randomised, so without explicit // sorting Terraform would see spurious plan diffs between describe calls. func TestAttributeSortedOrder(t *testing.T) { + t.Parallel() for _, k := range attrKinds() { t.Run(k.name, func(t *testing.T) { svc := setupTestService(t) @@ -3176,6 +3310,7 @@ func TestAttributeSortedOrder(t *testing.T) { // --- DescribeTags tests --- func TestDescribeTags_LoadBalancer(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("tags-lb"), @@ -3203,6 +3338,7 @@ func TestDescribeTags_LoadBalancer(t *testing.T) { } func TestDescribeTags_Listener_NoTags(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("tags-lst-lb")}, testAccountID) tgOut, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("tags-lst-tg")}, testAccountID) @@ -3229,6 +3365,7 @@ func TestDescribeTags_Listener_NoTags(t *testing.T) { } func TestDescribeTags_ListenerRule_NoTags(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("tags-rule-lb")}, testAccountID) tgOut, _ := svc.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("tags-rule-tg")}, testAccountID) @@ -3267,6 +3404,7 @@ func TestDescribeTags_ListenerRule_NoTags(t *testing.T) { } func TestDescribeTags_RuleNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.DescribeTags(context.Background(), &elbv2.DescribeTagsInput{ ResourceArns: []*string{ @@ -3278,6 +3416,7 @@ func TestDescribeTags_RuleNotFound(t *testing.T) { } func TestDescribeTags_MultipleArns(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("multi-lb"), @@ -3317,6 +3456,7 @@ func TestDescribeTags_MultipleArns(t *testing.T) { } func TestDescribeTags_LoadBalancerNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.DescribeTags(context.Background(), &elbv2.DescribeTagsInput{ ResourceArns: []*string{ @@ -3328,6 +3468,7 @@ func TestDescribeTags_LoadBalancerNotFound(t *testing.T) { } func TestDescribeTags_TargetGroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.DescribeTags(context.Background(), &elbv2.DescribeTagsInput{ ResourceArns: []*string{ @@ -3339,6 +3480,7 @@ func TestDescribeTags_TargetGroupNotFound(t *testing.T) { } func TestDescribeTags_ListenerNotFound(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.DescribeTags(context.Background(), &elbv2.DescribeTagsInput{ ResourceArns: []*string{ @@ -3350,6 +3492,7 @@ func TestDescribeTags_ListenerNotFound(t *testing.T) { } func TestDescribeTags_CrossAccount(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("xa-lb"), @@ -3365,6 +3508,7 @@ func TestDescribeTags_CrossAccount(t *testing.T) { } func TestDescribeTags_InvalidArn(t *testing.T) { + t.Parallel() svc := setupTestService(t) cases := []string{ "not-an-arn", @@ -3382,6 +3526,7 @@ func TestDescribeTags_InvalidArn(t *testing.T) { } func TestDescribeTags_MissingParameter(t *testing.T) { + t.Parallel() svc := setupTestService(t) // Empty ResourceArns @@ -3398,6 +3543,7 @@ func TestDescribeTags_MissingParameter(t *testing.T) { } func TestDescribeTags_UntaggedLoadBalancer(t *testing.T) { + t.Parallel() svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ Name: aws.String("untagged-lb"), @@ -3419,16 +3565,19 @@ func TestDescribeTags_UntaggedLoadBalancer(t *testing.T) { // --- DNSWatchBucket --- func TestDNSWatchBucket_NilReceiver(t *testing.T) { + t.Parallel() var svc *ELBv2ServiceImpl assert.Nil(t, svc.DNSWatchBucket()) } func TestDNSWatchBucket_NoStore(t *testing.T) { + t.Parallel() svc := &ELBv2ServiceImpl{} assert.Nil(t, svc.DNSWatchBucket()) } func TestDNSWatchBucket_WithStore(t *testing.T) { + t.Parallel() svc := setupTestService(t) bucket := svc.DNSWatchBucket() diff --git a/spinifex/handlers/elbv2/service_impl_vpc_test.go b/spinifex/handlers/elbv2/service_impl_vpc_test.go index 8d8331bde..d2c907eb4 100644 --- a/spinifex/handlers/elbv2/service_impl_vpc_test.go +++ b/spinifex/handlers/elbv2/service_impl_vpc_test.go @@ -67,6 +67,7 @@ func getTestSubnetID(t *testing.T, vpcSvc *handlers_ec2_vpc.VPCServiceImpl, vpcI } func TestCreateLoadBalancer_CreatesENIs(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) // Find the subnet we created @@ -118,6 +119,7 @@ func TestCreateLoadBalancer_CreatesENIs(t *testing.T) { // Subnets list. Ignoring SubnetMappings skips ENI allocation, so the data-plane VM // never launches and the ALB is created but cannot serve traffic. func TestCreateLoadBalancer_SubnetMappings_CreatesENIs(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -146,6 +148,7 @@ func TestCreateLoadBalancer_SubnetMappings_CreatesENIs(t *testing.T) { } func TestCreateLoadBalancer_MultipleSubnets(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) // Get VPC ID @@ -180,6 +183,7 @@ func TestCreateLoadBalancer_MultipleSubnets(t *testing.T) { // every subnet's ENI is threaded through to SystemInstanceInput, not just // the first one. func TestCreateLoadBalancer_MultiSubnet_AllENIsPassedToLauncher(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) vpcs, _ := vpcSvc.DescribeVpcs(context.Background(), &ec2.DescribeVpcsInput{}, testAccountID) @@ -232,6 +236,7 @@ func TestCreateLoadBalancer_MultiSubnet_AllENIsPassedToLauncher(t *testing.T) { } func TestDeleteLoadBalancer_CleansUpENIs(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, _ := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -264,6 +269,7 @@ func TestDeleteLoadBalancer_CleansUpENIs(t *testing.T) { // delete fails persistently — the ownership edge (lb.ENIs) is the only thing // that would ever let a retry (or the orphan reaper) find and finish it. func TestDeleteLoadBalancer_PersistsSurvivingENIsOnPersistentDeleteFailure(t *testing.T) { + t.Parallel() _, nc, js := testutil.StartTestJetStream(t) testutil.StubVpcdSGResponder(t, nc) @@ -320,6 +326,7 @@ func TestDeleteLoadBalancer_PersistsSurvivingENIsOnPersistentDeleteFailure(t *te } func TestCreateLoadBalancer_InvalidSubnet(t *testing.T) { + t.Parallel() svc, _ := setupTestServiceWithVPC(t) _, err := svc.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -331,6 +338,7 @@ func TestCreateLoadBalancer_InvalidSubnet(t *testing.T) { } func TestCreateLoadBalancer_RollbackOnPartialFailure(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, _ := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -349,6 +357,7 @@ func TestCreateLoadBalancer_RollbackOnPartialFailure(t *testing.T) { } func TestCreateLoadBalancer_WithoutVPCService(t *testing.T) { + t.Parallel() // When vpcService is nil (e.g. in pure unit tests), ENI creation is skipped svc := setupTestService(t) @@ -364,6 +373,7 @@ func TestCreateLoadBalancer_WithoutVPCService(t *testing.T) { // --- Scheme networking integration tests --- func TestCreateLoadBalancer_InternetFacing_AllocatesPublicIP(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -422,6 +432,7 @@ func TestCreateLoadBalancer_InternetFacing_AllocatesPublicIP(t *testing.T) { } func TestCreateLoadBalancer_Internal_NoPublicIP(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -463,6 +474,7 @@ func TestCreateLoadBalancer_Internal_NoPublicIP(t *testing.T) { } func TestCreateLoadBalancer_NLB_Internal_NoPublicIP(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -511,6 +523,7 @@ func TestCreateLoadBalancer_NLB_Internal_NoPublicIP(t *testing.T) { } func TestDeleteLoadBalancer_TerminatesVM_WithPublicIP(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -560,6 +573,7 @@ func TestDeleteLoadBalancer_TerminatesVM_WithPublicIP(t *testing.T) { } func TestDeleteLoadBalancer_ReapsFloatingIPNAT(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -618,6 +632,7 @@ func TestDeleteLoadBalancer_ReapsFloatingIPNAT(t *testing.T) { } func TestDescribeLoadBalancers_InternetFacing_IncludesPublicIP(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -669,6 +684,7 @@ func TestDescribeLoadBalancers_InternetFacing_IncludesPublicIP(t *testing.T) { } func TestDescribeLoadBalancers_Internal_NoPublicIP(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -711,6 +727,7 @@ func TestDescribeLoadBalancers_Internal_NoPublicIP(t *testing.T) { } func TestCreateLoadBalancer_LaunchFailure_SetsStateFailed(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -744,6 +761,7 @@ func TestCreateLoadBalancer_LaunchFailure_SetsStateFailed(t *testing.T) { } func TestCreateLoadBalancer_MissingCredentials_SetsStateFailed(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -778,6 +796,7 @@ func TestCreateLoadBalancer_MissingCredentials_SetsStateFailed(t *testing.T) { } func TestENI_RequesterManagedFlag(t *testing.T) { + t.Parallel() _, vpcSvc := setupTestServiceWithVPC(t) subnets, _ := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -823,6 +842,7 @@ func TestENI_RequesterManagedFlag(t *testing.T) { // SecurityGroups are applied to the ALB ENI; without this the OVN port-group misses // the user's allow rules and the default-deny ACL drops all inbound traffic. func TestCreateLoadBalancer_AttachesSpecifiedSecurityGroupsToENI(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -866,6 +886,7 @@ func TestCreateLoadBalancer_AttachesSpecifiedSecurityGroupsToENI(t *testing.T) { // AWS-semantics fallback: an ALB created without SecurityGroups joins the // VPC's default SG (so the default-deny ACL has at least one allow source). func TestCreateLoadBalancer_NoSecurityGroupsFallsBackToDefault(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -902,6 +923,7 @@ func TestCreateLoadBalancer_NoSecurityGroupsFallsBackToDefault(t *testing.T) { // same SystemInstanceInput as the original launch; a mismatch causes writeFwCfgBlobs // to emit a different netcfg/cacert blob than the persisted QEMU command line. func TestRebuildSystemInstanceInput_HappyPath(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) @@ -964,6 +986,7 @@ func TestRebuildSystemInstanceInput_HappyPath(t *testing.T) { // the LB record is gone from KV but the VM record survives; recovery must not // silently boot the VM into an unowned state. func TestRebuildSystemInstanceInput_NoLBRecord(t *testing.T) { + t.Parallel() svc := setupTestService(t) _, err := svc.RebuildSystemInstanceInput(RecoveryContext{ @@ -978,6 +1001,7 @@ func TestRebuildSystemInstanceInput_NoLBRecord(t *testing.T) { // multi-subnet ALBs; recovery must produce the same ExtraENIInput shape so the // daemon wires the same taps and NICs the persisted QEMU args reference. func TestRebuildSystemInstanceInput_MultiENI(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) vpcs, _ := vpcSvc.DescribeVpcs(context.Background(), &ec2.DescribeVpcsInput{}, testAccountID) @@ -1024,6 +1048,7 @@ func TestRebuildSystemInstanceInput_MultiENI(t *testing.T) { } func TestCreateClusterNLBSync_CarriesCrossAccountENI(t *testing.T) { + t.Parallel() svc, vpcSvc := setupTestServiceWithVPC(t) subnets, err := vpcSvc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{}, testAccountID) diff --git a/spinifex/handlers/elbv2/service_nats_e2e_test.go b/spinifex/handlers/elbv2/service_nats_e2e_test.go index 65e95f737..1182452ef 100644 --- a/spinifex/handlers/elbv2/service_nats_e2e_test.go +++ b/spinifex/handlers/elbv2/service_nats_e2e_test.go @@ -89,6 +89,7 @@ func handleNATSMsg[In any, Out any](msg *nats.Msg, fn func(context.Context, *In, // --- Full round-trip E2E tests --- func TestNATSE2E_CreateAndDescribeLoadBalancer(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) out, err := client.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ @@ -109,6 +110,7 @@ func TestNATSE2E_CreateAndDescribeLoadBalancer(t *testing.T) { } func TestNATSE2E_FullWorkflow(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) // 1. Create target group @@ -232,6 +234,7 @@ func TestNATSE2E_FullWorkflow(t *testing.T) { } func TestNATSE2E_DeleteLoadBalancerCascadesListeners(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) // Create LB + TG + 2 listeners @@ -259,6 +262,7 @@ func TestNATSE2E_DeleteLoadBalancerCascadesListeners(t *testing.T) { } func TestNATSE2E_ModifyListener(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) tgOut, _ := client.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("e2e-mod-tg")}, testAccountID) @@ -289,6 +293,7 @@ func TestNATSE2E_ModifyListener(t *testing.T) { } func TestNATSE2E_TargetGroupInUseProtection(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) tgOut, _ := client.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("protected-tg")}, testAccountID) @@ -307,6 +312,7 @@ func TestNATSE2E_TargetGroupInUseProtection(t *testing.T) { } func TestNATSE2E_TagsLifecycle(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) lbOut, err := client.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("e2e-tags-lb")}, testAccountID) @@ -348,6 +354,7 @@ func TestNATSE2E_TagsLifecycle(t *testing.T) { } func TestNATSE2E_AttributeRoundTrip(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) tgOut, err := client.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{Name: aws.String("e2e-attr-tg")}, testAccountID) @@ -392,6 +399,7 @@ func TestNATSE2E_AttributeRoundTrip(t *testing.T) { } func TestNATSE2E_RedirectListener(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) lbOut, err := client.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{Name: aws.String("e2e-redir-lb")}, testAccountID) @@ -425,6 +433,7 @@ func TestNATSE2E_RedirectListener(t *testing.T) { } func TestNATSE2E_IPTargetType(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) tgOut, err := client.CreateTargetGroup(context.Background(), &elbv2.CreateTargetGroupInput{ @@ -457,6 +466,7 @@ func TestNATSE2E_IPTargetType(t *testing.T) { } func TestNATSE2E_SetSecurityGroupsAndIpAddressType(t *testing.T) { + t.Parallel() client, _ := setupNATSELBv2Test(t) lbOut, err := client.CreateLoadBalancer(context.Background(), &elbv2.CreateLoadBalancerInput{ diff --git a/spinifex/handlers/elbv2/store_test.go b/spinifex/handlers/elbv2/store_test.go index 3b7886fdb..5431ba971 100644 --- a/spinifex/handlers/elbv2/store_test.go +++ b/spinifex/handlers/elbv2/store_test.go @@ -72,6 +72,7 @@ func newTestListener(id, lbArn string) *ListenerRecord { // bucket is not merely named, it opens against the live server so the DNS // reconcile can actually be woken by a load-balancer change. func TestStore_WatchBucketOpensAWatchableHandle(t *testing.T) { + t.Parallel() store := setupTestStore(t) bucket := store.WatchBucket() @@ -84,6 +85,7 @@ func TestStore_WatchBucketOpensAWatchableHandle(t *testing.T) { } func TestLoadBalancerStoreLifecycle(t *testing.T) { + t.Parallel() t.Run("put and get", func(t *testing.T) { store := setupTestStore(t) require.NoError(t, store.PutLoadBalancer(t.Context(), newTestLB("getput1", "lb-getput1"))) @@ -135,6 +137,7 @@ func TestLoadBalancerStoreLifecycle(t *testing.T) { } func TestTargetGroupStoreLifecycle(t *testing.T) { + t.Parallel() t.Run("put and get", func(t *testing.T) { store := setupTestStore(t) require.NoError(t, store.PutTargetGroup(t.Context(), newTestTG("getput1", "tg-getput1"))) @@ -186,6 +189,7 @@ func TestTargetGroupStoreLifecycle(t *testing.T) { } func TestListenerStoreLifecycle(t *testing.T) { + t.Parallel() lbArn := "arn:aws:elasticloadbalancing:us-east-1:" + testAccountID + ":loadbalancer/app/test/lb1" t.Run("put and get", func(t *testing.T) { @@ -241,6 +245,7 @@ func TestListenerStoreLifecycle(t *testing.T) { // --- LB-specific lookups (no equivalent on TG/Listener) --- func TestGetLoadBalancerByArn(t *testing.T) { + t.Parallel() store := setupTestStore(t) lb := newTestLB("arn123", "arn-test") require.NoError(t, store.PutLoadBalancer(t.Context(), lb)) @@ -256,6 +261,7 @@ func TestGetLoadBalancerByArn(t *testing.T) { } func TestGetLoadBalancerByName(t *testing.T) { + t.Parallel() store := setupTestStore(t) lb := newTestLB("name123", "find-by-name") require.NoError(t, store.PutLoadBalancer(t.Context(), lb)) @@ -267,6 +273,7 @@ func TestGetLoadBalancerByName(t *testing.T) { } func TestPutLoadBalancer_Update(t *testing.T) { + t.Parallel() store := setupTestStore(t) lb := newTestLB("upd123", "updatable") require.NoError(t, store.PutLoadBalancer(t.Context(), lb)) @@ -285,6 +292,7 @@ func TestPutLoadBalancer_Update(t *testing.T) { // --- TG-specific lookups + targets --- func TestGetTargetGroupByArn(t *testing.T) { + t.Parallel() store := setupTestStore(t) tg := newTestTG("tgarn", "arn-tg") require.NoError(t, store.PutTargetGroup(t.Context(), tg)) @@ -296,6 +304,7 @@ func TestGetTargetGroupByArn(t *testing.T) { } func TestGetTargetGroupByName(t *testing.T) { + t.Parallel() store := setupTestStore(t) tg := newTestTG("tgname", "named-tg") require.NoError(t, store.PutTargetGroup(t.Context(), tg)) @@ -311,6 +320,7 @@ func TestGetTargetGroupByName(t *testing.T) { } func TestTargetGroupWithTargets(t *testing.T) { + t.Parallel() store := setupTestStore(t) tg := newTestTG("tgtargets", "targets-tg") tg.Targets = []Target{ @@ -331,6 +341,7 @@ func TestTargetGroupWithTargets(t *testing.T) { // --- Listener-specific lookups --- func TestListListenersByLB(t *testing.T) { + t.Parallel() store := setupTestStore(t) lbArn1 := "arn:aws:elasticloadbalancing:us-east-1:" + testAccountID + ":loadbalancer/app/alb1/lb1" lbArn2 := "arn:aws:elasticloadbalancing:us-east-1:" + testAccountID + ":loadbalancer/app/alb2/lb2" @@ -356,6 +367,7 @@ func TestListListenersByLB(t *testing.T) { } func TestGetListenerByArn(t *testing.T) { + t.Parallel() store := setupTestStore(t) lbArn := "arn:aws:elasticloadbalancing:us-east-1:" + testAccountID + ":loadbalancer/app/test/lb1" l := newTestListener("lstarn", lbArn) @@ -380,6 +392,7 @@ func TestGetListenerByArn(t *testing.T) { // --- Cross-resource isolation: shared IDs across record types must not collide --- func TestResourceIsolation(t *testing.T) { + t.Parallel() store := setupTestStore(t) lb := newTestLB("shared1", "alb-shared") @@ -414,6 +427,7 @@ func TestResourceIsolation(t *testing.T) { } func TestTargetGroupsForLB(t *testing.T) { + t.Parallel() store := setupTestStore(t) // Non-existent LB returns nil, nil diff --git a/spinifex/handlers/elbv2/system_instance_launcher_nats_test.go b/spinifex/handlers/elbv2/system_instance_launcher_nats_test.go index 5cb0b9f96..2c86ade97 100644 --- a/spinifex/handlers/elbv2/system_instance_launcher_nats_test.go +++ b/spinifex/handlers/elbv2/system_instance_launcher_nats_test.go @@ -29,6 +29,7 @@ func (s *stubResponder) close() { } func TestNATSSystemInstanceLauncher_LaunchRoundTrip(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -77,6 +78,7 @@ func TestNATSSystemInstanceLauncher_LaunchRoundTrip(t *testing.T) { } func TestNATSSystemInstanceLauncher_LaunchPropagatesRemoteError(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -99,6 +101,7 @@ func TestNATSSystemInstanceLauncher_LaunchPropagatesRemoteError(t *testing.T) { } func TestNATSSystemInstanceLauncher_LaunchFailsWhenNoResponder(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -111,6 +114,7 @@ func TestNATSSystemInstanceLauncher_LaunchFailsWhenNoResponder(t *testing.T) { } func TestNATSSystemInstanceLauncher_TerminateRoundTrip(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -138,6 +142,7 @@ func TestNATSSystemInstanceLauncher_TerminateRoundTrip(t *testing.T) { } func TestNewNATSSystemInstanceLauncher_DefaultTimeout(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -152,6 +157,7 @@ func TestNewNATSSystemInstanceLauncher_DefaultTimeout(t *testing.T) { } func TestNATSSystemInstanceLauncher_LaunchNilInput(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -162,6 +168,7 @@ func TestNATSSystemInstanceLauncher_LaunchNilInput(t *testing.T) { } func TestNATSSystemInstanceLauncher_LaunchMissingInstanceType(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -172,6 +179,7 @@ func TestNATSSystemInstanceLauncher_LaunchMissingInstanceType(t *testing.T) { } func TestNATSSystemInstanceLauncher_LaunchDecodeFailure(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -188,6 +196,7 @@ func TestNATSSystemInstanceLauncher_LaunchDecodeFailure(t *testing.T) { } func TestNATSSystemInstanceLauncher_LaunchMissingOutput(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -204,6 +213,7 @@ func TestNATSSystemInstanceLauncher_LaunchMissingOutput(t *testing.T) { } func TestNATSSystemInstanceLauncher_TerminateEmptyID(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -214,6 +224,7 @@ func TestNATSSystemInstanceLauncher_TerminateEmptyID(t *testing.T) { } func TestNATSSystemInstanceLauncher_TerminateNoResponder(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -223,6 +234,7 @@ func TestNATSSystemInstanceLauncher_TerminateNoResponder(t *testing.T) { } func TestNATSSystemInstanceLauncher_TerminateDecodeFailure(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() @@ -239,6 +251,7 @@ func TestNATSSystemInstanceLauncher_TerminateDecodeFailure(t *testing.T) { } func TestNATSSystemInstanceLauncher_TerminatePropagatesRemoteError(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) defer nc.Close() diff --git a/spinifex/handlers/elbv2/types_test.go b/spinifex/handlers/elbv2/types_test.go index f3d748885..cbdb188ba 100644 --- a/spinifex/handlers/elbv2/types_test.go +++ b/spinifex/handlers/elbv2/types_test.go @@ -7,6 +7,7 @@ import ( ) func TestDefaultHealthCheck(t *testing.T) { + t.Parallel() hc := DefaultHealthCheck() assert.Equal(t, ProtocolHTTP, hc.Protocol) diff --git a/spinifex/handlers/iam/account_lifecycle_test.go b/spinifex/handlers/iam/account_lifecycle_test.go index 06fd50e1e..7a5a95d48 100644 --- a/spinifex/handlers/iam/account_lifecycle_test.go +++ b/spinifex/handlers/iam/account_lifecycle_test.go @@ -22,6 +22,7 @@ func newLifecycleService(t *testing.T) handlers_iam.IAMService { } func TestSetAccountStatusMovesBetweenStates(t *testing.T) { + t.Parallel() svc := newLifecycleService(t) account, err := svc.CreateAccount("tenant@example.com") require.NoError(t, err) @@ -44,6 +45,7 @@ func TestSetAccountStatusMovesBetweenStates(t *testing.T) { // resumes service is worse than one that stays down, and "undo" here would // mean restoring deleted block storage. func TestTerminatingIsAOneWayDoor(t *testing.T) { + t.Parallel() svc := newLifecycleService(t) account, err := svc.CreateAccount("tenant@example.com") require.NoError(t, err) @@ -62,6 +64,7 @@ func TestTerminatingIsAOneWayDoor(t *testing.T) { } func TestSetAccountStatusRejectsAnUnknownStatus(t *testing.T) { + t.Parallel() svc := newLifecycleService(t) account, err := svc.CreateAccount("tenant@example.com") require.NoError(t, err) @@ -74,6 +77,7 @@ func TestSetAccountStatusRejectsAnUnknownStatus(t *testing.T) { // Deleting the record while the account is still ACTIVE would leave every // resource it owns unattributable, so the status gate is the invariant. func TestDeleteAccountRequiresTerminating(t *testing.T) { + t.Parallel() svc := newLifecycleService(t) // Account ids are sequential and the first is the super admin, which is // protected — the tenant under test has to be the second. @@ -95,6 +99,7 @@ func TestDeleteAccountRequiresTerminating(t *testing.T) { // No credential grants deleting these two, so the refusal lives in the library // rather than only in the CLI that usually calls it. func TestProtectedAccountsCanNeverBeDeleted(t *testing.T) { + t.Parallel() svc := newLifecycleService(t) for accountID := range handlers_iam.UndeletableAccountIDs { @@ -113,6 +118,7 @@ func TestProtectedAccountsCanNeverBeDeleted(t *testing.T) { // A deleted account's name must be free again: a customer who leaves and comes // back must not be told their own address is taken. func TestReleaseDeletedFreesTheName(t *testing.T) { + t.Parallel() index, _ := newAccountNameIndex(t) ctx := t.Context() @@ -132,6 +138,7 @@ func TestReleaseDeletedFreesTheName(t *testing.T) { // Releasing a name that belongs to a live account would unindex it and let a // second account take the same address. func TestReleaseDeletedRefusesAnotherAccountsName(t *testing.T) { + t.Parallel() index, _ := newAccountNameIndex(t) ctx := t.Context() @@ -149,6 +156,7 @@ func TestReleaseDeletedRefusesAnotherAccountsName(t *testing.T) { // Teardown re-runs after a crash, so a name that is already released is a // success rather than a failure that blocks the account record's deletion. func TestReleaseDeletedIsIdempotent(t *testing.T) { + t.Parallel() index, _ := newAccountNameIndex(t) ctx := t.Context() diff --git a/spinifex/handlers/iam/account_names_test.go b/spinifex/handlers/iam/account_names_test.go index 407386b70..b677ed97d 100644 --- a/spinifex/handlers/iam/account_names_test.go +++ b/spinifex/handlers/iam/account_names_test.go @@ -21,6 +21,7 @@ func newAccountNameIndex(t *testing.T) (*handlers_iam.AccountNameIndex, jetstrea } func TestAccountNameIndexReserveCommitLookup(t *testing.T) { + t.Parallel() index, _ := newAccountNameIndex(t) ctx := t.Context() @@ -44,6 +45,7 @@ func TestAccountNameIndexReserveCommitLookup(t *testing.T) { } func TestAccountNameIndexReserveConflicts(t *testing.T) { + t.Parallel() index, _ := newAccountNameIndex(t) ctx := t.Context() @@ -63,6 +65,7 @@ func TestAccountNameIndexReserveConflicts(t *testing.T) { // Case and whitespace must not create a second account for the same person. func TestAccountNameIndexNormalizesName(t *testing.T) { + t.Parallel() index, _ := newAccountNameIndex(t) ctx := t.Context() @@ -78,6 +81,7 @@ func TestAccountNameIndexNormalizesName(t *testing.T) { } func TestAccountNameIndexRelease(t *testing.T) { + t.Parallel() index, _ := newAccountNameIndex(t) ctx := t.Context() @@ -101,6 +105,7 @@ func TestAccountNameIndexRelease(t *testing.T) { // Release on a name that was never reserved is a no-op, not an error: it runs // on the failure path where the reservation may already be gone. func TestAccountNameIndexReleaseUnknownName(t *testing.T) { + t.Parallel() index, _ := newAccountNameIndex(t) require.NoError(t, index.Release(t.Context(), "nobody@example.com", "token-a")) } @@ -108,6 +113,7 @@ func TestAccountNameIndexReleaseUnknownName(t *testing.T) { // KV keys are readable by anyone with cluster access, so a customer's email // address must not appear in one. func TestAccountNameIndexKeysCarryNoEmailAddress(t *testing.T) { + t.Parallel() index, js := newAccountNameIndex(t) ctx := t.Context() @@ -126,6 +132,7 @@ func TestAccountNameIndexKeysCarryNoEmailAddress(t *testing.T) { } func TestFindAccountByName(t *testing.T) { + t.Parallel() svc := newIAMService(t) created, err := svc.CreateAccount("ben@example.com") @@ -144,6 +151,7 @@ func TestFindAccountByName(t *testing.T) { // A corrupt entry must surface as an error. Treating it as absent would let a // second account be created under a name that is already indexed. func TestAccountNameIndexRejectsCorruptEntry(t *testing.T) { + t.Parallel() index, js := newAccountNameIndex(t) ctx := t.Context() diff --git a/spinifex/handlers/iam/account_summary_test.go b/spinifex/handlers/iam/account_summary_test.go index 5ab8c4520..bd9264ef9 100644 --- a/spinifex/handlers/iam/account_summary_test.go +++ b/spinifex/handlers/iam/account_summary_test.go @@ -55,6 +55,7 @@ func resName(prefix string, i int) string { } func TestGetAccountSummary_Counts(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Org A") @@ -87,6 +88,7 @@ func TestGetAccountSummary_Counts(t *testing.T) { } func TestGetAccountSummary_EmptyAccount(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acc, err := svc.CreateAccount("Empty Org") diff --git a/spinifex/handlers/iam/account_test.go b/spinifex/handlers/iam/account_test.go index 02e357a1d..0971205e5 100644 --- a/spinifex/handlers/iam/account_test.go +++ b/spinifex/handlers/iam/account_test.go @@ -19,6 +19,7 @@ import ( // ============================================================================ func TestCreateAccount(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acc1, err := svc.CreateAccount("Team Alpha") @@ -36,6 +37,7 @@ func TestCreateAccount(t *testing.T) { } func TestCreateAccount_SequentialIDs(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) var prevID string @@ -51,6 +53,7 @@ func TestCreateAccount_SequentialIDs(t *testing.T) { } func TestGetAccount(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created, err := svc.CreateAccount("Lookup Test") @@ -64,6 +67,7 @@ func TestGetAccount(t *testing.T) { } func TestGetAccount_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetAccount("999999999999") @@ -71,6 +75,7 @@ func TestGetAccount_NotFound(t *testing.T) { } func TestListAccounts(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) svc.CreateAccount("Acct1") @@ -91,6 +96,7 @@ func TestListAccounts(t *testing.T) { } func TestListAccounts_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accounts, err := svc.ListAccounts() @@ -103,6 +109,7 @@ func TestListAccounts_Empty(t *testing.T) { // ============================================================================ func TestAccountScopedUsers(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acc1, err := svc.CreateAccount("Org A") @@ -160,6 +167,7 @@ func TestAccountScopedUsers(t *testing.T) { // ============================================================================ func TestAccountScopedPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acc1, err := svc.CreateAccount("Policy Org A") @@ -199,6 +207,7 @@ func TestAccountScopedPolicies(t *testing.T) { // ============================================================================ func TestAccessKeyReturnsAccountID(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acc, err := svc.CreateAccount("Key Org") @@ -230,6 +239,7 @@ func TestAccessKeyReturnsAccountID(t *testing.T) { // ============================================================================ func TestCrossAccount_UserIsolation(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Account A") @@ -256,6 +266,7 @@ func TestCrossAccount_UserIsolation(t *testing.T) { } func TestCrossAccount_AccessKeyIsolation(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Key Org A") @@ -281,6 +292,7 @@ func TestCrossAccount_AccessKeyIsolation(t *testing.T) { } func TestCrossAccount_PolicyAttachmentFails(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Policy Org A") @@ -312,6 +324,7 @@ func TestCrossAccount_PolicyAttachmentFails(t *testing.T) { } func TestCrossAccount_LookupAccessKeyReturnsCorrectAccount(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Lookup A") @@ -348,6 +361,7 @@ func TestCrossAccount_LookupAccessKeyReturnsCorrectAccount(t *testing.T) { // ============================================================================ func TestSeedBootstrap_AccountScoped(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) encryptedSecret, err := svc.key.EncryptBase64("root-secret") @@ -387,6 +401,7 @@ func TestSeedBootstrap_AccountScoped(t *testing.T) { // ============================================================================ func TestCreateAccount_PublishesEvent(t *testing.T) { + t.Parallel() _, nc, _ := testutil.StartTestJetStream(t) masterKey, err := GenerateMasterKey() diff --git a/spinifex/handlers/iam/authorization_test.go b/spinifex/handlers/iam/authorization_test.go index 3f3204937..fffa62717 100644 --- a/spinifex/handlers/iam/authorization_test.go +++ b/spinifex/handlers/iam/authorization_test.go @@ -12,6 +12,7 @@ import ( ) func TestCanonicalResourceARNPreservesStoredPaths(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) trust := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}` policy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*"}]}` diff --git a/spinifex/handlers/iam/crypto_test.go b/spinifex/handlers/iam/crypto_test.go index 48b9b6e8c..81561d764 100644 --- a/spinifex/handlers/iam/crypto_test.go +++ b/spinifex/handlers/iam/crypto_test.go @@ -10,6 +10,7 @@ import ( ) func TestGenerateMasterKey(t *testing.T) { + t.Parallel() key, err := GenerateMasterKey() if err != nil { t.Fatalf("GenerateMasterKey() error: %v", err) @@ -29,6 +30,7 @@ func TestGenerateMasterKey(t *testing.T) { } func TestSaveAndReadMasterKey(t *testing.T) { + t.Parallel() key, err := GenerateMasterKey() if err != nil { t.Fatalf("GenerateMasterKey() error: %v", err) @@ -60,6 +62,7 @@ func TestSaveAndReadMasterKey(t *testing.T) { } func TestReadMasterKeyWrongSize(t *testing.T) { + t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "bad.key") @@ -74,6 +77,7 @@ func TestReadMasterKeyWrongSize(t *testing.T) { } func TestReadMasterKeyNotFound(t *testing.T) { + t.Parallel() _, err := masterkey.ReadShared("/nonexistent/master.key") if err == nil { t.Fatal("masterkey.ReadShared() should fail for missing file") @@ -81,6 +85,7 @@ func TestReadMasterKeyNotFound(t *testing.T) { } func TestSaveMasterKeyWrongSize(t *testing.T) { + t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "bad.key") @@ -91,6 +96,7 @@ func TestSaveMasterKeyWrongSize(t *testing.T) { } func TestEncryptDecryptRoundTrip(t *testing.T) { + t.Parallel() key, err := GenerateMasterKey() if err != nil { t.Fatalf("GenerateMasterKey() error: %v", err) @@ -118,6 +124,7 @@ func TestEncryptDecryptRoundTrip(t *testing.T) { } func TestEncryptProducesDifferentCiphertexts(t *testing.T) { + t.Parallel() key, _ := GenerateMasterKey() secret := "test-secret" @@ -130,6 +137,7 @@ func TestEncryptProducesDifferentCiphertexts(t *testing.T) { } func TestDecryptWrongKey(t *testing.T) { + t.Parallel() key1, _ := GenerateMasterKey() key2, _ := GenerateMasterKey() secret := "test-secret" @@ -146,6 +154,7 @@ func TestDecryptWrongKey(t *testing.T) { } func TestDecryptTamperedCiphertext(t *testing.T) { + t.Parallel() key, _ := GenerateMasterKey() secret := "test-secret" @@ -166,6 +175,7 @@ func TestDecryptTamperedCiphertext(t *testing.T) { } func TestDecryptInvalidBase64(t *testing.T) { + t.Parallel() key, _ := GenerateMasterKey() _, err := DecryptSecret("not-valid-base64!!!", key) if err == nil { @@ -174,6 +184,7 @@ func TestDecryptInvalidBase64(t *testing.T) { } func TestDecryptTooShort(t *testing.T) { + t.Parallel() key, _ := GenerateMasterKey() // Valid base64 but too short for nonce + ciphertext _, err := DecryptSecret("AQID", key) @@ -183,6 +194,7 @@ func TestDecryptTooShort(t *testing.T) { } func TestLoadBootstrapData(t *testing.T) { + t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "bootstrap.json") @@ -217,6 +229,7 @@ func TestLoadBootstrapData(t *testing.T) { } func TestLoadBootstrapDataNotFound(t *testing.T) { + t.Parallel() _, err := LoadBootstrapData("/nonexistent/bootstrap.json") if err == nil { t.Fatal("LoadBootstrapData() should fail for missing file") @@ -224,6 +237,7 @@ func TestLoadBootstrapDataNotFound(t *testing.T) { } func TestLoadBootstrapDataInvalidJSON(t *testing.T) { + t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "bootstrap.json") @@ -238,6 +252,7 @@ func TestLoadBootstrapDataInvalidJSON(t *testing.T) { } func TestSaveBootstrapData_RoundTrip(t *testing.T) { + t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "bootstrap.json") @@ -280,6 +295,7 @@ func TestSaveBootstrapData_RoundTrip(t *testing.T) { } func TestBootstrapData_ExtendedRoundTrip(t *testing.T) { + t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "bootstrap.json") @@ -335,6 +351,7 @@ func TestBootstrapData_ExtendedRoundTrip(t *testing.T) { } func TestBootstrapData_NoAdmin(t *testing.T) { + t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "bootstrap.json") @@ -357,6 +374,7 @@ func TestBootstrapData_NoAdmin(t *testing.T) { } func TestLoadBootstrapData_MissingVersion(t *testing.T) { + t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "bootstrap.json") @@ -372,6 +390,7 @@ func TestLoadBootstrapData_MissingVersion(t *testing.T) { } func TestSaveBootstrapData_InvalidPath(t *testing.T) { + t.Parallel() data := &BootstrapData{ AccessKeyID: "AKIAIOSFODNN7EXAMPLE", EncryptedSecret: "dGVzdA==", diff --git a/spinifex/handlers/iam/groups_test.go b/spinifex/handlers/iam/groups_test.go index 1534d25e8..48c906456 100644 --- a/spinifex/handlers/iam/groups_test.go +++ b/spinifex/handlers/iam/groups_test.go @@ -34,6 +34,7 @@ func createTestGroup(t *testing.T, svc *IAMServiceImpl, name string) *iam.Group // ============================================================================ func TestCreateGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateGroup(testAccountID, &iam.CreateGroupInput{ @@ -50,6 +51,7 @@ func TestCreateGroup(t *testing.T) { } func TestCreateGroup_DefaultPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateGroup(testAccountID, &iam.CreateGroupInput{ @@ -61,6 +63,7 @@ func TestCreateGroup_DefaultPath(t *testing.T) { } func TestCreateGroup_Duplicate(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "dup-group") @@ -72,6 +75,7 @@ func TestCreateGroup_Duplicate(t *testing.T) { } func TestCreateGroup_InvalidName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) longName := strings.Repeat("a", 129) @@ -83,6 +87,7 @@ func TestCreateGroup_InvalidName(t *testing.T) { } func TestCreateGroup_InvalidPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateGroup(testAccountID, &iam.CreateGroupInput{ @@ -94,6 +99,7 @@ func TestCreateGroup_InvalidPath(t *testing.T) { } func TestGetGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "get-group") createTestUser(t, svc, "member") @@ -114,6 +120,7 @@ func TestGetGroup(t *testing.T) { } func TestGetGroup_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetGroup(testAccountID, &iam.GetGroupInput{ @@ -124,6 +131,7 @@ func TestGetGroup_NotFound(t *testing.T) { } func TestGetGroup_UsersNeverNil(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "empty-group") @@ -136,6 +144,7 @@ func TestGetGroup_UsersNeverNil(t *testing.T) { } func TestListGroups(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "group1") createTestGroup(t, svc, "group2") @@ -155,6 +164,7 @@ func TestListGroups(t *testing.T) { } func TestListGroups_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.ListGroups(testAccountID, &iam.ListGroupsInput{}) @@ -166,6 +176,7 @@ func TestListGroups_Empty(t *testing.T) { // TestListGroups_EmptyAfterOtherAccountsExist walks the filtering path rather // than the no-keys-at-all shortcut: the bucket has keys, none of them ours. func TestListGroups_EmptyAfterOtherAccountsExist(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateGroup("999988887777", &iam.CreateGroupInput{GroupName: aws.String("othergroup")}) @@ -178,6 +189,7 @@ func TestListGroups_EmptyAfterOtherAccountsExist(t *testing.T) { } func TestListGroups_PathPrefix(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateGroup(testAccountID, &iam.CreateGroupInput{ @@ -201,6 +213,7 @@ func TestListGroups_PathPrefix(t *testing.T) { } func TestDeleteGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "del-group") @@ -217,6 +230,7 @@ func TestDeleteGroup(t *testing.T) { } func TestDeleteGroup_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DeleteGroup(testAccountID, &iam.DeleteGroupInput{ @@ -227,6 +241,7 @@ func TestDeleteGroup_NotFound(t *testing.T) { } func TestDeleteGroup_WithAttachedPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "attached-group") policy := createTestPolicy(t, svc, "GroupPolicy") @@ -245,6 +260,7 @@ func TestDeleteGroup_WithAttachedPolicy(t *testing.T) { } func TestDeleteGroup_WithMembers(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "populated-group") createTestUser(t, svc, "occupant") @@ -267,6 +283,7 @@ func TestDeleteGroup_WithMembers(t *testing.T) { // ============================================================================ func TestAddUserToGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "team") createTestUser(t, svc, "alice") @@ -286,6 +303,7 @@ func TestAddUserToGroup(t *testing.T) { } func TestAddUserToGroup_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "team") createTestUser(t, svc, "bob") @@ -306,6 +324,7 @@ func TestAddUserToGroup_Idempotent(t *testing.T) { } func TestAddUserToGroup_LimitExceeded(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "busy") @@ -330,6 +349,7 @@ func TestAddUserToGroup_LimitExceeded(t *testing.T) { } func TestAddUserToGroup_UserNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "team") @@ -342,6 +362,7 @@ func TestAddUserToGroup_UserNotFound(t *testing.T) { } func TestAddUserToGroup_GroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "carol") @@ -354,6 +375,7 @@ func TestAddUserToGroup_GroupNotFound(t *testing.T) { } func TestRemoveUserFromGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "team") createTestUser(t, svc, "dave") @@ -378,6 +400,7 @@ func TestRemoveUserFromGroup(t *testing.T) { } func TestRemoveUserFromGroup_NotMember(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "team") createTestUser(t, svc, "erin") @@ -391,6 +414,7 @@ func TestRemoveUserFromGroup_NotMember(t *testing.T) { } func TestRemoveUserFromGroup_UserNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "team") @@ -406,6 +430,7 @@ func TestRemoveUserFromGroup_UserNotFound(t *testing.T) { // group that was deleted out from under the user is still cleanable — removal // operates purely on User.Groups and never fetches the group record. func TestRemoveUserFromGroup_DanglingPointer(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "doomed") createTestUser(t, svc, "frank") @@ -433,6 +458,7 @@ func TestRemoveUserFromGroup_DanglingPointer(t *testing.T) { } func TestListGroupsForUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "grace") for _, name := range []string{"alpha", "bravo"} { @@ -458,6 +484,7 @@ func TestListGroupsForUser(t *testing.T) { } func TestListGroupsForUser_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "loner") @@ -469,6 +496,7 @@ func TestListGroupsForUser_Empty(t *testing.T) { } func TestListGroupsForUser_UserNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ListGroupsForUser(testAccountID, &iam.ListGroupsForUserInput{ @@ -481,6 +509,7 @@ func TestListGroupsForUser_UserNotFound(t *testing.T) { // TestListGroupsForUser_SkipsMissingGroup proves a dangling membership pointer // is silently skipped rather than erroring the whole listing. func TestListGroupsForUser_SkipsMissingGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "live") createTestGroup(t, svc, "vanishing") @@ -509,6 +538,7 @@ func TestListGroupsForUser_SkipsMissingGroup(t *testing.T) { // ============================================================================ func TestAttachGroupPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "policy-group") policy := createTestPolicy(t, svc, "AttachPolicy") @@ -529,6 +559,7 @@ func TestAttachGroupPolicy(t *testing.T) { } func TestAttachGroupPolicy_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "idem-group") policy := createTestPolicy(t, svc, "IdemPolicy") @@ -549,6 +580,7 @@ func TestAttachGroupPolicy_Idempotent(t *testing.T) { } func TestAttachGroupPolicy_PolicyNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "needs-policy") @@ -561,6 +593,7 @@ func TestAttachGroupPolicy_PolicyNotFound(t *testing.T) { } func TestAttachGroupPolicy_GroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) policy := createTestPolicy(t, svc, "OrphanPolicy") @@ -575,6 +608,7 @@ func TestAttachGroupPolicy_GroupNotFound(t *testing.T) { // TestAttachGroupPolicy_AWSManagedOpaque proves an AWS-managed ARN with no // backing policy record round-trips opaquely instead of failing NoSuchEntity. func TestAttachGroupPolicy_AWSManagedOpaque(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "managed-group") const managedARN = "arn:aws:iam::aws:policy/service-role/AmazonEKS_CNI_Policy" @@ -595,6 +629,7 @@ func TestAttachGroupPolicy_AWSManagedOpaque(t *testing.T) { } func TestDetachGroupPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "detach-group") policy := createTestPolicy(t, svc, "DetachPolicy") @@ -619,6 +654,7 @@ func TestDetachGroupPolicy(t *testing.T) { } func TestDetachGroupPolicy_NotAttached(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "bare-group") policy := createTestPolicy(t, svc, "NotAttachedPolicy") @@ -632,6 +668,7 @@ func TestDetachGroupPolicy_NotAttached(t *testing.T) { } func TestDetachGroupPolicy_GroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) policy := createTestPolicy(t, svc, "OrphanDetach") @@ -644,6 +681,7 @@ func TestDetachGroupPolicy_GroupNotFound(t *testing.T) { } func TestListAttachedGroupPolicies_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "empty-attach") @@ -655,6 +693,7 @@ func TestListAttachedGroupPolicies_Empty(t *testing.T) { } func TestListAttachedGroupPolicies_GroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ListAttachedGroupPolicies(testAccountID, &iam.ListAttachedGroupPoliciesInput{ @@ -669,6 +708,7 @@ func TestListAttachedGroupPolicies_GroupNotFound(t *testing.T) { // ============================================================================ func TestPutGroupPolicy_RoundTrip(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "inline-group") @@ -690,6 +730,7 @@ func TestPutGroupPolicy_RoundTrip(t *testing.T) { } func TestPutGroupPolicy_IdempotentOverwrite(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "overwrite-group") @@ -722,6 +763,7 @@ func TestPutGroupPolicy_IdempotentOverwrite(t *testing.T) { } func TestPutGroupPolicy_InvalidName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "badname-group") @@ -735,6 +777,7 @@ func TestPutGroupPolicy_InvalidName(t *testing.T) { } func TestPutGroupPolicy_MalformedDocument(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "malformed-group") @@ -748,6 +791,7 @@ func TestPutGroupPolicy_MalformedDocument(t *testing.T) { } func TestPutGroupPolicy_OversizedDocument(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "oversized-group") @@ -762,6 +806,7 @@ func TestPutGroupPolicy_OversizedDocument(t *testing.T) { } func TestPutGroupPolicy_GroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.PutGroupPolicy(testAccountID, &iam.PutGroupPolicyInput{ @@ -774,6 +819,7 @@ func TestPutGroupPolicy_GroupNotFound(t *testing.T) { } func TestGetGroupPolicy_UnknownName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "get-unknown") @@ -786,6 +832,7 @@ func TestGetGroupPolicy_UnknownName(t *testing.T) { } func TestGetGroupPolicy_GroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetGroupPolicy(testAccountID, &iam.GetGroupPolicyInput{ @@ -797,6 +844,7 @@ func TestGetGroupPolicy_GroupNotFound(t *testing.T) { } func TestListGroupPolicies_Sorted(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "list-group") @@ -822,6 +870,7 @@ func TestListGroupPolicies_Sorted(t *testing.T) { } func TestListGroupPolicies_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "empty-inline-group") @@ -835,6 +884,7 @@ func TestListGroupPolicies_Empty(t *testing.T) { } func TestListGroupPolicies_GroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ListGroupPolicies(testAccountID, &iam.ListGroupPoliciesInput{ @@ -845,6 +895,7 @@ func TestListGroupPolicies_GroupNotFound(t *testing.T) { } func TestDeleteGroupPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "del-inline-group") @@ -876,6 +927,7 @@ func TestDeleteGroupPolicy(t *testing.T) { } func TestDeleteGroupPolicy_DoubleDelete(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "double-del-group") @@ -901,6 +953,7 @@ func TestDeleteGroupPolicy_DoubleDelete(t *testing.T) { } func TestDeleteGroupPolicy_GroupNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DeleteGroupPolicy(testAccountID, &iam.DeleteGroupPolicyInput{ @@ -914,6 +967,7 @@ func TestDeleteGroupPolicy_GroupNotFound(t *testing.T) { // TestDeleteGroup_WithInlinePolicy proves a group carrying an inline policy // refuses deletion until the inline policy is removed, mirroring DeleteRole. func TestDeleteGroup_WithInlinePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "inline-conflict-group") @@ -952,6 +1006,7 @@ func TestDeleteGroup_WithInlinePolicy(t *testing.T) { // permission set, and stop contributing once the user leaves the group. Without // this behaviour groups are cosmetic and grant nothing. func TestGetUserPolicies_GroupInheritance(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "grantor") createTestUser(t, svc, "ivy") @@ -1002,6 +1057,7 @@ func TestGetUserPolicies_GroupInheritance(t *testing.T) { // TestGetUserPolicies_DirectAndGroup proves direct user attachments and // group-inherited policies both surface in one combined effective set. func TestGetUserPolicies_DirectAndGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "combined-group") createTestUser(t, svc, "jack") @@ -1035,6 +1091,7 @@ func TestGetUserPolicies_DirectAndGroup(t *testing.T) { // skipped (not fail-closed): the user keeps their direct grants and the dangling // name remains cleanable via RemoveUserFromGroup. func TestGetUserPolicies_SkipsMissingGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "soon-gone") createTestUser(t, svc, "kim") @@ -1090,6 +1147,7 @@ func putRawGroupInlinePolicy(t *testing.T, svc *IAMServiceImpl, groupName, polic // permission set, and stop contributing once the inline policy is removed. // Without this, group inline policies are cosmetic and grant nothing. func TestGetUserPolicies_GroupInlineInheritance(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "inline-grantor") createTestUser(t, svc, "nora") @@ -1134,6 +1192,7 @@ func TestGetUserPolicies_GroupInlineInheritance(t *testing.T) { // and its inline document both surface in a member's combined effective set — // inline grants supplement managed grants rather than replacing them. func TestGetUserPolicies_GroupManagedAndInline(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "combined-inline-group") createTestUser(t, svc, "omar") @@ -1169,6 +1228,7 @@ func TestGetUserPolicies_GroupManagedAndInline(t *testing.T) { // document on a resolvable group fails the whole resolution closed rather than // silently dropping the grant source, mirroring GetRolePolicies. func TestGetUserPolicies_GroupInlineMalformedFailsClosed(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "corrupt-inline-group") createTestUser(t, svc, "pam") @@ -1190,6 +1250,7 @@ func TestGetUserPolicies_GroupInlineMalformedFailsClosed(t *testing.T) { // ============================================================================ func TestDeleteUser_InGroup(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestGroup(t, svc, "blocker") createTestUser(t, svc, "leo") @@ -1224,6 +1285,7 @@ func TestDeleteUser_InGroup(t *testing.T) { // ============================================================================ func TestGroups_AccountScoping(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Org A") diff --git a/spinifex/handlers/iam/instance_profiles_test.go b/spinifex/handlers/iam/instance_profiles_test.go index 361f27f83..b0fe3757e 100644 --- a/spinifex/handlers/iam/instance_profiles_test.go +++ b/spinifex/handlers/iam/instance_profiles_test.go @@ -27,6 +27,7 @@ func createTestInstanceProfile(t *testing.T, svc *IAMServiceImpl, name string) * // ============================================================================ func TestCreateInstanceProfile(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateInstanceProfile(testAccountID, &iam.CreateInstanceProfileInput{ @@ -49,6 +50,7 @@ func TestCreateInstanceProfile(t *testing.T) { } func TestCreateInstanceProfile_DefaultPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateInstanceProfile(testAccountID, &iam.CreateInstanceProfileInput{ @@ -60,6 +62,7 @@ func TestCreateInstanceProfile_DefaultPath(t *testing.T) { } func TestCreateInstanceProfile_InvalidName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) longName := strings.Repeat("a", 129) @@ -71,6 +74,7 @@ func TestCreateInstanceProfile_InvalidName(t *testing.T) { } func TestCreateInstanceProfile_InvalidPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateInstanceProfile(testAccountID, &iam.CreateInstanceProfileInput{ @@ -82,6 +86,7 @@ func TestCreateInstanceProfile_InvalidPath(t *testing.T) { } func TestCreateInstanceProfile_Duplicate(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestInstanceProfile(t, svc, "dup-profile") @@ -93,6 +98,7 @@ func TestCreateInstanceProfile_Duplicate(t *testing.T) { } func TestGetInstanceProfile(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestInstanceProfile(t, svc, "get-profile") @@ -105,6 +111,7 @@ func TestGetInstanceProfile(t *testing.T) { } func TestGetInstanceProfile_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetInstanceProfile(testAccountID, &iam.GetInstanceProfileInput{ @@ -115,6 +122,7 @@ func TestGetInstanceProfile_NotFound(t *testing.T) { } func TestGetInstanceProfile_WithAttachedRole(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "embedded-role") createTestInstanceProfile(t, svc, "wrap-profile") @@ -134,6 +142,7 @@ func TestGetInstanceProfile_WithAttachedRole(t *testing.T) { } func TestListInstanceProfiles(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestInstanceProfile(t, svc, "profile1") @@ -154,6 +163,7 @@ func TestListInstanceProfiles(t *testing.T) { } func TestListInstanceProfiles_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.ListInstanceProfiles(testAccountID, &iam.ListInstanceProfilesInput{}) @@ -162,6 +172,7 @@ func TestListInstanceProfiles_Empty(t *testing.T) { } func TestListInstanceProfiles_PathPrefix(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateInstanceProfile(testAccountID, &iam.CreateInstanceProfileInput{ @@ -185,6 +196,7 @@ func TestListInstanceProfiles_PathPrefix(t *testing.T) { } func TestDeleteInstanceProfile(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestInstanceProfile(t, svc, "del-profile") @@ -201,6 +213,7 @@ func TestDeleteInstanceProfile(t *testing.T) { } func TestDeleteInstanceProfile_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DeleteInstanceProfile(testAccountID, &iam.DeleteInstanceProfileInput{ @@ -211,6 +224,7 @@ func TestDeleteInstanceProfile_NotFound(t *testing.T) { } func TestDeleteInstanceProfile_WithRoleAttached(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "attached-role") createTestInstanceProfile(t, svc, "loaded-profile") @@ -233,6 +247,7 @@ func TestDeleteInstanceProfile_WithRoleAttached(t *testing.T) { // ============================================================================ func TestAddRoleToInstanceProfile(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "binding-role") createTestInstanceProfile(t, svc, "binding-profile") @@ -252,6 +267,7 @@ func TestAddRoleToInstanceProfile(t *testing.T) { } func TestAddRoleToInstanceProfile_RoleNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestInstanceProfile(t, svc, "no-role-profile") @@ -264,6 +280,7 @@ func TestAddRoleToInstanceProfile_RoleNotFound(t *testing.T) { } func TestAddRoleToInstanceProfile_ProfileNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "lonely-role") @@ -276,6 +293,7 @@ func TestAddRoleToInstanceProfile_ProfileNotFound(t *testing.T) { } func TestAddRoleToInstanceProfile_OneRoleLimit(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "first-role") createTestRole(t, svc, "second-role") @@ -325,6 +343,7 @@ func runConcurrently(n int, fn func(i int) error) []error { // guard from the same revision, so the later write silently replaced the first // role. Exactly one attach may win; the loser must see LimitExceeded. func TestAddRoleToInstanceProfile_ConcurrentDistinctRoles(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) roles := []string{"race-role-a", "race-role-b"} for _, r := range roles { @@ -367,6 +386,7 @@ func TestAddRoleToInstanceProfile_ConcurrentDistinctRoles(t *testing.T) { // callers detach the same role at once and exactly one may win, the loser // re-reading an empty profile and reporting NoSuchEntity. func TestRemoveRoleFromInstanceProfile_ConcurrentDetach(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "detach-race-role") @@ -409,6 +429,7 @@ func TestRemoveRoleFromInstanceProfile_ConcurrentDetach(t *testing.T) { // same lost update: a blind Put wrote back a stale RoleName and silently // undid a role attach that had already reported success. func TestTagInstanceProfile_ConcurrentWithAttach(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "tag-race-role") @@ -446,6 +467,7 @@ func TestTagInstanceProfile_ConcurrentWithAttach(t *testing.T) { // TestTagInstanceProfile_ConcurrentDistinctKeys pins tag writes against each // other: under a blind Put all but one of the racing keys were lost. func TestTagInstanceProfile_ConcurrentDistinctKeys(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestInstanceProfile(t, svc, "tag-keys-profile") @@ -474,6 +496,7 @@ func TestTagInstanceProfile_ConcurrentDistinctKeys(t *testing.T) { } func TestRemoveRoleFromInstanceProfile(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "remove-role") createTestInstanceProfile(t, svc, "remove-profile") @@ -498,6 +521,7 @@ func TestRemoveRoleFromInstanceProfile(t *testing.T) { } func TestRemoveRoleFromInstanceProfile_NoRoleAttached(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestInstanceProfile(t, svc, "empty-profile") @@ -510,6 +534,7 @@ func TestRemoveRoleFromInstanceProfile_NoRoleAttached(t *testing.T) { } func TestRemoveRoleFromInstanceProfile_WrongRoleName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "actual-role") createTestInstanceProfile(t, svc, "wrong-name-profile") @@ -529,6 +554,7 @@ func TestRemoveRoleFromInstanceProfile_WrongRoleName(t *testing.T) { } func TestListInstanceProfilesForRole(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "popular-role") @@ -562,6 +588,7 @@ func TestListInstanceProfilesForRole(t *testing.T) { } func TestListInstanceProfilesForRole_RoleNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ListInstanceProfilesForRole(testAccountID, &iam.ListInstanceProfilesForRoleInput{ @@ -572,6 +599,7 @@ func TestListInstanceProfilesForRole_RoleNotFound(t *testing.T) { } func TestListInstanceProfilesForRole_None(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "unused-role") @@ -591,6 +619,7 @@ func TestListInstanceProfilesForRole_None(t *testing.T) { // ============================================================================ func TestResolveInstanceProfile_ByName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestInstanceProfile(t, svc, "by-name-profile") @@ -602,6 +631,7 @@ func TestResolveInstanceProfile_ByName(t *testing.T) { } func TestResolveInstanceProfile_ByARN(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestInstanceProfile(t, svc, "by-arn-profile") @@ -612,6 +642,7 @@ func TestResolveInstanceProfile_ByARN(t *testing.T) { } func TestResolveInstanceProfile_ByARNWithPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateInstanceProfile(testAccountID, &iam.CreateInstanceProfileInput{ InstanceProfileName: aws.String("nested-profile"), @@ -626,6 +657,7 @@ func TestResolveInstanceProfile_ByARNWithPath(t *testing.T) { } func TestResolveInstanceProfile_CrossAccountARNRejected(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestInstanceProfile(t, svc, "shadow-profile") @@ -636,6 +668,7 @@ func TestResolveInstanceProfile_CrossAccountARNRejected(t *testing.T) { } func TestResolveInstanceProfile_NameNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ResolveInstanceProfile(testAccountID, "ghost-profile") @@ -644,6 +677,7 @@ func TestResolveInstanceProfile_NameNotFound(t *testing.T) { } func TestResolveInstanceProfile_ARNNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) arn := "arn:aws:iam::" + testAccountID + ":instance-profile/ghost" @@ -653,6 +687,7 @@ func TestResolveInstanceProfile_ARNNotFound(t *testing.T) { } func TestResolveInstanceProfile_MalformedARN(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) cases := []string{ @@ -670,6 +705,7 @@ func TestResolveInstanceProfile_MalformedARN(t *testing.T) { } func TestResolveInstanceProfile_EmptyReference(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ResolveInstanceProfile(testAccountID, "") @@ -678,6 +714,7 @@ func TestResolveInstanceProfile_EmptyReference(t *testing.T) { } func TestInstanceProfiles_AccountScoping(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Org A") diff --git a/spinifex/handlers/iam/invariants_test.go b/spinifex/handlers/iam/invariants_test.go index 8a00e4e7d..f4bc03ff8 100644 --- a/spinifex/handlers/iam/invariants_test.go +++ b/spinifex/handlers/iam/invariants_test.go @@ -20,6 +20,7 @@ import ( // a new writer path bypassing the helpers also fails CI. func TestInvariant_AccessKeysBucket_RejectsNonAKIAPrefix(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) cases := []struct { @@ -48,6 +49,7 @@ func TestInvariant_AccessKeysBucket_RejectsNonAKIAPrefix(t *testing.T) { } func TestInvariant_AccessKeysBucket_AcceptsAKIAPrefix(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) akid := LongLivedAccessKeyIDPrefix + "0123456789ABCDEF" diff --git a/spinifex/handlers/iam/managed_policies_test.go b/spinifex/handlers/iam/managed_policies_test.go index 0ed8d86ff..d0e9fa0c6 100644 --- a/spinifex/handlers/iam/managed_policies_test.go +++ b/spinifex/handlers/iam/managed_policies_test.go @@ -24,6 +24,7 @@ var rdsInternalActions = []string{ } func TestParseBuiltinManagedPolicies(t *testing.T) { + t.Parallel() tests := []struct { name string raw map[string]string @@ -58,6 +59,7 @@ func TestParseBuiltinManagedPolicies(t *testing.T) { } } +// Serial: mutates the package-level parse error that every constructor reads. func TestNewIAMServiceImpl_PropagatesBuiltinManagedPolicyParseError(t *testing.T) { parseErr := errors.New("malformed builtin policy") previousErr := builtinManagedPolicyParseErr @@ -73,6 +75,7 @@ func TestNewIAMServiceImpl_PropagatesBuiltinManagedPolicyParseError(t *testing.T // resolve to a grant, the way the stock EKS roles already do, rather than fail // closed on a document Spinifex never stores. func TestResolveAttachedPolicy_RDSManagedShimsResolve(t *testing.T) { + t.Parallel() s := &IAMServiceImpl{} for _, arn := range []string{rdsFullAccessARN, rdsReadOnlyAccessARN} { doc, include, err := s.resolveAttachedPolicy(t.Context(), "123456789012", arn) @@ -86,6 +89,7 @@ func TestResolveAttachedPolicy_RDSManagedShimsResolve(t *testing.T) { // a path to the master password. The gateway refuses the internal actions by // principal class regardless, but GetPolicyVersion must not claim otherwise. func TestRDSManagedShims_GrantNoInternalAction(t *testing.T) { + t.Parallel() for _, arn := range []string{rdsFullAccessARN, rdsReadOnlyAccessARN} { doc, ok := builtinManagedPolicyDoc(arn) require.True(t, ok, "arn %q", arn) @@ -97,6 +101,7 @@ func TestRDSManagedShims_GrantNoInternalAction(t *testing.T) { } func TestRDSFullAccessShim_GrantsTheCustomerSurface(t *testing.T) { + t.Parallel() doc, ok := builtinManagedPolicyDoc(rdsFullAccessARN) require.True(t, ok) @@ -120,6 +125,7 @@ func TestRDSFullAccessShim_GrantsTheCustomerSurface(t *testing.T) { // Read-only means read-only: the shim is the whole grant for a role that carries // nothing else, so a mutation reaching Allow here would be the only check missed. func TestRDSReadOnlyAccessShim_GrantsReadsOnly(t *testing.T) { + t.Parallel() doc, ok := builtinManagedPolicyDoc(rdsReadOnlyAccessARN) require.True(t, ok) @@ -139,6 +145,7 @@ func TestRDSReadOnlyAccessShim_GrantsReadsOnly(t *testing.T) { // An RDS-looking managed ARN Spinifex does not model resolves to no grant rather // than an error, so a role carrying it is denied that grant and not broken. func TestResolveAttachedPolicy_UnmodeledRDSManagedARNGrantsNothing(t *testing.T) { + t.Parallel() s := &IAMServiceImpl{} for _, arn := range []string{ "arn:aws:iam::aws:policy/AmazonRDSDataFullAccess", diff --git a/spinifex/handlers/iam/oidc_providers_test.go b/spinifex/handlers/iam/oidc_providers_test.go index e7d5e2fa2..4fd810349 100644 --- a/spinifex/handlers/iam/oidc_providers_test.go +++ b/spinifex/handlers/iam/oidc_providers_test.go @@ -12,6 +12,7 @@ import ( const testIssuer = "https://10.0.0.1:9999/oidc/eks/ap-southeast-2/000000000001/h1" func TestCreateOpenIDConnectProvider(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acct := "000000000001" @@ -39,6 +40,7 @@ func TestCreateOpenIDConnectProvider(t *testing.T) { } func TestCreateOpenIDConnectProvider_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acct := "000000000001" in := &iam.CreateOpenIDConnectProviderInput{Url: aws.String(testIssuer)} @@ -53,6 +55,7 @@ func TestCreateOpenIDConnectProvider_Idempotent(t *testing.T) { } func TestCreateOpenIDConnectProvider_InvalidURL(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) for _, bad := range []string{"", "http://insecure.example", "://nohost", "ftp://x"} { _, err := svc.CreateOpenIDConnectProvider("000000000001", @@ -64,6 +67,7 @@ func TestCreateOpenIDConnectProvider_InvalidURL(t *testing.T) { } func TestGetOpenIDConnectProvider(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acct := "000000000001" created, err := svc.CreateOpenIDConnectProvider(acct, &iam.CreateOpenIDConnectProviderInput{ @@ -89,6 +93,7 @@ func TestGetOpenIDConnectProvider(t *testing.T) { } func TestGetOpenIDConnectProvider_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetOpenIDConnectProvider("000000000001", &iam.GetOpenIDConnectProviderInput{ OpenIDConnectProviderArn: aws.String(OIDCProviderARN("000000000001", "10.0.0.1:9999/oidc/eks/x/y/z")), @@ -99,6 +104,7 @@ func TestGetOpenIDConnectProvider_NotFound(t *testing.T) { } func TestListOpenIDConnectProviders(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acct := "000000000001" @@ -137,6 +143,7 @@ func TestListOpenIDConnectProviders(t *testing.T) { } func TestDeleteOpenIDConnectProvider(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) acct := "000000000001" created, err := svc.CreateOpenIDConnectProvider(acct, &iam.CreateOpenIDConnectProviderInput{Url: aws.String(testIssuer)}) @@ -160,6 +167,7 @@ func TestDeleteOpenIDConnectProvider(t *testing.T) { } func TestIssuerProviderARNRoundTrip(t *testing.T) { + t.Parallel() arn := OIDCProviderARN("000000000001", strings.TrimPrefix(testIssuer, "https://")) got, err := issuerFromOIDCProviderARN(arn) if err != nil { diff --git a/spinifex/handlers/iam/provision_test.go b/spinifex/handlers/iam/provision_test.go index a5fd17a61..0a9a9759f 100644 --- a/spinifex/handlers/iam/provision_test.go +++ b/spinifex/handlers/iam/provision_test.go @@ -26,6 +26,7 @@ func newIAMService(t *testing.T) *handlers_iam.IAMServiceImpl { } func TestNormalizeAccountName(t *testing.T) { + t.Parallel() tests := []struct { name string in string @@ -43,6 +44,7 @@ func TestNormalizeAccountName(t *testing.T) { } func TestProvisionAccountCreatesAdminIdentity(t *testing.T) { + t.Parallel() svc := newIAMService(t) got, err := handlers_iam.ProvisionAccount(svc, provisionAccountID, "ben@example.com") @@ -64,6 +66,7 @@ func TestProvisionAccountCreatesAdminIdentity(t *testing.T) { // A retry must finish the job rather than fail on the steps that already ran: // account creation has no rollback, so resuming is the only recovery path. func TestProvisionAccountResumesPartialState(t *testing.T) { + t.Parallel() tests := []struct { name string prepare func(t *testing.T, svc handlers_iam.IAMService) @@ -108,6 +111,7 @@ func TestProvisionAccountResumesPartialState(t *testing.T) { // A key from an abandoned attempt was never handed to anyone, so it must not // survive alongside the one that is. func TestProvisionAccountLeavesExactlyOneAccessKey(t *testing.T) { + t.Parallel() svc := newIAMService(t) first, err := handlers_iam.ProvisionAccount(svc, provisionAccountID, "ben@example.com") @@ -126,6 +130,7 @@ func TestProvisionAccountLeavesExactlyOneAccessKey(t *testing.T) { } func TestProvisionAccountRejectsEmptyInput(t *testing.T) { + t.Parallel() svc := newIAMService(t) _, err := handlers_iam.ProvisionAccount(svc, "", "ben@example.com") diff --git a/spinifex/handlers/iam/roles_test.go b/spinifex/handlers/iam/roles_test.go index 979ef106d..bca58a0f2 100644 --- a/spinifex/handlers/iam/roles_test.go +++ b/spinifex/handlers/iam/roles_test.go @@ -35,6 +35,7 @@ func createTestRole(t *testing.T, svc *IAMServiceImpl, name string) *iam.Role { // ============================================================================ func TestCreateRole(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -62,6 +63,7 @@ func TestCreateRole(t *testing.T) { } func TestCreateRole_DefaultPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -74,6 +76,7 @@ func TestCreateRole_DefaultPath(t *testing.T) { } func TestCreateRole_DefaultMaxSessionDuration(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -85,6 +88,7 @@ func TestCreateRole_DefaultMaxSessionDuration(t *testing.T) { } func TestCreateRole_InvalidName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) longName := strings.Repeat("a", 65) @@ -97,6 +101,7 @@ func TestCreateRole_InvalidName(t *testing.T) { } func TestCreateRole_InvalidPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -109,6 +114,7 @@ func TestCreateRole_InvalidPath(t *testing.T) { } func TestCreateRole_PermissionsBoundarySet(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -126,6 +132,7 @@ func TestCreateRole_PermissionsBoundarySet(t *testing.T) { } func TestCreateRole_PermissionsBoundaryAbsent(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) tests := []struct { @@ -151,6 +158,7 @@ func TestCreateRole_PermissionsBoundaryAbsent(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_InvalidJSON(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -162,6 +170,7 @@ func TestCreateRole_MalformedTrustPolicy_InvalidJSON(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_WrongVersion(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -173,6 +182,7 @@ func TestCreateRole_MalformedTrustPolicy_WrongVersion(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_NoStatements(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -184,6 +194,7 @@ func TestCreateRole_MalformedTrustPolicy_NoStatements(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_MissingPrincipal(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -195,6 +206,7 @@ func TestCreateRole_MalformedTrustPolicy_MissingPrincipal(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_BadEffect(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -206,6 +218,7 @@ func TestCreateRole_MalformedTrustPolicy_BadEffect(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_TooLarge(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) // Pad the Sid to push the doc past 2048 bytes. @@ -220,6 +233,7 @@ func TestCreateRole_MalformedTrustPolicy_TooLarge(t *testing.T) { } func TestCreateRole_TrustPolicy_DenyEffectAccepted(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Principal":"*","Action":"sts:AssumeRole"}]}` @@ -231,6 +245,7 @@ func TestCreateRole_TrustPolicy_DenyEffectAccepted(t *testing.T) { } func TestCreateRole_MaxSessionDuration_TooSmall(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -243,6 +258,7 @@ func TestCreateRole_MaxSessionDuration_TooSmall(t *testing.T) { } func TestCreateRole_MaxSessionDuration_TooLarge(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -255,6 +271,7 @@ func TestCreateRole_MaxSessionDuration_TooLarge(t *testing.T) { } func TestCreateRole_Duplicate(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "dup-role") @@ -267,6 +284,7 @@ func TestCreateRole_Duplicate(t *testing.T) { } func TestGetRole(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "get-role") @@ -279,6 +297,7 @@ func TestGetRole(t *testing.T) { } func TestGetRole_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetRole(testAccountID, &iam.GetRoleInput{ @@ -289,6 +308,7 @@ func TestGetRole_NotFound(t *testing.T) { } func TestListRoles(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "role1") @@ -309,6 +329,7 @@ func TestListRoles(t *testing.T) { } func TestListRoles_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.ListRoles(testAccountID, &iam.ListRolesInput{}) @@ -317,6 +338,7 @@ func TestListRoles_Empty(t *testing.T) { } func TestListRoles_PathPrefix(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{ @@ -342,6 +364,7 @@ func TestListRoles_PathPrefix(t *testing.T) { } func TestDeleteRole(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "del-role") @@ -358,6 +381,7 @@ func TestDeleteRole(t *testing.T) { } func TestDeleteRole_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DeleteRole(testAccountID, &iam.DeleteRoleInput{ @@ -368,6 +392,7 @@ func TestDeleteRole_NotFound(t *testing.T) { } func TestDeleteRole_WithAttachedPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "attached-role") policy := createTestPolicy(t, svc, "RolePolicy") @@ -386,6 +411,7 @@ func TestDeleteRole_WithAttachedPolicies(t *testing.T) { } func TestDeleteRole_InInstanceProfile(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "inprofile-role") @@ -408,6 +434,7 @@ func TestDeleteRole_InInstanceProfile(t *testing.T) { } func TestUpdateRole(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "upd-role") @@ -427,6 +454,7 @@ func TestUpdateRole(t *testing.T) { } func TestUpdateRole_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.UpdateRole(testAccountID, &iam.UpdateRoleInput{ @@ -438,6 +466,7 @@ func TestUpdateRole_NotFound(t *testing.T) { } func TestUpdateRole_InvalidMaxSessionDuration(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "session-role") @@ -450,6 +479,7 @@ func TestUpdateRole_InvalidMaxSessionDuration(t *testing.T) { } func TestUpdateAssumeRolePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "trust-role") @@ -468,6 +498,7 @@ func TestUpdateAssumeRolePolicy(t *testing.T) { } func TestUpdateAssumeRolePolicy_Malformed(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "trust-role-malformed") @@ -480,6 +511,7 @@ func TestUpdateAssumeRolePolicy_Malformed(t *testing.T) { } func TestUpdateAssumeRolePolicy_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.UpdateAssumeRolePolicy(testAccountID, &iam.UpdateAssumeRolePolicyInput{ @@ -495,6 +527,7 @@ func TestUpdateAssumeRolePolicy_NotFound(t *testing.T) { // ============================================================================ func TestAttachRolePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "attachtarget") policy := createTestPolicy(t, svc, "AttachPolicy") @@ -515,6 +548,7 @@ func TestAttachRolePolicy(t *testing.T) { } func TestAttachRolePolicy_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "idempotent") policy := createTestPolicy(t, svc, "IdempotentPolicy") @@ -539,6 +573,7 @@ func TestAttachRolePolicy_Idempotent(t *testing.T) { } func TestAttachRolePolicy_PolicyNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "needspolicy") @@ -551,6 +586,7 @@ func TestAttachRolePolicy_PolicyNotFound(t *testing.T) { } func TestAttachRolePolicy_RoleNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) policy := createTestPolicy(t, svc, "OrphanPolicy") @@ -563,6 +599,7 @@ func TestAttachRolePolicy_RoleNotFound(t *testing.T) { } func TestAttachRolePolicy_AWSManagedPolicyNotSeeded(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "eks-node-role") // AWS-managed ARN with no backing policy in the store — stock EKS tooling @@ -597,6 +634,7 @@ func TestAttachRolePolicy_AWSManagedPolicyNotSeeded(t *testing.T) { } func TestAttachRolePolicy_MalformedAWSManagedPolicyRejected(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "malformed-managed-policy") @@ -615,6 +653,7 @@ func TestAttachRolePolicy_MalformedAWSManagedPolicyRejected(t *testing.T) { } func TestDetachRolePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "detach-role") policy := createTestPolicy(t, svc, "DetachPolicy") @@ -639,6 +678,7 @@ func TestDetachRolePolicy(t *testing.T) { } func TestDetachRolePolicy_NotAttached(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "detach-empty") policy := createTestPolicy(t, svc, "NotAttachedPolicy") @@ -657,6 +697,7 @@ func TestDetachRolePolicy_NotAttached(t *testing.T) { // from the same revision and clobbered each other); the CAS path must persist // all three. func TestAttachRolePolicy_ConcurrentDistinctPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "eks-node-role") @@ -696,6 +737,7 @@ func TestAttachRolePolicy_ConcurrentDistinctPolicies(t *testing.T) { } func TestListAttachedRolePolicies_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "empty-attach") @@ -711,6 +753,7 @@ func TestListAttachedRolePolicies_Empty(t *testing.T) { // ============================================================================ func TestGetRolePolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "eval-role") p1 := createTestPolicy(t, svc, "RolePolicy1") @@ -739,6 +782,7 @@ func TestGetRolePolicies(t *testing.T) { } func TestGetRolePolicies_NoPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "bare-role") @@ -748,6 +792,7 @@ func TestGetRolePolicies_NoPolicies(t *testing.T) { } func TestGetRolePolicies_NonexistentRole(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetRolePolicies(testAccountID, "ghost-role") @@ -759,6 +804,7 @@ func TestGetRolePolicies_NonexistentRole(t *testing.T) { // referencing an attached policy ARN that can no longer be resolved must return // an error so the gateway denies rather than evaluating a partial policy set. func TestGetRolePolicies_UnresolvablePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "dangling-role") @@ -782,6 +828,7 @@ func TestGetRolePolicies_UnresolvablePolicy(t *testing.T) { // grant documents, so assumed-role authorization honours them instead of // denying every call. func TestGetRolePolicies_AWSManagedResolved(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "eks-node-role") @@ -809,6 +856,7 @@ func TestGetRolePolicies_AWSManagedResolved(t *testing.T) { // does not model resolves to no grant (fail-closed deny) rather than erroring // the whole request. func TestGetRolePolicies_UnmodeledManagedSkipped(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "unknown-managed-role") _, err := svc.AttachRolePolicy(testAccountID, &iam.AttachRolePolicyInput{ @@ -844,6 +892,7 @@ func inlineDenyDocument() string { } func TestPutRolePolicy_RoundTrip(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "inline-role") @@ -865,6 +914,7 @@ func TestPutRolePolicy_RoundTrip(t *testing.T) { } func TestPutRolePolicy_IdempotentOverwrite(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "overwrite-role") @@ -897,6 +947,7 @@ func TestPutRolePolicy_IdempotentOverwrite(t *testing.T) { } func TestPutRolePolicy_InvalidName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "badname-role") @@ -910,6 +961,7 @@ func TestPutRolePolicy_InvalidName(t *testing.T) { } func TestPutRolePolicy_MalformedDocument(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "malformed-role") @@ -923,6 +975,7 @@ func TestPutRolePolicy_MalformedDocument(t *testing.T) { } func TestPutRolePolicy_OversizedDocument(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "oversized-role") @@ -937,6 +990,7 @@ func TestPutRolePolicy_OversizedDocument(t *testing.T) { } func TestPutRolePolicy_RoleNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.PutRolePolicy(testAccountID, &iam.PutRolePolicyInput{ @@ -949,6 +1003,7 @@ func TestPutRolePolicy_RoleNotFound(t *testing.T) { } func TestGetRolePolicy_UnknownName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "get-unknown") @@ -961,6 +1016,7 @@ func TestGetRolePolicy_UnknownName(t *testing.T) { } func TestGetRolePolicy_RoleNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetRolePolicy(testAccountID, &iam.GetRolePolicyInput{ @@ -972,6 +1028,7 @@ func TestGetRolePolicy_RoleNotFound(t *testing.T) { } func TestListRolePolicies_Sorted(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "list-role") @@ -997,6 +1054,7 @@ func TestListRolePolicies_Sorted(t *testing.T) { } func TestListRolePolicies_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "empty-inline") @@ -1010,6 +1068,7 @@ func TestListRolePolicies_Empty(t *testing.T) { } func TestListRolePolicies_RoleNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ListRolePolicies(testAccountID, &iam.ListRolePoliciesInput{ @@ -1020,6 +1079,7 @@ func TestListRolePolicies_RoleNotFound(t *testing.T) { } func TestDeleteRolePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "del-inline") @@ -1051,6 +1111,7 @@ func TestDeleteRolePolicy(t *testing.T) { } func TestDeleteRolePolicy_DoubleDelete(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "double-del") @@ -1076,6 +1137,7 @@ func TestDeleteRolePolicy_DoubleDelete(t *testing.T) { } func TestDeleteRolePolicy_RoleNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DeleteRolePolicy(testAccountID, &iam.DeleteRolePolicyInput{ @@ -1087,6 +1149,7 @@ func TestDeleteRolePolicy_RoleNotFound(t *testing.T) { } func TestDeleteRole_WithInlinePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "inline-conflict") @@ -1119,6 +1182,7 @@ func TestDeleteRole_WithInlinePolicy(t *testing.T) { // TestGetRolePolicies_Inline proves the enforcement resolver walks inline // policies, not just managed attachments, so an inline statement is evaluated. func TestGetRolePolicies_Inline(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "inline-eval") @@ -1138,6 +1202,7 @@ func TestGetRolePolicies_Inline(t *testing.T) { // TestGetRolePolicies_ManagedAndInline proves managed and inline documents both // surface from the resolver in one combined set. func TestGetRolePolicies_ManagedAndInline(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) role := createTestRole(t, svc, "combined-eval") policy := createTestPolicy(t, svc, "ManagedAllow") @@ -1167,6 +1232,7 @@ func TestGetRolePolicies_ManagedAndInline(t *testing.T) { // ============================================================================ func TestRoles_AccountScoping(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Org A") @@ -1221,6 +1287,7 @@ func TestRoles_AccountScoping(t *testing.T) { // ============================================================================ func TestCreateRole_MalformedTrustPolicy_ConditionRejected_StringEquals(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole","Condition":{"StringEquals":{"sts:ExternalId":"abc"}}}]}` @@ -1233,6 +1300,7 @@ func TestCreateRole_MalformedTrustPolicy_ConditionRejected_StringEquals(t *testi } func TestCreateRole_MalformedTrustPolicy_ConditionRejected_IpAddress(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole","Condition":{"IpAddress":{"aws:SourceIp":"10.0.0.0/8"}}}]}` @@ -1245,6 +1313,7 @@ func TestCreateRole_MalformedTrustPolicy_ConditionRejected_IpAddress(t *testing. } func TestCreateRole_TrustPolicy_EmptyConditionAccepted(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) // Condition: {} is trivially empty — no field actually present at @@ -1258,6 +1327,7 @@ func TestCreateRole_TrustPolicy_EmptyConditionAccepted(t *testing.T) { } func TestCreateRole_TrustPolicy_NullConditionAccepted(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole","Condition":null}]}` @@ -1269,6 +1339,7 @@ func TestCreateRole_TrustPolicy_NullConditionAccepted(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_NotPrincipalRejected(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","NotPrincipal":{"AWS":"arn:aws:iam::123456789012:user/Bob"},"Action":"sts:AssumeRole"}]}` @@ -1281,6 +1352,7 @@ func TestCreateRole_MalformedTrustPolicy_NotPrincipalRejected(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_NotActionRejected(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"NotAction":["sts:AssumeRole"]}]}` @@ -1293,6 +1365,7 @@ func TestCreateRole_MalformedTrustPolicy_NotActionRejected(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_EmptyActionElement(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) // len(Action) > 0, but the single element is empty — the original @@ -1307,6 +1380,7 @@ func TestCreateRole_MalformedTrustPolicy_EmptyActionElement(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_EmptyPrincipalObject(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{},"Action":"sts:AssumeRole"}]}` @@ -1319,6 +1393,7 @@ func TestCreateRole_MalformedTrustPolicy_EmptyPrincipalObject(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_EmptyPrincipalArray(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":[],"Action":"sts:AssumeRole"}]}` @@ -1331,6 +1406,7 @@ func TestCreateRole_MalformedTrustPolicy_EmptyPrincipalArray(t *testing.T) { } func TestCreateRole_MalformedTrustPolicy_MultiStatementOneForbidden(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) // First statement is clean; the second carries a Condition. The whole @@ -1348,6 +1424,7 @@ func TestCreateRole_MalformedTrustPolicy_MultiStatementOneForbidden(t *testing.T } func TestUpdateAssumeRolePolicy_ConditionRejected(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "update-cond") @@ -1361,6 +1438,7 @@ func TestUpdateAssumeRolePolicy_ConditionRejected(t *testing.T) { } func TestUpdateAssumeRolePolicy_NotPrincipalRejected(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "update-notprincipal") @@ -1374,6 +1452,7 @@ func TestUpdateAssumeRolePolicy_NotPrincipalRejected(t *testing.T) { } func TestUpdateAssumeRolePolicy_NotActionRejected(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestRole(t, svc, "update-notaction") diff --git a/spinifex/handlers/iam/service_impl_test.go b/spinifex/handlers/iam/service_impl_test.go index 2b4e44007..b9a4d5df4 100644 --- a/spinifex/handlers/iam/service_impl_test.go +++ b/spinifex/handlers/iam/service_impl_test.go @@ -48,6 +48,7 @@ func createTestUser(t *testing.T, svc *IAMServiceImpl, userName string) *iam.Use // ============================================================================ func TestCreateUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateUser(testAccountID, &iam.CreateUserInput{ @@ -67,6 +68,7 @@ func TestCreateUser(t *testing.T) { } func TestCreateUser_DefaultPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreateUser(testAccountID, &iam.CreateUserInput{ @@ -77,6 +79,7 @@ func TestCreateUser_DefaultPath(t *testing.T) { } func TestCreateUser_Duplicate(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateUser(testAccountID, &iam.CreateUserInput{ @@ -92,6 +95,7 @@ func TestCreateUser_Duplicate(t *testing.T) { } func TestCreateUser_PermissionsBoundarySet(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateUser(testAccountID, &iam.CreateUserInput{ @@ -108,6 +112,7 @@ func TestCreateUser_PermissionsBoundarySet(t *testing.T) { } func TestCreateUser_PermissionsBoundaryAbsent(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) tests := []struct { @@ -132,6 +137,7 @@ func TestCreateUser_PermissionsBoundaryAbsent(t *testing.T) { } func TestGetUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "getuser") @@ -143,6 +149,7 @@ func TestGetUser(t *testing.T) { } func TestGetUser_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetUser(testAccountID, &iam.GetUserInput{ @@ -153,6 +160,7 @@ func TestGetUser_NotFound(t *testing.T) { } func TestListUsers(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "user1") @@ -173,6 +181,7 @@ func TestListUsers(t *testing.T) { } func TestListUsers_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.ListUsers(testAccountID, &iam.ListUsersInput{}) @@ -185,6 +194,7 @@ func TestListUsers_Empty(t *testing.T) { // match, so the filtering loop runs rather than the no-keys shortcut, and the // result must come back empty but non-nil. func TestListRequiredMembersAreEmptyNotNil(t *testing.T) { + t.Parallel() const otherAccountID = "999988887777" tests := []struct { @@ -271,6 +281,7 @@ func TestListRequiredMembersAreEmptyNotNil(t *testing.T) { } func TestListUsers_PathFilter(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) svc.CreateUser(testAccountID, &iam.CreateUserInput{ @@ -291,6 +302,7 @@ func TestListUsers_PathFilter(t *testing.T) { } func TestDeleteUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "deleteuser") @@ -307,6 +319,7 @@ func TestDeleteUser(t *testing.T) { } func TestDeleteUser_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DeleteUser(testAccountID, &iam.DeleteUserInput{ @@ -317,6 +330,7 @@ func TestDeleteUser_NotFound(t *testing.T) { } func TestDeleteUser_WithAccessKeys(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "userWithKeys") @@ -333,6 +347,7 @@ func TestDeleteUser_WithAccessKeys(t *testing.T) { } func TestDeleteUser_WithAttachedPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "policyuser") @@ -361,6 +376,7 @@ func TestDeleteUser_WithAttachedPolicies(t *testing.T) { // ============================================================================ func TestCreateUser_InvalidName_TooLong(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) longName := strings.Repeat("a", 65) @@ -372,6 +388,7 @@ func TestCreateUser_InvalidName_TooLong(t *testing.T) { } func TestCreateUser_InvalidName_BadChars(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateUser(testAccountID, &iam.CreateUserInput{ @@ -382,6 +399,7 @@ func TestCreateUser_InvalidName_BadChars(t *testing.T) { } func TestCreateUser_InvalidPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateUser(testAccountID, &iam.CreateUserInput{ @@ -393,6 +411,7 @@ func TestCreateUser_InvalidPath(t *testing.T) { } func TestCreatePolicy_InvalidName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) longName := strings.Repeat("a", 129) @@ -405,6 +424,7 @@ func TestCreatePolicy_InvalidName(t *testing.T) { } func TestCreatePolicy_InvalidPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -417,6 +437,7 @@ func TestCreatePolicy_InvalidPath(t *testing.T) { } func TestValidatePolicyDocument_TooLarge(t *testing.T) { + t.Parallel() largeDoc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"` + strings.Repeat("a", maxPolicyDocumentSize) + `"}]}` _, err := ValidatePolicyDocument(largeDoc) assert.Error(t, err) @@ -428,6 +449,7 @@ func TestValidatePolicyDocument_TooLarge(t *testing.T) { // ============================================================================ func TestCreateAccessKey(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "keyuser") @@ -445,6 +467,7 @@ func TestCreateAccessKey(t *testing.T) { } func TestCreateAccessKey_SecretIsDecryptable(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "decryptuser") @@ -466,6 +489,7 @@ func TestCreateAccessKey_SecretIsDecryptable(t *testing.T) { } func TestCreateAccessKey_UserNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreateAccessKey(testAccountID, &iam.CreateAccessKeyInput{ @@ -476,6 +500,7 @@ func TestCreateAccessKey_UserNotFound(t *testing.T) { } func TestCreateAccessKey_MaxLimit(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "limituser") @@ -498,6 +523,7 @@ func TestCreateAccessKey_MaxLimit(t *testing.T) { } func TestAccessKeyQuota_Recovery(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "quotauser") @@ -527,6 +553,7 @@ func TestAccessKeyQuota_Recovery(t *testing.T) { } func TestAccessKeyQuota_PerUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "user1") createTestUser(t, svc, "user2") @@ -543,6 +570,7 @@ func TestAccessKeyQuota_PerUser(t *testing.T) { } func TestListAccessKeys(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "listkeysuser") @@ -568,6 +596,7 @@ func TestListAccessKeys(t *testing.T) { } func TestDeleteAccessKey(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "delkeyuser") @@ -598,6 +627,7 @@ func TestDeleteAccessKey(t *testing.T) { } func TestDeleteAccessKey_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "delnotfounduser") @@ -610,6 +640,7 @@ func TestDeleteAccessKey_NotFound(t *testing.T) { } func TestUpdateAccessKey(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "updatekeyuser") @@ -645,6 +676,7 @@ func TestUpdateAccessKey(t *testing.T) { } func TestUpdateAccessKey_InvalidStatus(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "invalidstatususer") @@ -661,6 +693,7 @@ func TestUpdateAccessKey_InvalidStatus(t *testing.T) { } func TestUpdateAccessKey_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.UpdateAccessKey(testAccountID, &iam.UpdateAccessKeyInput{ @@ -672,6 +705,7 @@ func TestUpdateAccessKey_NotFound(t *testing.T) { } func TestUpdateAccessKey_CaseSensitiveStatus(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "caseuser") @@ -702,6 +736,7 @@ func TestUpdateAccessKey_CaseSensitiveStatus(t *testing.T) { } func TestUpdateAccessKey_CrossAccountBlocked(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) accA, err := svc.CreateAccount("Status Org A") @@ -730,6 +765,7 @@ func TestUpdateAccessKey_CrossAccountBlocked(t *testing.T) { // ============================================================================ func TestLookupAccessKey(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "lookupuser") @@ -746,6 +782,7 @@ func TestLookupAccessKey(t *testing.T) { } func TestLookupAccessKey_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.LookupAccessKey("AKIANONEXISTENT12345") @@ -754,6 +791,7 @@ func TestLookupAccessKey_NotFound(t *testing.T) { } func TestLookupAccessKey_InactiveKey(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "inactiveuser") @@ -778,6 +816,7 @@ func TestLookupAccessKey_InactiveKey(t *testing.T) { // ============================================================================ func TestSeedBootstrap(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) encryptedSecret, err := svc.key.EncryptBase64("test-secret-key") @@ -820,6 +859,7 @@ func TestSeedBootstrap(t *testing.T) { } func TestSeedBootstrap_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) encryptedSecret, _ := svc.key.EncryptBase64("test-secret") @@ -846,6 +886,7 @@ func TestSeedBootstrap_Idempotent(t *testing.T) { } func TestSeedBootstrap_WithAdmin(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) systemSecret, err := svc.key.EncryptBase64("system-secret") @@ -914,6 +955,7 @@ func TestSeedBootstrap_WithAdmin(t *testing.T) { } func TestSeedBootstrap_AdminNil_BackwardCompat(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) encryptedSecret, err := svc.key.EncryptBase64("test-secret") @@ -944,6 +986,7 @@ func TestSeedBootstrap_AdminNil_BackwardCompat(t *testing.T) { // ============================================================================ func TestIsEmpty_True(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) empty, err := svc.IsEmpty() @@ -952,6 +995,7 @@ func TestIsEmpty_True(t *testing.T) { } func TestIsEmpty_False(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "notempty") @@ -965,6 +1009,7 @@ func TestIsEmpty_False(t *testing.T) { // ============================================================================ func TestGenerateIAMID(t *testing.T) { + t.Parallel() id, err := generateIAMID("AIDA") assert.NoError(t, err) assert.Equal(t, "AIDA", id[:4]) @@ -983,6 +1028,7 @@ func TestGenerateIAMID(t *testing.T) { } func TestGenerateAccessKeyID(t *testing.T) { + t.Parallel() id, err := generateAccessKeyID() assert.NoError(t, err) assert.Equal(t, "AKIA", id[:4]) @@ -994,6 +1040,7 @@ func TestGenerateAccessKeyID(t *testing.T) { } func TestGenerateSecretAccessKey(t *testing.T) { + t.Parallel() secret, err := admin.GenerateAWSSecretKey() assert.NoError(t, err) assert.Len(t, secret, 40) @@ -1023,6 +1070,7 @@ func createTestPolicy(t *testing.T, svc *IAMServiceImpl, name string) *iam.Polic } func TestCreatePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -1045,6 +1093,7 @@ func TestCreatePolicy(t *testing.T) { } func TestCreatePolicy_DefaultPath(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -1057,6 +1106,7 @@ func TestCreatePolicy_DefaultPath(t *testing.T) { } func TestCreatePolicy_InvalidJSON(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -1068,6 +1118,7 @@ func TestCreatePolicy_InvalidJSON(t *testing.T) { } func TestCreatePolicy_InvalidVersion(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -1079,6 +1130,7 @@ func TestCreatePolicy_InvalidVersion(t *testing.T) { } func TestCreatePolicy_NoStatements(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -1090,6 +1142,7 @@ func TestCreatePolicy_NoStatements(t *testing.T) { } func TestCreatePolicy_InvalidEffect(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -1101,6 +1154,7 @@ func TestCreatePolicy_InvalidEffect(t *testing.T) { } func TestCreatePolicy_MissingAction(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -1112,6 +1166,7 @@ func TestCreatePolicy_MissingAction(t *testing.T) { } func TestCreatePolicy_MissingResource(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{ @@ -1123,6 +1178,7 @@ func TestCreatePolicy_MissingResource(t *testing.T) { } func TestCreatePolicy_Duplicate(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestPolicy(t, svc, "DupPolicy") @@ -1136,6 +1192,7 @@ func TestCreatePolicy_Duplicate(t *testing.T) { } func TestCreatePolicy_ArrayActions(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["ec2:DescribeInstances","ec2:RunInstances"],"Resource":"*"}]}` @@ -1148,6 +1205,7 @@ func TestCreatePolicy_ArrayActions(t *testing.T) { } func TestGetPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "GetMe") @@ -1163,6 +1221,7 @@ func TestGetPolicy(t *testing.T) { } func TestGetPolicy_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetPolicy(testAccountID, &iam.GetPolicyInput{ @@ -1173,6 +1232,7 @@ func TestGetPolicy_NotFound(t *testing.T) { } func TestGetPolicy_MalformedARN(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetPolicy(testAccountID, &iam.GetPolicyInput{ @@ -1183,6 +1243,7 @@ func TestGetPolicy_MalformedARN(t *testing.T) { } func TestGetPolicy_ARNParsingEdgeCases(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}` @@ -1220,6 +1281,7 @@ func TestGetPolicy_ARNParsingEdgeCases(t *testing.T) { } func TestGetPolicy_WithAttachments(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "AttachedPolicy") createTestUser(t, svc, "attachuser1") @@ -1242,6 +1304,7 @@ func TestGetPolicy_WithAttachments(t *testing.T) { } func TestGetPolicyVersion(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "VersionPolicy") @@ -1262,6 +1325,7 @@ func TestGetPolicyVersion(t *testing.T) { } func TestGetPolicyVersion_InvalidVersion(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "VersionPolicy2") @@ -1274,6 +1338,7 @@ func TestGetPolicyVersion_InvalidVersion(t *testing.T) { } func TestGetPolicyVersion_PolicyNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetPolicyVersion(testAccountID, &iam.GetPolicyVersionInput{ @@ -1285,6 +1350,7 @@ func TestGetPolicyVersion_PolicyNotFound(t *testing.T) { } func TestListPolicyVersions(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "ListVersionPolicy") @@ -1301,6 +1367,7 @@ func TestListPolicyVersions(t *testing.T) { } func TestListPolicyVersions_PolicyNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ListPolicyVersions(testAccountID, &iam.ListPolicyVersionsInput{ @@ -1311,6 +1378,7 @@ func TestListPolicyVersions_PolicyNotFound(t *testing.T) { } func TestListPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestPolicy(t, svc, "Policy1") @@ -1331,6 +1399,7 @@ func TestListPolicies(t *testing.T) { } func TestListPolicies_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) out, err := svc.ListPolicies(testAccountID, &iam.ListPoliciesInput{}) @@ -1339,6 +1408,7 @@ func TestListPolicies_Empty(t *testing.T) { } func TestDeletePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "DeleteMe") @@ -1356,6 +1426,7 @@ func TestDeletePolicy(t *testing.T) { } func TestDeletePolicy_NotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DeletePolicy(testAccountID, &iam.DeletePolicyInput{ @@ -1366,6 +1437,7 @@ func TestDeletePolicy_NotFound(t *testing.T) { } func TestDeletePolicy_AttachedConflict(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "Attached") createTestUser(t, svc, "conflictuser") @@ -1400,6 +1472,7 @@ func TestDeletePolicy_AttachedConflict(t *testing.T) { // ============================================================================ func TestAttachUserPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "AttachPolicy") createTestUser(t, svc, "attachme") @@ -1421,6 +1494,7 @@ func TestAttachUserPolicy(t *testing.T) { } func TestAttachUserPolicy_Idempotent(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "IdempotentPolicy") createTestUser(t, svc, "idempotentuser") @@ -1446,6 +1520,7 @@ func TestAttachUserPolicy_Idempotent(t *testing.T) { } func TestAttachUserPolicy_NonexistentPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "orphanuser") @@ -1458,6 +1533,7 @@ func TestAttachUserPolicy_NonexistentPolicy(t *testing.T) { } func TestAttachUserPolicy_NonexistentUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "OrphanPolicy") @@ -1470,6 +1546,7 @@ func TestAttachUserPolicy_NonexistentUser(t *testing.T) { } func TestDetachUserPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "DetachPolicy") createTestUser(t, svc, "detachme") @@ -1495,6 +1572,7 @@ func TestDetachUserPolicy(t *testing.T) { } func TestDetachUserPolicy_NotAttached(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) created := createTestPolicy(t, svc, "NeverAttached") createTestUser(t, svc, "cleanuser") @@ -1508,6 +1586,7 @@ func TestDetachUserPolicy_NotAttached(t *testing.T) { } func TestDetachUserPolicy_NonexistentUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DetachUserPolicy(testAccountID, &iam.DetachUserPolicyInput{ @@ -1519,6 +1598,7 @@ func TestDetachUserPolicy_NonexistentUser(t *testing.T) { } func TestListAttachedUserPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) p1 := createTestPolicy(t, svc, "ListPolicy1") @@ -1549,6 +1629,7 @@ func TestListAttachedUserPolicies(t *testing.T) { } func TestListAttachedUserPolicies_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "nopolicies") @@ -1560,6 +1641,7 @@ func TestListAttachedUserPolicies_Empty(t *testing.T) { } func TestListAttachedUserPolicies_NonexistentUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ListAttachedUserPolicies(testAccountID, &iam.ListAttachedUserPoliciesInput{ @@ -1574,6 +1656,7 @@ func TestListAttachedUserPolicies_NonexistentUser(t *testing.T) { // ============================================================================ func TestGetUserPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"ec2:DescribeInstances","Resource":"*"}]}` @@ -1609,6 +1692,7 @@ func TestGetUserPolicies(t *testing.T) { } func TestGetUserPolicies_NoPolicies(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "emptyuser") @@ -1618,6 +1702,7 @@ func TestGetUserPolicies_NoPolicies(t *testing.T) { } func TestGetUserPolicies_NonexistentUser(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetUserPolicies(testAccountID, "ghostuser") @@ -1630,6 +1715,7 @@ func TestGetUserPolicies_NonexistentUser(t *testing.T) { // ============================================================================ func TestValidatePolicyDocument_Valid(t *testing.T) { + t.Parallel() doc, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}`) require.NoError(t, err) assert.Equal(t, "2012-10-17", doc.Version) @@ -1638,6 +1724,7 @@ func TestValidatePolicyDocument_Valid(t *testing.T) { } func TestValidatePolicyDocument_MultipleStatements(t *testing.T) { + t.Parallel() doc, err := ValidatePolicyDocument(`{ "Version":"2012-10-17", "Statement":[ @@ -1652,41 +1739,48 @@ func TestValidatePolicyDocument_MultipleStatements(t *testing.T) { } func TestValidatePolicyDocument_BadJSON(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{broken`) assert.Error(t, err) } func TestValidatePolicyDocument_WrongVersion(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2008-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}`) assert.Error(t, err) assert.Contains(t, err.Error(), "unsupported policy version") } func TestValidatePolicyDocument_EmptyStatements(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[]}`) assert.Error(t, err) assert.Contains(t, err.Error(), "at least one statement") } func TestValidatePolicyDocument_BadEffect(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Maybe","Action":"*","Resource":"*"}]}`) assert.Error(t, err) assert.Contains(t, err.Error(), "Effect must be Allow or Deny") } func TestValidatePolicyDocument_MissingAction(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Resource":"*"}]}`) assert.Error(t, err) assert.Contains(t, err.Error(), "Action is required") } func TestValidatePolicyDocument_MissingResource(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*"}]}`) assert.Error(t, err) assert.Contains(t, err.Error(), "Resource is required") } func TestValidatePolicyDocument_SupportedCondition(t *testing.T) { + t.Parallel() doc, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*", "Condition":{"IpAddress":{"aws:SourceIp":"10.0.0.0/8"}}}]}`) require.NoError(t, err) @@ -1695,6 +1789,7 @@ func TestValidatePolicyDocument_SupportedCondition(t *testing.T) { } func TestValidatePolicyDocument_UnsupportedConditionOperator(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*", "Condition":{"StringEquals":{"aws:SourceIp":"10.0.0.1"}}}]}`) assert.Error(t, err) @@ -1702,6 +1797,7 @@ func TestValidatePolicyDocument_UnsupportedConditionOperator(t *testing.T) { } func TestValidatePolicyDocument_UnsupportedConditionKey(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*", "Condition":{"StringEquals":{"aws:PrincipalOrgID":"o-1234"}}}]}`) assert.Error(t, err) @@ -1711,6 +1807,7 @@ func TestValidatePolicyDocument_UnsupportedConditionKey(t *testing.T) { // MFA does not exist in spinifex, so this key could never be true and accepting // it would mint a grant that silently never fires. func TestValidatePolicyDocument_RejectsMFACondition(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*", "Condition":{"Bool":{"aws:MultiFactorAuthPresent":"true"}}}]}`) assert.Error(t, err) @@ -1718,6 +1815,7 @@ func TestValidatePolicyDocument_RejectsMFACondition(t *testing.T) { } func TestValidatePolicyDocument_RejectsPrincipal(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*", "Principal":{"AWS":"arn:aws:iam::123456789012:root"}}]}`) assert.Error(t, err) @@ -1725,6 +1823,7 @@ func TestValidatePolicyDocument_RejectsPrincipal(t *testing.T) { } func TestValidatePolicyDocument_RejectsNotAction(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"*","Resource":"*", "NotAction":"sts:AssumeRole"}]}`) assert.Error(t, err) @@ -1735,6 +1834,7 @@ func TestValidatePolicyDocument_RejectsNotAction(t *testing.T) { // matcher cannot parse it, so the Allow never fires and the operator gets a bare // AccessDenied with nothing naming the cause. func TestValidatePolicyDocument_RejectsMalformedConditionValues(t *testing.T) { + t.Parallel() tests := []struct { name string cond string @@ -1760,6 +1860,7 @@ func TestValidatePolicyDocument_RejectsMalformedConditionValues(t *testing.T) { // D4's lenient leaf parsing must survive at the API surface: a native JSON bool // is what Terraform emits, and rejecting it would fail ordinary valid policies. func TestValidatePolicyDocument_AcceptsNativeBoolAndCIDRForms(t *testing.T) { + t.Parallel() for _, cond := range []string{ `{"Bool":{"aws:SecureTransport":true}}`, `{"Bool":{"aws:SecureTransport":"TRUE"}}`, @@ -1775,6 +1876,7 @@ func TestValidatePolicyDocument_AcceptsNativeBoolAndCIDRForms(t *testing.T) { // Map iteration order makes a break-instead-of-continue bug non-deterministic, // so a single-operator document cannot pin the loop. func TestValidatePolicyDocument_RejectsUnsupportedAlongsideSupported(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*", "Condition":{"IpAddress":{"aws:SourceIp":"10.0.0.0/8"},"StringEquals":{"aws:PrincipalOrgID":"o-1234"}}}]}`) require.Error(t, err) @@ -1782,6 +1884,7 @@ func TestValidatePolicyDocument_RejectsUnsupportedAlongsideSupported(t *testing. } func TestValidatePolicyDocument_RejectsNotResource(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"*","Resource":"*", "NotResource":"arn:aws:s3:::public/*"}]}`) assert.Error(t, err) @@ -1792,6 +1895,9 @@ func TestValidatePolicyDocument_RejectsNotResource(t *testing.T) { // Sensitive Data Not Logged Tests // ============================================================================ +// Serial: swaps the process-wide default logger to capture output. In parallel +// a racing restore would leave this asserting against an empty buffer, which +// passes while proving nothing. func TestSensitiveDataNotLogged_CreateAccessKey(t *testing.T) { svc := setupTestIAMService(t) createTestUser(t, svc, "loguser") @@ -1823,6 +1929,7 @@ func TestSensitiveDataNotLogged_CreateAccessKey(t *testing.T) { "encrypted secret must not appear in log output") } +// Serial: swaps the process-wide default logger, as above. func TestSensitiveDataNotLogged_MasterKey(t *testing.T) { // Capture log output during service init var buf strings.Builder @@ -1852,6 +1959,7 @@ func TestSensitiveDataNotLogged_MasterKey(t *testing.T) { // ============================================================================ func TestInputValidation_UserNameLength(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) // 64 chars — should pass @@ -1866,6 +1974,7 @@ func TestInputValidation_UserNameLength(t *testing.T) { } func TestInputValidation_PolicyNameLength(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) doc := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}` @@ -1887,6 +1996,7 @@ func TestInputValidation_PolicyNameLength(t *testing.T) { } func TestInputValidation_PathLength(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) // 512 chars — should pass (path must start and end with /) @@ -1909,6 +2019,7 @@ func TestInputValidation_PathLength(t *testing.T) { } func TestInputValidation_PolicyDocumentSize(t *testing.T) { + t.Parallel() // 6144 bytes — should pass filler6144 := strings.Repeat("a", 6144-len(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"`)-len(`"}]}`)) doc6144 := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"` + filler6144 + `"}]}` @@ -1923,6 +2034,7 @@ func TestInputValidation_PolicyDocumentSize(t *testing.T) { } func TestValidatePolicyDocument_OverlappingDenyAllow(t *testing.T) { + t.Parallel() doc, err := ValidatePolicyDocument(`{ "Version":"2012-10-17", "Statement":[ @@ -1939,6 +2051,7 @@ func TestValidatePolicyDocument_OverlappingDenyAllow(t *testing.T) { } func TestValidatePolicyDocument_WithoutSid(t *testing.T) { + t.Parallel() doc, err := ValidatePolicyDocument(`{ "Version":"2012-10-17", "Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"*"}] @@ -1948,6 +2061,7 @@ func TestValidatePolicyDocument_WithoutSid(t *testing.T) { } func TestValidatePolicyDocument_ActionSingleString(t *testing.T) { + t.Parallel() doc, err := ValidatePolicyDocument(`{ "Version":"2012-10-17", "Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*"}] @@ -1957,6 +2071,7 @@ func TestValidatePolicyDocument_ActionSingleString(t *testing.T) { } func TestValidatePolicyDocument_ActionArray(t *testing.T) { + t.Parallel() doc, err := ValidatePolicyDocument(`{ "Version":"2012-10-17", "Statement":[{"Effect":"Allow","Action":["s3:Get*","s3:List*"],"Resource":"*"}] @@ -1966,6 +2081,7 @@ func TestValidatePolicyDocument_ActionArray(t *testing.T) { } func TestValidatePolicyDocument_EmptyActionArray(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{ "Version":"2012-10-17", "Statement":[{"Effect":"Allow","Action":[],"Resource":"*"}] @@ -1975,6 +2091,7 @@ func TestValidatePolicyDocument_EmptyActionArray(t *testing.T) { } func TestValidatePolicyDocument_EmptyResourceArray(t *testing.T) { + t.Parallel() _, err := ValidatePolicyDocument(`{ "Version":"2012-10-17", "Statement":[{"Effect":"Allow","Action":"s3:*","Resource":[]}] @@ -1984,6 +2101,7 @@ func TestValidatePolicyDocument_EmptyResourceArray(t *testing.T) { } func TestValidatePolicyDocument_ResourceARNFormat(t *testing.T) { + t.Parallel() doc, err := ValidatePolicyDocument(`{ "Version":"2012-10-17", "Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::my-bucket/*"}] @@ -1997,6 +2115,7 @@ func TestValidatePolicyDocument_ResourceARNFormat(t *testing.T) { // ============================================================================ func TestGeneratePolicyID(t *testing.T) { + t.Parallel() id, err := generateIAMID("ANPA") assert.NoError(t, err) assert.Equal(t, "ANPA", id[:4]) @@ -2012,6 +2131,7 @@ func TestGeneratePolicyID(t *testing.T) { // ============================================================================ func TestIsIAMNameChar(t *testing.T) { + t.Parallel() // Valid characters for _, c := range "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+=,.@-_" { assert.True(t, isIAMNameChar(byte(c)), "expected valid: %c", c) @@ -2023,6 +2143,7 @@ func TestIsIAMNameChar(t *testing.T) { } func TestValidateUserName(t *testing.T) { + t.Parallel() tests := []struct { name string input string @@ -2051,6 +2172,7 @@ func TestValidateUserName(t *testing.T) { } func TestValidatePolicyName(t *testing.T) { + t.Parallel() tests := []struct { name string input string @@ -2078,6 +2200,7 @@ func TestValidatePolicyName(t *testing.T) { } func TestValidatePath(t *testing.T) { + t.Parallel() tests := []struct { name string input string @@ -2105,6 +2228,7 @@ func TestValidatePath(t *testing.T) { } func TestParseCreatedAt(t *testing.T) { + t.Parallel() // Valid RFC3339 ts := "2024-01-15T10:30:00Z" result := parseCreatedAt(ts) @@ -2130,6 +2254,7 @@ func TestParseCreatedAt(t *testing.T) { } func TestGenerateIAMID_AllUpperHex(t *testing.T) { + t.Parallel() for range 20 { id, err := generateIAMID("AIDA") assert.NoError(t, err) @@ -2142,6 +2267,7 @@ func TestGenerateIAMID_AllUpperHex(t *testing.T) { } func TestGenerateAccessKeyID_AllUpperHex(t *testing.T) { + t.Parallel() for range 20 { id, err := generateAccessKeyID() assert.NoError(t, err) @@ -2154,6 +2280,7 @@ func TestGenerateAccessKeyID_AllUpperHex(t *testing.T) { } func TestAttachUserPolicy_AWSManagedOpaque(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "managed-user") const managedARN = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly" @@ -2175,6 +2302,7 @@ func TestAttachUserPolicy_AWSManagedOpaque(t *testing.T) { } func TestAttachUserPolicy_CustomerManagedMustExist(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "strict-user") diff --git a/spinifex/handlers/iam/system_role_test.go b/spinifex/handlers/iam/system_role_test.go index 5998efaff..a440131b0 100644 --- a/spinifex/handlers/iam/system_role_test.go +++ b/spinifex/handlers/iam/system_role_test.go @@ -22,6 +22,7 @@ const ( // TestEnsureSystemInstanceProfile_CreatesAll asserts the role (EC2 trust), inline // policy, and instance profile are all created and the profile ARN is returned. func TestEnsureSystemInstanceProfile_CreatesAll(t *testing.T) { + t.Parallel() f := iammock.New() arn, err := handlers_iam.EnsureSystemInstanceProfile(f, testRoleAcct, testRoleName, testPolicyName, testPolicyDoc) require.NoError(t, err) @@ -39,6 +40,7 @@ func TestEnsureSystemInstanceProfile_CreatesAll(t *testing.T) { // TestEnsureSystemInstanceProfile_Idempotent asserts a re-run against existing // role+profile creates nothing new but still re-asserts the inline policy. func TestEnsureSystemInstanceProfile_Idempotent(t *testing.T) { + t.Parallel() f := iammock.New() _, err := handlers_iam.EnsureSystemInstanceProfile(f, testRoleAcct, testRoleName, testPolicyName, testPolicyDoc) require.NoError(t, err) @@ -53,6 +55,7 @@ func TestEnsureSystemInstanceProfile_Idempotent(t *testing.T) { // TestConvergeSystemRolePolicy_RewritesExistingRole asserts an account that // already carries the role picks up a changed document. func TestConvergeSystemRolePolicy_RewritesExistingRole(t *testing.T) { + t.Parallel() f := iammock.New() _, err := handlers_iam.EnsureSystemInstanceProfile(f, testRoleAcct, testRoleName, testPolicyName, testPolicyDoc) require.NoError(t, err) @@ -66,6 +69,7 @@ func TestConvergeSystemRolePolicy_RewritesExistingRole(t *testing.T) { // keeps a fleet-wide converge pass from writing IAM entities into accounts that // never launched capacity: no role means nothing to converge. func TestConvergeSystemRolePolicy_AbsentRoleIsNotProvisioned(t *testing.T) { + t.Parallel() f := iammock.New() require.NoError(t, handlers_iam.ConvergeSystemRolePolicy(f, testRoleAcct, testRoleName, testPolicyName, testPolicyDoc)) @@ -78,6 +82,7 @@ func TestConvergeSystemRolePolicy_AbsentRoleIsNotProvisioned(t *testing.T) { // TestConvergeSystemRolePolicy_PropagatesPutFailure keeps a failed write a // failure: swallowing it reports a converged fleet that is not converged. func TestConvergeSystemRolePolicy_PropagatesPutFailure(t *testing.T) { + t.Parallel() f := iammock.New() _, err := handlers_iam.EnsureSystemInstanceProfile(f, testRoleAcct, testRoleName, testPolicyName, testPolicyDoc) require.NoError(t, err) diff --git a/spinifex/handlers/iam/tags_test.go b/spinifex/handlers/iam/tags_test.go index 946c02d1d..777c32b02 100644 --- a/spinifex/handlers/iam/tags_test.go +++ b/spinifex/handlers/iam/tags_test.go @@ -17,6 +17,7 @@ func sdkTag(key, value string) *iam.Tag { } func TestValidateTags(t *testing.T) { + t.Parallel() tooMany := make([]*iam.Tag, maxTagsPerResource+1) for i := range tooMany { tooMany[i] = sdkTag("key"+strings.Repeat("a", i%100+1), "v") @@ -55,6 +56,7 @@ func TestValidateTags(t *testing.T) { } func TestMergeTags(t *testing.T) { + t.Parallel() cases := []struct { name string existing []Tag @@ -91,12 +93,14 @@ func TestMergeTags(t *testing.T) { } func TestMergeTags_DoesNotMutateExisting(t *testing.T) { + t.Parallel() existing := []Tag{{Key: "a", Value: "1"}} _ = mergeTags(existing, []*iam.Tag{sdkTag("a", "9")}) assert.Equal(t, []Tag{{Key: "a", Value: "1"}}, existing) } func TestRemoveTagKeys(t *testing.T) { + t.Parallel() existing := []Tag{{Key: "a", Value: "1"}, {Key: "b", Value: "2"}, {Key: "c", Value: "3"}} cases := []struct { @@ -262,6 +266,7 @@ func tagsAsMap(tags []*iam.Tag) map[string]string { } func TestResourceTagging_RoundTrip(t *testing.T) { + t.Parallel() for _, ops := range allTagOps() { t.Run(ops.resource, func(t *testing.T) { svc := setupTestIAMService(t) @@ -292,6 +297,7 @@ func TestResourceTagging_RoundTrip(t *testing.T) { } func TestTagUser_GetUserSurfacesTags(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) user := createTestUser(t, svc, "tagme") @@ -307,6 +313,7 @@ func TestTagUser_GetUserSurfacesTags(t *testing.T) { } func TestResourceTagging_MissingEntity(t *testing.T) { + t.Parallel() for _, ops := range allTagOps() { t.Run(ops.resource, func(t *testing.T) { svc := setupTestIAMService(t) @@ -327,6 +334,7 @@ func TestResourceTagging_MissingEntity(t *testing.T) { } func TestTagUser_MergedLimitExceeded(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "taglimit") @@ -354,6 +362,7 @@ func TestTagUser_MergedLimitExceeded(t *testing.T) { } func TestTagsToSDK(t *testing.T) { + t.Parallel() assert.Nil(t, tagsToSDK(nil)) assert.Nil(t, tagsToSDK([]Tag{})) got := tagsToSDK([]Tag{{Key: "a", Value: "1"}}) diff --git a/spinifex/handlers/iam/types_test.go b/spinifex/handlers/iam/types_test.go index 00c6625a6..6948183fe 100644 --- a/spinifex/handlers/iam/types_test.go +++ b/spinifex/handlers/iam/types_test.go @@ -9,6 +9,7 @@ import ( ) func TestStringOrArr_UnmarshalSingleString(t *testing.T) { + t.Parallel() var s StringOrArr err := json.Unmarshal([]byte(`"s3:GetObject"`), &s) require.NoError(t, err) @@ -16,6 +17,7 @@ func TestStringOrArr_UnmarshalSingleString(t *testing.T) { } func TestStringOrArr_UnmarshalArray(t *testing.T) { + t.Parallel() var s StringOrArr err := json.Unmarshal([]byte(`["s3:Get*","s3:List*"]`), &s) require.NoError(t, err) @@ -23,6 +25,7 @@ func TestStringOrArr_UnmarshalArray(t *testing.T) { } func TestStringOrArr_UnmarshalNull(t *testing.T) { + t.Parallel() // A JSON null yields a nil slice (an inert field), not [""]. var s StringOrArr err := json.Unmarshal([]byte(`null`), &s) @@ -31,6 +34,7 @@ func TestStringOrArr_UnmarshalNull(t *testing.T) { } func TestStringOrArr_UnmarshalEmptyArray(t *testing.T) { + t.Parallel() var s StringOrArr err := json.Unmarshal([]byte(`[]`), &s) require.NoError(t, err) @@ -38,6 +42,7 @@ func TestStringOrArr_UnmarshalEmptyArray(t *testing.T) { } func TestStringOrArr_MarshalSingleElement(t *testing.T) { + t.Parallel() s := StringOrArr{"ec2:*"} data, err := json.Marshal(s) require.NoError(t, err) @@ -45,6 +50,7 @@ func TestStringOrArr_MarshalSingleElement(t *testing.T) { } func TestStringOrArr_MarshalMultipleElements(t *testing.T) { + t.Parallel() s := StringOrArr{"s3:Get*", "s3:Put*"} data, err := json.Marshal(s) require.NoError(t, err) @@ -52,6 +58,7 @@ func TestStringOrArr_MarshalMultipleElements(t *testing.T) { } func TestStringOrArr_RoundTrip_Single(t *testing.T) { + t.Parallel() original := StringOrArr{"iam:CreateUser"} data, err := json.Marshal(original) require.NoError(t, err) @@ -63,6 +70,7 @@ func TestStringOrArr_RoundTrip_Single(t *testing.T) { } func TestStringOrArr_RoundTrip_Array(t *testing.T) { + t.Parallel() original := StringOrArr{"ec2:Describe*", "ec2:Run*", "ec2:Stop*"} data, err := json.Marshal(original) require.NoError(t, err) diff --git a/spinifex/handlers/iam/user_inline_test.go b/spinifex/handlers/iam/user_inline_test.go index dd838ba82..f30ef8bb0 100644 --- a/spinifex/handlers/iam/user_inline_test.go +++ b/spinifex/handlers/iam/user_inline_test.go @@ -17,6 +17,7 @@ import ( // ============================================================================ func TestPutUserPolicy_RoundTrip(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "inline-user") @@ -38,6 +39,7 @@ func TestPutUserPolicy_RoundTrip(t *testing.T) { } func TestPutUserPolicy_IdempotentOverwrite(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "overwrite-user") @@ -70,6 +72,7 @@ func TestPutUserPolicy_IdempotentOverwrite(t *testing.T) { } func TestPutUserPolicy_InvalidName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "badname-user") @@ -83,6 +86,7 @@ func TestPutUserPolicy_InvalidName(t *testing.T) { } func TestPutUserPolicy_MalformedDocument(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "malformed-user") @@ -96,6 +100,7 @@ func TestPutUserPolicy_MalformedDocument(t *testing.T) { } func TestPutUserPolicy_OversizedDocument(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "oversized-user") @@ -110,6 +115,7 @@ func TestPutUserPolicy_OversizedDocument(t *testing.T) { } func TestPutUserPolicy_UserNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.PutUserPolicy(testAccountID, &iam.PutUserPolicyInput{ @@ -122,6 +128,7 @@ func TestPutUserPolicy_UserNotFound(t *testing.T) { } func TestGetUserPolicy_UnknownName(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "get-unknown") @@ -134,6 +141,7 @@ func TestGetUserPolicy_UnknownName(t *testing.T) { } func TestGetUserPolicy_UserNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.GetUserPolicy(testAccountID, &iam.GetUserPolicyInput{ @@ -145,6 +153,7 @@ func TestGetUserPolicy_UserNotFound(t *testing.T) { } func TestListUserPolicies_Sorted(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "list-user") @@ -170,6 +179,7 @@ func TestListUserPolicies_Sorted(t *testing.T) { } func TestListUserPolicies_Empty(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "empty-inline-user") @@ -183,6 +193,7 @@ func TestListUserPolicies_Empty(t *testing.T) { } func TestListUserPolicies_UserNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.ListUserPolicies(testAccountID, &iam.ListUserPoliciesInput{ @@ -193,6 +204,7 @@ func TestListUserPolicies_UserNotFound(t *testing.T) { } func TestDeleteUserPolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "del-inline-user") @@ -224,6 +236,7 @@ func TestDeleteUserPolicy(t *testing.T) { } func TestDeleteUserPolicy_DoubleDelete(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "double-del-user") @@ -249,6 +262,7 @@ func TestDeleteUserPolicy_DoubleDelete(t *testing.T) { } func TestDeleteUserPolicy_UserNotFound(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) _, err := svc.DeleteUserPolicy(testAccountID, &iam.DeleteUserPolicyInput{ @@ -285,6 +299,7 @@ func putRawUserInlinePolicy(t *testing.T, svc *IAMServiceImpl, userName, policyN // stop contributing once the inline policy is removed. Without this, put-user-policy // appears to succeed while granting nothing — a silent no-op. func TestGetUserPolicies_UserInlineEnforced(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "quinn") @@ -323,6 +338,7 @@ func TestGetUserPolicies_UserInlineEnforced(t *testing.T) { // set — inline grants supplement managed grants rather than replacing them, so a // deny-wins evaluator can honour an inline Deny alongside a managed Allow. func TestGetUserPolicies_UserManagedAndInline(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "rita") managed := createTestPolicy(t, svc, "ManagedGrant") @@ -351,6 +367,7 @@ func TestGetUserPolicies_UserManagedAndInline(t *testing.T) { // document on a user fails the whole resolution closed rather than silently // dropping the grant source, mirroring the group-inline handling. func TestGetUserPolicies_UserInlineMalformedFailsClosed(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "sam") @@ -367,6 +384,7 @@ func TestGetUserPolicies_UserInlineMalformedFailsClosed(t *testing.T) { // TestDeleteUser_WithInlinePolicy proves a user carrying an inline policy refuses // deletion until the inline policy is removed, mirroring DeleteGroup. func TestDeleteUser_WithInlinePolicy(t *testing.T) { + t.Parallel() svc := setupTestIAMService(t) createTestUser(t, svc, "inline-conflict-user")