From b0d58ff0f6bcf15880d57752cc29e454debddf19 Mon Sep 17 00:00:00 2001 From: Julian Sommer <115516918+juliansommer@users.noreply.github.com> Date: Tue, 28 Apr 2026 14:18:56 +1000 Subject: [PATCH] chore: add missing tests --- spinifex/admin/network_detect_test.go | 81 +++++++++++++++++++ .../gateway/ec2/instance/RunInstances_test.go | 28 +++++++ spinifex/services/vpcd/dhcp_manager_test.go | 23 ++++++ spinifex/utils/tags_test.go | 36 +++++++++ 4 files changed, 168 insertions(+) create mode 100644 spinifex/admin/network_detect_test.go create mode 100644 spinifex/utils/tags_test.go diff --git a/spinifex/admin/network_detect_test.go b/spinifex/admin/network_detect_test.go new file mode 100644 index 000000000..d8cf7b7e0 --- /dev/null +++ b/spinifex/admin/network_detect_test.go @@ -0,0 +1,81 @@ +package admin + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSuggestPoolRange(t *testing.T) { + tests := []struct { + name string + subnet string + wantStart string + wantEnd string + }{ + { + // /23 broadcast 192.168.1.255 → end .250, start .150 (borrows across octet) + name: "Slash23BorrowsAcrossOctet", + subnet: "192.168.0.0/23", + wantStart: "192.168.1.150", + wantEnd: "192.168.1.250", + }, + { + // /24 broadcast 192.168.1.255 → end .250, start .150 + name: "Slash24", + subnet: "192.168.1.0/24", + wantStart: "192.168.1.150", + wantEnd: "192.168.1.250", + }, + { + name: "InvalidCIDRReturnsEmpty", + subnet: "not-a-cidr", + wantStart: "", + wantEnd: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + start, end := SuggestPoolRange(&DetectedInterface{Subnet: tt.subnet}) + assert.Equal(t, tt.wantStart, start) + assert.Equal(t, tt.wantEnd, end) + }) + } +} + +func TestIsVirtualInterface(t *testing.T) { + tests := []struct { + name string + iface string + defaultRouteDev string + want bool + }{ + { + // Default-route override: a bridge name normally treated as virtual + // is considered physical when it's the WAN uplink. + name: "DefaultRouteOverridesVirtualPrefix", + iface: "br-wan", + defaultRouteDev: "br-wan", + want: false, + }, + { + name: "DockerPrefixIsVirtual", + iface: "docker0", + defaultRouteDev: "enp0s3", + want: true, + }, + { + name: "PhysicalNICNotVirtual", + iface: "enp0s3", + defaultRouteDev: "enp0s3", + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, isVirtualInterface(tt.iface, tt.defaultRouteDev)) + }) + } +} diff --git a/spinifex/gateway/ec2/instance/RunInstances_test.go b/spinifex/gateway/ec2/instance/RunInstances_test.go index 632216f95..6db8a94a3 100644 --- a/spinifex/gateway/ec2/instance/RunInstances_test.go +++ b/spinifex/gateway/ec2/instance/RunInstances_test.go @@ -176,6 +176,34 @@ func TestParseRunInstances(t *testing.T) { want: errors.New(awserrors.ErrorMissingParameter), }, + { + name: "NilMaxCount", + input: &ec2.RunInstancesInput{ + ImageId: defaults.ImageId, + InstanceType: defaults.InstanceType, + MinCount: aws.Int64(1), + MaxCount: nil, + KeyName: defaults.KeyName, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: errors.New(awserrors.ErrorMissingParameter), + }, + + { + name: "MissingKeyName", + input: &ec2.RunInstancesInput{ + ImageId: defaults.ImageId, + InstanceType: defaults.InstanceType, + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + KeyName: nil, + SecurityGroupIds: defaults.SecurityGroupIds, + SubnetId: defaults.SubnetId, + }, + want: errors.New(awserrors.ErrorMissingParameter), + }, + // Successful test { name: "ValidTest", diff --git a/spinifex/services/vpcd/dhcp_manager_test.go b/spinifex/services/vpcd/dhcp_manager_test.go index d43860341..3be61e170 100644 --- a/spinifex/services/vpcd/dhcp_manager_test.go +++ b/spinifex/services/vpcd/dhcp_manager_test.go @@ -410,3 +410,26 @@ func TestDHCPManager_EncodeDecodeLeaseRoundTrip(t *testing.T) { require.Equal(t, in.RawACK, out.RawACK) require.Equal(t, in.RawOffer, out.RawOffer) } + +func TestResolveHWAddr(t *testing.T) { + t.Run("InvalidRawMACReturnsParseError", func(t *testing.T) { + mac, err := resolveHWAddr("not-a-mac", "client-1", nil) + require.Error(t, err) + require.Nil(t, mac) + require.Contains(t, err.Error(), "parse hw_addr") + }) + + t.Run("EmptyRawWithNilDeriveErrors", func(t *testing.T) { + mac, err := resolveHWAddr("", "client-1", nil) + require.Error(t, err) + require.Nil(t, mac) + require.Contains(t, err.Error(), "no derivation function") + }) + + t.Run("EmptyRawWithDeriveReturningEmptyErrors", func(t *testing.T) { + mac, err := resolveHWAddr("", "client-1", func(string) net.HardwareAddr { return nil }) + require.Error(t, err) + require.Nil(t, mac) + require.Contains(t, err.Error(), "empty result") + }) +} diff --git a/spinifex/utils/tags_test.go b/spinifex/utils/tags_test.go new file mode 100644 index 000000000..f25ff57ce --- /dev/null +++ b/spinifex/utils/tags_test.go @@ -0,0 +1,36 @@ +package utils + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/stretchr/testify/assert" +) + +func TestExtractTags(t *testing.T) { + specs := []*ec2.TagSpecification{ + { + ResourceType: aws.String("instance"), + Tags: []*ec2.Tag{ + {Key: aws.String("Name"), Value: aws.String("web-1")}, + {Key: nil, Value: aws.String("skipped-nil-key")}, + {Key: aws.String("skipped-nil-value"), Value: nil}, + }, + }, + { + ResourceType: aws.String("volume"), + Tags: []*ec2.Tag{ + {Key: aws.String("Env"), Value: aws.String("prod")}, + }, + }, + } + + got := ExtractTags(specs, "instance") + assert.Equal(t, map[string]string{"Name": "web-1"}, got) + + // Non-matching resource type returns an empty (non-nil) map. + empty := ExtractTags(specs, "snapshot") + assert.NotNil(t, empty) + assert.Empty(t, empty) +}