fix: test coverage

This commit is contained in:
Julian Sommer
2026-03-27 09:04:21 +10:00
parent 5bfc680a68
commit 8ea40a1973
10 changed files with 925 additions and 0 deletions
@@ -0,0 +1,55 @@
package gateway_ec2_instance
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/awserrors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDescribeInstanceCreditSpecifications_NilInput(t *testing.T) {
out, err := DescribeInstanceCreditSpecifications(nil)
require.Error(t, err)
assert.Nil(t, out)
assert.Equal(t, awserrors.ErrorInvalidParameterValue, err.Error())
}
func TestDescribeInstanceCreditSpecifications_EmptyInstanceIds(t *testing.T) {
out, err := DescribeInstanceCreditSpecifications(&ec2.DescribeInstanceCreditSpecificationsInput{})
require.NoError(t, err)
assert.Empty(t, out.InstanceCreditSpecifications)
}
func TestDescribeInstanceCreditSpecifications_SingleInstance(t *testing.T) {
out, err := DescribeInstanceCreditSpecifications(&ec2.DescribeInstanceCreditSpecificationsInput{
InstanceIds: []*string{aws.String("i-abc123")},
})
require.NoError(t, err)
require.Len(t, out.InstanceCreditSpecifications, 1)
assert.Equal(t, "i-abc123", *out.InstanceCreditSpecifications[0].InstanceId)
assert.Equal(t, "standard", *out.InstanceCreditSpecifications[0].CpuCredits)
}
func TestDescribeInstanceCreditSpecifications_MultipleInstances(t *testing.T) {
out, err := DescribeInstanceCreditSpecifications(&ec2.DescribeInstanceCreditSpecificationsInput{
InstanceIds: []*string{aws.String("i-aaa"), aws.String("i-bbb"), aws.String("i-ccc")},
})
require.NoError(t, err)
require.Len(t, out.InstanceCreditSpecifications, 3)
for _, spec := range out.InstanceCreditSpecifications {
assert.Equal(t, "standard", *spec.CpuCredits)
}
}
func TestDescribeInstanceCreditSpecifications_SkipsNilAndEmpty(t *testing.T) {
out, err := DescribeInstanceCreditSpecifications(&ec2.DescribeInstanceCreditSpecificationsInput{
InstanceIds: []*string{nil, aws.String(""), aws.String("i-valid"), nil, aws.String("i-also")},
})
require.NoError(t, err)
require.Len(t, out.InstanceCreditSpecifications, 2)
assert.Equal(t, "i-valid", *out.InstanceCreditSpecifications[0].InstanceId)
assert.Equal(t, "i-also", *out.InstanceCreditSpecifications[1].InstanceId)
}
+47
View File
@@ -0,0 +1,47 @@
package gateway_ec2_natgw
import (
"testing"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/awserrors"
"github.com/stretchr/testify/assert"
)
const testAccountID = "123456789012"
// CreateNatGateway tests
func TestCreateNatGateway_NilInput(t *testing.T) {
_, err := CreateNatGateway(nil, nil, testAccountID)
assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue)
}
func TestCreateNatGateway_NilNATS(t *testing.T) {
_, err := CreateNatGateway(&ec2.CreateNatGatewayInput{}, nil, testAccountID)
assert.Error(t, err)
}
// DeleteNatGateway tests
func TestDeleteNatGateway_NilInput(t *testing.T) {
_, err := DeleteNatGateway(nil, nil, testAccountID)
assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue)
}
func TestDeleteNatGateway_NilNATS(t *testing.T) {
_, err := DeleteNatGateway(&ec2.DeleteNatGatewayInput{}, nil, testAccountID)
assert.Error(t, err)
}
// DescribeNatGateways tests
func TestDescribeNatGateways_NilInput(t *testing.T) {
_, err := DescribeNatGateways(nil, nil, testAccountID)
assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue)
}
func TestDescribeNatGateways_NilNATS(t *testing.T) {
_, err := DescribeNatGateways(&ec2.DescribeNatGatewaysInput{}, nil, testAccountID)
assert.Error(t, err)
}
@@ -0,0 +1,34 @@
package gateway_ec2_vpc
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mulgadc/spinifex/spinifex/awserrors"
"github.com/stretchr/testify/assert"
)
func TestModifyNetworkInterfaceAttribute_NilInput(t *testing.T) {
_, err := ModifyNetworkInterfaceAttribute(nil, nil, "123456789012")
assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue)
}
func TestModifyNetworkInterfaceAttribute_NilNetworkInterfaceId(t *testing.T) {
_, err := ModifyNetworkInterfaceAttribute(&ec2.ModifyNetworkInterfaceAttributeInput{}, nil, "123456789012")
assert.EqualError(t, err, awserrors.ErrorMissingParameter)
}
func TestModifyNetworkInterfaceAttribute_EmptyNetworkInterfaceId(t *testing.T) {
_, err := ModifyNetworkInterfaceAttribute(&ec2.ModifyNetworkInterfaceAttributeInput{
NetworkInterfaceId: aws.String(""),
}, nil, "123456789012")
assert.EqualError(t, err, awserrors.ErrorMissingParameter)
}
func TestModifyNetworkInterfaceAttribute_NilNATS(t *testing.T) {
_, err := ModifyNetworkInterfaceAttribute(&ec2.ModifyNetworkInterfaceAttributeInput{
NetworkInterfaceId: aws.String("eni-abc123"),
}, nil, "123456789012")
assert.Error(t, err)
}
@@ -0,0 +1,33 @@
package handlers_ec2_instance
import (
"testing"
"github.com/stretchr/testify/assert"
)
// --- generateNetworkConfig ---
func TestGenerateNetworkConfig_BothEmpty(t *testing.T) {
cfg := generateNetworkConfig("", "")
assert.Equal(t, cloudInitNetworkConfigWildcard, cfg)
}
func TestGenerateNetworkConfig_OneEmpty(t *testing.T) {
cfg := generateNetworkConfig("02:00:00:aa:bb:cc", "")
assert.Equal(t, cloudInitNetworkConfigWildcard, cfg, "should fall back to wildcard if devMAC empty")
cfg = generateNetworkConfig("", "02:00:00:dd:ee:ff")
assert.Equal(t, cloudInitNetworkConfigWildcard, cfg, "should fall back to wildcard if eniMAC empty")
}
func TestGenerateNetworkConfig_DualNIC(t *testing.T) {
cfg := generateNetworkConfig("02:00:00:aa:bb:cc", "02:00:00:dd:ee:ff")
assert.Contains(t, cfg, "version: 2")
assert.Contains(t, cfg, `macaddress: "02:00:00:aa:bb:cc"`)
assert.Contains(t, cfg, `macaddress: "02:00:00:dd:ee:ff"`)
assert.Contains(t, cfg, "use-routes: false")
assert.Contains(t, cfg, "use-dns: false")
assert.Contains(t, cfg, "vpc0:")
assert.Contains(t, cfg, "dev0:")
}
@@ -0,0 +1,69 @@
package handlers_ec2_natgw
import (
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// --- recordToEC2 ---
func TestRecordToEC2_Basic(t *testing.T) {
now := time.Now()
record := &NatGatewayRecord{
NatGatewayId: "nat-abc",
VpcId: "vpc-1",
SubnetId: "subnet-1",
State: "available",
AccountID: "111222333444",
CreatedAt: now,
}
ngw := recordToEC2(record)
assert.Equal(t, "nat-abc", *ngw.NatGatewayId)
assert.Equal(t, "vpc-1", *ngw.VpcId)
assert.Equal(t, "subnet-1", *ngw.SubnetId)
assert.Equal(t, "available", *ngw.State)
assert.Equal(t, "public", *ngw.ConnectivityType)
assert.Equal(t, now, *ngw.CreateTime)
assert.Empty(t, ngw.NatGatewayAddresses, "no addresses when PublicIp empty")
assert.Empty(t, ngw.Tags)
}
func TestRecordToEC2_WithPublicIp(t *testing.T) {
record := &NatGatewayRecord{
NatGatewayId: "nat-1",
VpcId: "vpc-1",
SubnetId: "subnet-1",
AllocationId: "eipalloc-abc",
PublicIp: "54.1.2.3",
State: "available",
CreatedAt: time.Now(),
}
ngw := recordToEC2(record)
require.Len(t, ngw.NatGatewayAddresses, 1)
assert.Equal(t, "eipalloc-abc", *ngw.NatGatewayAddresses[0].AllocationId)
assert.Equal(t, "54.1.2.3", *ngw.NatGatewayAddresses[0].PublicIp)
}
func TestRecordToEC2_WithTags(t *testing.T) {
record := &NatGatewayRecord{
NatGatewayId: "nat-1",
VpcId: "vpc-1",
SubnetId: "subnet-1",
State: "available",
Tags: map[string]string{"Name": "my-nat", "env": "test"},
CreatedAt: time.Now(),
}
ngw := recordToEC2(record)
require.Len(t, ngw.Tags, 2)
tagMap := make(map[string]string)
for _, tag := range ngw.Tags {
tagMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value)
}
assert.Equal(t, "my-nat", tagMap["Name"])
assert.Equal(t, "test", tagMap["env"])
}
@@ -0,0 +1,245 @@
package handlers_ec2_routetable
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// --- containsString ---
func TestContainsString_Found(t *testing.T) {
assert.True(t, containsString([]string{"a", "b", "c"}, "b"))
}
func TestContainsString_NotFound(t *testing.T) {
assert.False(t, containsString([]string{"a", "b", "c"}, "d"))
}
func TestContainsString_EmptySlice(t *testing.T) {
assert.False(t, containsString([]string{}, "a"))
}
func TestContainsString_NilSlice(t *testing.T) {
assert.False(t, containsString(nil, "a"))
}
// --- matchesFilters ---
func TestMatchesFilters_EmptyFilters(t *testing.T) {
record := &RouteTableRecord{RouteTableId: "rtb-1", VpcId: "vpc-1"}
assert.True(t, matchesFilters(record, map[string][]string{}))
}
func TestMatchesFilters_VpcId(t *testing.T) {
record := &RouteTableRecord{RouteTableId: "rtb-1", VpcId: "vpc-aaa"}
assert.True(t, matchesFilters(record, map[string][]string{"vpc-id": {"vpc-aaa"}}))
assert.False(t, matchesFilters(record, map[string][]string{"vpc-id": {"vpc-bbb"}}))
}
func TestMatchesFilters_RouteTableId(t *testing.T) {
record := &RouteTableRecord{RouteTableId: "rtb-xyz", VpcId: "vpc-1"}
assert.True(t, matchesFilters(record, map[string][]string{"route-table-id": {"rtb-xyz"}}))
assert.False(t, matchesFilters(record, map[string][]string{"route-table-id": {"rtb-other"}}))
}
func TestMatchesFilters_AssociationMain_True(t *testing.T) {
record := &RouteTableRecord{
Associations: []AssociationRecord{
{AssociationId: "rtbassoc-1", Main: true},
},
}
assert.True(t, matchesFilters(record, map[string][]string{"association.main": {"true"}}))
assert.False(t, matchesFilters(record, map[string][]string{"association.main": {"false"}}))
}
func TestMatchesFilters_AssociationMain_False(t *testing.T) {
record := &RouteTableRecord{
Associations: []AssociationRecord{
{AssociationId: "rtbassoc-1", Main: false},
},
}
assert.False(t, matchesFilters(record, map[string][]string{"association.main": {"true"}}))
}
func TestMatchesFilters_AssociationId(t *testing.T) {
record := &RouteTableRecord{
Associations: []AssociationRecord{
{AssociationId: "rtbassoc-abc"},
},
}
assert.True(t, matchesFilters(record, map[string][]string{
"association.route-table-association-id": {"rtbassoc-abc"},
}))
assert.False(t, matchesFilters(record, map[string][]string{
"association.route-table-association-id": {"rtbassoc-other"},
}))
}
func TestMatchesFilters_AssociationSubnetId(t *testing.T) {
record := &RouteTableRecord{
Associations: []AssociationRecord{
{AssociationId: "rtbassoc-1", SubnetId: "subnet-aaa"},
},
}
assert.True(t, matchesFilters(record, map[string][]string{
"association.subnet-id": {"subnet-aaa"},
}))
assert.False(t, matchesFilters(record, map[string][]string{
"association.subnet-id": {"subnet-bbb"},
}))
}
func TestMatchesFilters_RouteDestinationCidr(t *testing.T) {
record := &RouteTableRecord{
Routes: []RouteRecord{
{DestinationCidrBlock: "10.0.0.0/16", GatewayId: "local", State: "active"},
{DestinationCidrBlock: "0.0.0.0/0", GatewayId: "igw-123", State: "active"},
},
}
assert.True(t, matchesFilters(record, map[string][]string{
"route.destination-cidr-block": {"0.0.0.0/0"},
}))
assert.False(t, matchesFilters(record, map[string][]string{
"route.destination-cidr-block": {"192.168.0.0/16"},
}))
}
func TestMatchesFilters_RouteGatewayId(t *testing.T) {
record := &RouteTableRecord{
Routes: []RouteRecord{
{DestinationCidrBlock: "0.0.0.0/0", GatewayId: "igw-abc", State: "active"},
},
}
assert.True(t, matchesFilters(record, map[string][]string{
"route.gateway-id": {"igw-abc"},
}))
assert.False(t, matchesFilters(record, map[string][]string{
"route.gateway-id": {"igw-other"},
}))
}
func TestMatchesFilters_MultipleFilters(t *testing.T) {
record := &RouteTableRecord{
RouteTableId: "rtb-1",
VpcId: "vpc-aaa",
Routes: []RouteRecord{
{DestinationCidrBlock: "0.0.0.0/0", GatewayId: "igw-123", State: "active"},
},
}
// Both match -> true
assert.True(t, matchesFilters(record, map[string][]string{
"vpc-id": {"vpc-aaa"},
"route.gateway-id": {"igw-123"},
}))
// One mismatches -> false
assert.False(t, matchesFilters(record, map[string][]string{
"vpc-id": {"vpc-aaa"},
"route.gateway-id": {"igw-other"},
}))
}
func TestMatchesFilters_MultipleValues(t *testing.T) {
record := &RouteTableRecord{VpcId: "vpc-bbb"}
assert.True(t, matchesFilters(record, map[string][]string{
"vpc-id": {"vpc-aaa", "vpc-bbb", "vpc-ccc"},
}))
}
func TestMatchesFilters_NoAssociations(t *testing.T) {
record := &RouteTableRecord{RouteTableId: "rtb-1"}
assert.False(t, matchesFilters(record, map[string][]string{
"association.subnet-id": {"subnet-1"},
}))
}
func TestMatchesFilters_NoRoutes(t *testing.T) {
record := &RouteTableRecord{RouteTableId: "rtb-1"}
assert.False(t, matchesFilters(record, map[string][]string{
"route.destination-cidr-block": {"0.0.0.0/0"},
}))
}
// --- recordToEC2 ---
func TestRecordToEC2_Basic(t *testing.T) {
record := &RouteTableRecord{
RouteTableId: "rtb-abc",
VpcId: "vpc-123",
AccountID: "111222333444",
}
rtb := recordToEC2(record)
assert.Equal(t, "rtb-abc", *rtb.RouteTableId)
assert.Equal(t, "vpc-123", *rtb.VpcId)
assert.Equal(t, "111222333444", *rtb.OwnerId)
assert.Empty(t, rtb.Routes)
assert.Empty(t, rtb.Associations)
assert.Empty(t, rtb.Tags)
}
func TestRecordToEC2_Routes(t *testing.T) {
record := &RouteTableRecord{
RouteTableId: "rtb-1",
VpcId: "vpc-1",
AccountID: "acct",
Routes: []RouteRecord{
{DestinationCidrBlock: "10.0.0.0/16", GatewayId: "local", State: "active", Origin: "CreateRouteTable"},
{DestinationCidrBlock: "0.0.0.0/0", GatewayId: "igw-123", State: "active", Origin: "CreateRoute"},
{DestinationCidrBlock: "192.168.0.0/16", NatGatewayId: "nat-abc", State: "active", Origin: "CreateRoute"},
},
}
rtb := recordToEC2(record)
require.Len(t, rtb.Routes, 3)
assert.Equal(t, "10.0.0.0/16", *rtb.Routes[0].DestinationCidrBlock)
assert.Equal(t, "local", *rtb.Routes[0].GatewayId)
assert.Nil(t, rtb.Routes[0].NatGatewayId)
assert.Equal(t, "igw-123", *rtb.Routes[1].GatewayId)
assert.Equal(t, "nat-abc", *rtb.Routes[2].NatGatewayId)
assert.Nil(t, rtb.Routes[2].GatewayId)
}
func TestRecordToEC2_Associations(t *testing.T) {
record := &RouteTableRecord{
RouteTableId: "rtb-1",
VpcId: "vpc-1",
AccountID: "acct",
Associations: []AssociationRecord{
{AssociationId: "rtbassoc-main", Main: true},
{AssociationId: "rtbassoc-sub", SubnetId: "subnet-aaa", Main: false},
},
}
rtb := recordToEC2(record)
require.Len(t, rtb.Associations, 2)
assert.Equal(t, "rtbassoc-main", *rtb.Associations[0].RouteTableAssociationId)
assert.True(t, *rtb.Associations[0].Main)
assert.Nil(t, rtb.Associations[0].SubnetId)
assert.Equal(t, "associated", *rtb.Associations[0].AssociationState.State)
assert.Equal(t, "rtbassoc-sub", *rtb.Associations[1].RouteTableAssociationId)
assert.False(t, *rtb.Associations[1].Main)
assert.Equal(t, "subnet-aaa", *rtb.Associations[1].SubnetId)
}
func TestRecordToEC2_Tags(t *testing.T) {
record := &RouteTableRecord{
RouteTableId: "rtb-1",
VpcId: "vpc-1",
AccountID: "acct",
Tags: map[string]string{"Name": "my-rt", "env": "prod"},
}
rtb := recordToEC2(record)
require.Len(t, rtb.Tags, 2)
tagMap := make(map[string]string)
for _, tag := range rtb.Tags {
tagMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value)
}
assert.Equal(t, "my-rt", tagMap["Name"])
assert.Equal(t, "prod", tagMap["env"])
}
+32
View File
@@ -0,0 +1,32 @@
package handlers_ec2_vpc
import (
"regexp"
"testing"
"github.com/stretchr/testify/assert"
)
func TestGenerateENIMac_Deterministic(t *testing.T) {
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) {
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) {
mac := generateENIMac("eni-test123")
// Must start with 02:00:00 (locally-administered unicast)
assert.Regexp(t, regexp.MustCompile(`^02:00:00:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}$`), mac)
}
func TestGenerateENIMac_EmptyString(t *testing.T) {
mac := generateENIMac("")
// Hash of empty string = 0, so all three octets should be 00
assert.Equal(t, "02:00:00:00:00:00", mac)
}
+36
View File
@@ -0,0 +1,36 @@
package handlers_elbv2
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestBuildLBArn(t *testing.T) {
arn := buildLBArn("us-east-1", "123456789012", "my-alb", "50dc6c495c0c9188")
assert.Equal(t, "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/50dc6c495c0c9188", arn)
}
func TestBuildTGArn(t *testing.T) {
arn := buildTGArn("us-west-2", "111222333444", "my-tg", "deadbeef")
assert.Equal(t, "arn:aws:elasticloadbalancing:us-west-2:111222333444:targetgroup/my-tg/deadbeef", arn)
}
func TestBuildListenerArn(t *testing.T) {
arn := buildListenerArn("eu-west-1", "999888777666", "my-alb", "lbid123", "listener456")
assert.Equal(t, "arn:aws:elasticloadbalancing:eu-west-1:999888777666:listener/app/my-alb/lbid123/listener456", arn)
}
func TestAlbVMUserData_DefaultNatsURL(t *testing.T) {
ud := albVMUserData("lb-abc123", "")
assert.Contains(t, ud, "#cloud-config")
assert.Contains(t, ud, "--lb-id=lb-abc123")
assert.Contains(t, ud, "--nats=nats://127.0.0.1:4222")
}
func TestAlbVMUserData_CustomNatsURL(t *testing.T) {
ud := albVMUserData("lb-xyz", "nats://10.0.0.5:4222")
assert.Contains(t, ud, "--lb-id=lb-xyz")
assert.Contains(t, ud, "--nats=nats://10.0.0.5:4222")
assert.NotContains(t, ud, "127.0.0.1")
}
+297
View File
@@ -0,0 +1,297 @@
package handlers_elbv2
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// --- CreateTargetGroup: all health check fields + target type + tags ---
func TestCreateTargetGroup_AllHealthCheckFields(t *testing.T) {
svc := setupTestService(t)
out, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{
Name: aws.String("full-hc"),
Port: aws.Int64(8080),
Protocol: aws.String("HTTPS"),
VpcId: aws.String("vpc-123"),
TargetType: aws.String("ip"),
HealthCheckProtocol: aws.String("HTTPS"),
HealthCheckPort: aws.String("8443"),
HealthCheckPath: aws.String("/health"),
HealthCheckIntervalSeconds: aws.Int64(15),
HealthCheckTimeoutSeconds: aws.Int64(5),
HealthyThresholdCount: aws.Int64(3),
UnhealthyThresholdCount: aws.Int64(2),
Matcher: &elbv2.Matcher{HttpCode: aws.String("200")},
Tags: []*elbv2.Tag{
{Key: aws.String("env"), Value: aws.String("prod")},
{Key: aws.String("team"), Value: aws.String("platform")},
},
}, testAccountID)
require.NoError(t, err)
tg := out.TargetGroups[0]
assert.Equal(t, "ip", *tg.TargetType)
assert.Equal(t, "HTTPS", *tg.HealthCheckProtocol)
assert.Equal(t, "8443", *tg.HealthCheckPort)
assert.Equal(t, "/health", *tg.HealthCheckPath)
assert.Equal(t, int64(15), *tg.HealthCheckIntervalSeconds)
assert.Equal(t, int64(5), *tg.HealthCheckTimeoutSeconds)
assert.Equal(t, int64(3), *tg.HealthyThresholdCount)
assert.Equal(t, int64(2), *tg.UnhealthyThresholdCount)
assert.Equal(t, "200", *tg.Matcher.HttpCode)
assert.Equal(t, int64(8080), *tg.Port)
assert.Equal(t, "vpc-123", *tg.VpcId)
}
// --- DescribeLoadBalancers: ARN filter ---
func TestDescribeLoadBalancers_FilterByArn(t *testing.T) {
svc := setupTestService(t)
out1, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-arn-a")}, testAccountID)
_, _ = svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-arn-b")}, testAccountID)
desc, err := svc.DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{
LoadBalancerArns: []*string{out1.LoadBalancers[0].LoadBalancerArn},
}, testAccountID)
require.NoError(t, err)
require.Len(t, desc.LoadBalancers, 1)
assert.Equal(t, "lb-arn-a", *desc.LoadBalancers[0].LoadBalancerName)
}
// --- DescribeTargetGroups: by name ---
func TestDescribeTargetGroups_FilterByName(t *testing.T) {
svc := setupTestService(t)
_, _ = svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-alpha")}, testAccountID)
_, _ = svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-beta")}, testAccountID)
desc, err := svc.DescribeTargetGroups(&elbv2.DescribeTargetGroupsInput{
Names: []*string{aws.String("tg-alpha")},
}, testAccountID)
require.NoError(t, err)
require.Len(t, desc.TargetGroups, 1)
assert.Equal(t, "tg-alpha", *desc.TargetGroups[0].TargetGroupName)
}
// --- DescribeTargetGroups: by ARN ---
func TestDescribeTargetGroups_FilterByArn(t *testing.T) {
svc := setupTestService(t)
out1, _ := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-arn-a")}, testAccountID)
_, _ = svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-arn-b")}, testAccountID)
desc, err := svc.DescribeTargetGroups(&elbv2.DescribeTargetGroupsInput{
TargetGroupArns: []*string{out1.TargetGroups[0].TargetGroupArn},
}, testAccountID)
require.NoError(t, err)
require.Len(t, desc.TargetGroups, 1)
assert.Equal(t, "tg-arn-a", *desc.TargetGroups[0].TargetGroupName)
}
// --- DescribeListeners: filter by listener ARN ---
func TestDescribeListeners_FilterByListenerArn(t *testing.T) {
svc := setupTestService(t)
lb, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-larn")}, testAccountID)
tg, _ := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-larn")}, testAccountID)
l1, _ := svc.CreateListener(&elbv2.CreateListenerInput{
LoadBalancerArn: lb.LoadBalancers[0].LoadBalancerArn,
Port: aws.Int64(80),
DefaultActions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tg.TargetGroups[0].TargetGroupArn}},
}, testAccountID)
_, _ = svc.CreateListener(&elbv2.CreateListenerInput{
LoadBalancerArn: lb.LoadBalancers[0].LoadBalancerArn,
Port: aws.Int64(443),
DefaultActions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tg.TargetGroups[0].TargetGroupArn}},
}, testAccountID)
desc, err := svc.DescribeListeners(&elbv2.DescribeListenersInput{
ListenerArns: []*string{l1.Listeners[0].ListenerArn},
}, testAccountID)
require.NoError(t, err)
require.Len(t, desc.Listeners, 1)
assert.Equal(t, int64(80), *desc.Listeners[0].Port)
}
// --- RegisterTargets: nil target id skipped ---
func TestRegisterTargets_NilTargetSkipped(t *testing.T) {
svc := setupTestService(t)
tg, _ := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-nil"), Port: aws.Int64(80)}, testAccountID)
_, err := svc.RegisterTargets(&elbv2.RegisterTargetsInput{
TargetGroupArn: tg.TargetGroups[0].TargetGroupArn,
Targets: []*elbv2.TargetDescription{
{Id: nil},
{Id: aws.String("i-valid")},
},
}, testAccountID)
require.NoError(t, err)
health, _ := svc.DescribeTargetHealth(&elbv2.DescribeTargetHealthInput{
TargetGroupArn: tg.TargetGroups[0].TargetGroupArn,
}, testAccountID)
require.Len(t, health.TargetHealthDescriptions, 1)
assert.Equal(t, "i-valid", *health.TargetHealthDescriptions[0].Target.Id)
}
// --- RegisterTargets / DeregisterTargets: missing ARN ---
func TestRegisterTargets_MissingArn(t *testing.T) {
svc := setupTestService(t)
_, err := svc.RegisterTargets(&elbv2.RegisterTargetsInput{}, testAccountID)
assert.Error(t, err)
}
func TestDeregisterTargets_MissingArn(t *testing.T) {
svc := setupTestService(t)
_, err := svc.DeregisterTargets(&elbv2.DeregisterTargetsInput{}, testAccountID)
assert.Error(t, err)
}
func TestDeregisterTargets_TGNotFound(t *testing.T) {
svc := setupTestService(t)
_, err := svc.DeregisterTargets(&elbv2.DeregisterTargetsInput{
TargetGroupArn: aws.String("arn:nonexistent"),
}, testAccountID)
assert.Error(t, err)
}
// --- CreateListener: custom protocol ---
func TestCreateListener_CustomProtocol(t *testing.T) {
svc := setupTestService(t)
lb, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-proto")}, testAccountID)
tg, _ := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-proto")}, testAccountID)
out, err := svc.CreateListener(&elbv2.CreateListenerInput{
LoadBalancerArn: lb.LoadBalancers[0].LoadBalancerArn,
Protocol: aws.String("HTTPS"),
Port: aws.Int64(443),
DefaultActions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tg.TargetGroups[0].TargetGroupArn}},
}, testAccountID)
require.NoError(t, err)
assert.Equal(t, "HTTPS", *out.Listeners[0].Protocol)
assert.Equal(t, int64(443), *out.Listeners[0].Port)
}
// --- CreateListener: missing actions ---
func TestCreateListener_MissingActions(t *testing.T) {
svc := setupTestService(t)
lb, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-noact")}, testAccountID)
_, err := svc.CreateListener(&elbv2.CreateListenerInput{
LoadBalancerArn: lb.LoadBalancers[0].LoadBalancerArn,
}, testAccountID)
assert.Error(t, err)
}
// --- DeleteTargetGroup: missing ARN ---
func TestDeleteTargetGroup_MissingArn(t *testing.T) {
svc := setupTestService(t)
_, err := svc.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{}, testAccountID)
assert.Error(t, err)
}
// --- DeleteListener: missing ARN ---
func TestDeleteListener_MissingArn(t *testing.T) {
svc := setupTestService(t)
_, err := svc.DeleteListener(&elbv2.DeleteListenerInput{}, testAccountID)
assert.Error(t, err)
}
// --- DescribeTargetHealth: missing ARN ---
func TestDescribeTargetHealth_MissingArn(t *testing.T) {
svc := setupTestService(t)
_, err := svc.DescribeTargetHealth(&elbv2.DescribeTargetHealthInput{}, testAccountID)
assert.Error(t, err)
}
// --- DescribeLoadBalancers: empty filters returns all ---
func TestDescribeLoadBalancers_All(t *testing.T) {
svc := setupTestService(t)
_, _ = svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-all-a")}, testAccountID)
_, _ = svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-all-b")}, testAccountID)
desc, err := svc.DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{}, testAccountID)
require.NoError(t, err)
assert.GreaterOrEqual(t, len(desc.LoadBalancers), 2)
}
// --- DescribeTargetGroups: all ---
func TestDescribeTargetGroups_All(t *testing.T) {
svc := setupTestService(t)
_, _ = svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-all-a")}, testAccountID)
_, _ = svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-all-b")}, testAccountID)
desc, err := svc.DescribeTargetGroups(&elbv2.DescribeTargetGroupsInput{}, testAccountID)
require.NoError(t, err)
assert.GreaterOrEqual(t, len(desc.TargetGroups), 2)
}
// --- DescribeListeners: all (no LB ARN filter) ---
func TestDescribeListeners_All(t *testing.T) {
svc := setupTestService(t)
lb, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-lall")}, testAccountID)
tg, _ := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-lall")}, testAccountID)
_, _ = svc.CreateListener(&elbv2.CreateListenerInput{
LoadBalancerArn: lb.LoadBalancers[0].LoadBalancerArn,
DefaultActions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tg.TargetGroups[0].TargetGroupArn}},
}, testAccountID)
desc, err := svc.DescribeListeners(&elbv2.DescribeListenersInput{}, testAccountID)
require.NoError(t, err)
assert.GreaterOrEqual(t, len(desc.Listeners), 1)
}
// --- DeleteLoadBalancer: missing ARN ---
func TestDeleteLoadBalancer_MissingArn(t *testing.T) {
svc := setupTestService(t)
_, err := svc.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{}, testAccountID)
assert.Error(t, err)
}
// --- RegisterTargets: TG not found ---
func TestRegisterTargets_TGNotFound(t *testing.T) {
svc := setupTestService(t)
_, err := svc.RegisterTargets(&elbv2.RegisterTargetsInput{
TargetGroupArn: aws.String("arn:nonexistent"),
Targets: []*elbv2.TargetDescription{{Id: aws.String("i-abc")}},
}, testAccountID)
assert.Error(t, err)
}
// --- CreateListener: missing LB ARN ---
func TestCreateListener_MissingLBArn(t *testing.T) {
svc := setupTestService(t)
_, err := svc.CreateListener(&elbv2.CreateListenerInput{
DefaultActions: []*elbv2.Action{{Type: aws.String("forward")}},
}, testAccountID)
assert.Error(t, err)
}
+77
View File
@@ -0,0 +1,77 @@
package vpcd
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Additional edge-case tests for subnetGateway and generateMAC.
// Core happy-path tests are in topology_test.go.
func TestSubnetGateway_Slash28(t *testing.T) {
gw, prefix, err := subnetGateway("172.31.0.0/28")
require.NoError(t, err)
assert.Equal(t, "172.31.0.1", gw)
assert.Equal(t, 28, prefix)
}
func TestSubnetGateway_IPv6(t *testing.T) {
_, _, err := subnetGateway("2001:db8::/32")
require.Error(t, err)
assert.Contains(t, err.Error(), "only IPv4 supported")
}
func TestGenerateMAC_EmptyString(t *testing.T) {
mac := generateMAC("")
assert.Equal(t, "02:00:00:00:00:00", mac)
}
// --- dnsServer ---
func TestDnsServer_WithDNSServers(t *testing.T) {
pools := []ExternalPoolConfig{
{Name: "test", DNSServers: []string{"10.0.0.2", "10.0.0.3"}},
}
h := NewTopologyHandler(nil, WithExternalNetwork("pool", pools))
assert.Equal(t, "{10.0.0.2, 10.0.0.3}", h.dnsServer())
}
func TestDnsServer_SingleDNS(t *testing.T) {
pools := []ExternalPoolConfig{
{Name: "test", DNSServers: []string{"1.2.3.4"}},
}
h := NewTopologyHandler(nil, WithExternalNetwork("pool", pools))
assert.Equal(t, "{1.2.3.4}", h.dnsServer())
}
func TestDnsServer_NoPools(t *testing.T) {
h := NewTopologyHandler(nil)
assert.Equal(t, "{8.8.8.8, 1.1.1.1}", h.dnsServer())
}
func TestDnsServer_PoolWithNoDNS(t *testing.T) {
pools := []ExternalPoolConfig{
{Name: "test"},
}
h := NewTopologyHandler(nil, WithExternalNetwork("pool", pools))
assert.Equal(t, "{8.8.8.8, 1.1.1.1}", h.dnsServer())
}
// --- isMacvlanMode ---
func TestIsMacvlanMode_Default(t *testing.T) {
h := NewTopologyHandler(nil)
assert.True(t, h.isMacvlanMode(), "default (empty) should be macvlan")
}
func TestIsMacvlanMode_Direct(t *testing.T) {
h := NewTopologyHandler(nil, WithBridgeMode(BridgeModeDirect))
assert.False(t, h.isMacvlanMode())
}
func TestIsMacvlanMode_Macvlan(t *testing.T) {
h := NewTopologyHandler(nil, WithBridgeMode(BridgeModeMacvlan))
assert.True(t, h.isMacvlanMode())
}