fix: run the vpc, elbv2 and iam handler tests in parallel

This commit is contained in:
Julian Sommer
2026-09-01 12:32:27 +10:00
parent d143757598
commit 6c68c236aa
60 changed files with 1228 additions and 1 deletions
@@ -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)
@@ -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")
@@ -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")
@@ -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")
@@ -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)
+68
View File
@@ -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")
@@ -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",
+13
View File
@@ -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")))
@@ -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(), "")
@@ -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")
@@ -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")
@@ -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{
@@ -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{
@@ -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
+11
View File
@@ -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,
@@ -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
+9
View File
@@ -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)
@@ -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"
@@ -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"})
+15
View File
@@ -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",
@@ -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
+3
View File
@@ -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))
}
@@ -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.
@@ -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{
+13
View File
@@ -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))
+3 -1
View File
@@ -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()
}
@@ -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{
@@ -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")
@@ -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")
@@ -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)
@@ -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)
@@ -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{
@@ -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)
@@ -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),
@@ -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",
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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)
@@ -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{
+14
View File
@@ -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
@@ -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()
+1
View File
@@ -7,6 +7,7 @@ import (
)
func TestDefaultHealthCheck(t *testing.T) {
t.Parallel()
hc := DefaultHealthCheck()
assert.Equal(t, ProtocolHTTP, hc.Protocol)
@@ -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()
@@ -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()
@@ -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")
+15
View File
@@ -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()
@@ -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":"*"}]}`
+19
View File
@@ -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==",
+62
View File
@@ -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")
@@ -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")
+2
View File
@@ -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"
@@ -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",
@@ -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 {
+5
View File
@@ -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")
+79
View File
@@ -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")
+128
View File
@@ -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")
@@ -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)
+9
View File
@@ -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"}})
+8
View File
@@ -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)
+18
View File
@@ -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")