Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pimlu committed Feb 25, 2025
1 parent 155350f commit d384137
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 1 deletion.
5 changes: 4 additions & 1 deletion pkg/util/cloudproviders/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func GetNetworkID(ctx context.Context) (string, error) {
})
}

func getVPCSubnetsForHost(ctx context.Context) ([]string, error) {
func getVPCSubnetsForHostImpl(ctx context.Context) ([]string, error) {
subnets, ec2err := ec2.GetVPCSubnetsForHost(ctx)
if ec2err == nil {
return subnets, nil
Expand All @@ -69,6 +69,9 @@ func getVPCSubnetsForHost(ctx context.Context) ([]string, error) {
return nil, fmt.Errorf("could not detect VPC subnets: %w", errors.Join(ec2err))
}

// use a global to allow easy mocking
var getVPCSubnetsForHost = getVPCSubnetsForHostImpl

// GetVPCSubnetsForHost gets all the subnets in the VPCs this host has network interfaces for
func GetVPCSubnetsForHost(ctx context.Context) ([]*net.IPNet, error) {
return cache.GetWithExpiration[[]*net.IPNet](
Expand Down
66 changes: 66 additions & 0 deletions pkg/util/cloudproviders/network_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2025-present Datadog, Inc.

package cloudproviders

import (
"context"
"errors"
"testing"

"github.com/stretchr/testify/require"

"github.com/DataDog/datadog-agent/pkg/util/cache"
)

// addCleanupForSubnets clears the subnet cache after the tests.
// otherwise, tests will interfere with each other.
func addCleanupForSubnets(t *testing.T) {
t.Cleanup(func() {
cache.Cache.Delete(vpcSubnetsForHostCacheKey)
})
}

// mockGetVPCSubnetsForHostImpl replaces the implementation of getVPCSubnetsForHost with a mock
func mockGetVPCSubnetsForHostImpl(t *testing.T, mock func(context.Context) ([]string, error)) {
t.Cleanup(func() { getVPCSubnetsForHost = getVPCSubnetsForHostImpl })
getVPCSubnetsForHost = mock
}

func TestGetVPCSubnetsForHost(t *testing.T) {
addCleanupForSubnets(t)
expectedSubnets := []string{"192.168.1.0/24", "beef::/64"}
mockGetVPCSubnetsForHostImpl(t, func(_ context.Context) ([]string, error) {
return expectedSubnets, nil
})
subnets, err := GetVPCSubnetsForHost(context.Background())
require.NoError(t, err)

var actualSubnets []string
for _, subnet := range subnets {
actualSubnets = append(actualSubnets, subnet.String())
}
// check that it parsed the subnets correctly
require.ElementsMatch(t, expectedSubnets, actualSubnets)
}

func TestGetVPCSubnetsForHostInvalid(t *testing.T) {
addCleanupForSubnets(t)
mockGetVPCSubnetsForHostImpl(t, func(_ context.Context) ([]string, error) {
return []string{"not a valid subnet"}, nil
})
_, err := GetVPCSubnetsForHost(context.Background())
require.Error(t, err)
}

func TestGetVPCSubnetsForHostError(t *testing.T) {
addCleanupForSubnets(t)
errMock := errors.New("mock error")
mockGetVPCSubnetsForHostImpl(t, func(_ context.Context) ([]string, error) {
return nil, errMock
})
_, err := GetVPCSubnetsForHost(context.Background())
require.ErrorIs(t, err, errMock)
}
55 changes: 55 additions & 0 deletions pkg/util/ec2/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,58 @@ func TestGetInstanceIDMultipleVPC(t *testing.T) {
require.Error(t, err)
assert.Contains(t, err.Error(), "too many mac addresses returned")
}

func TestGetVPCSubnets(t *testing.T) {
ctx := context.Background()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
switch r.Method {
case http.MethodPut: // token request
io.WriteString(w, testIMDSToken)
case http.MethodGet: // metadata request
switch r.RequestURI {
case "/network/interfaces/macs":
io.WriteString(w, "00:00:00:12:34/\n")
io.WriteString(w, "00:00:00:56:78/")
case "/network/interfaces/macs/00:00:00:12:34/vpc-ipv4-cidr-blocks":
io.WriteString(w, "10.1.56.0/8\n")
io.WriteString(w, "10.1.56.1/8")
case "/network/interfaces/macs/00:00:00:12:34/vpc-ipv6-cidr-blocks":
io.WriteString(w, "2600::/64\n")
io.WriteString(w, "2601::/64")
case "/network/interfaces/macs/00:00:00:56:78/vpc-ipv4-cidr-blocks":
io.WriteString(w, "10.1.56.2/8\n")
io.WriteString(w, "10.1.56.3/8")
case "/network/interfaces/macs/00:00:00:56:78/vpc-ipv6-cidr-blocks":
io.WriteString(w, "2602::/64\n")
io.WriteString(w, "2603::/64")
default:
w.WriteHeader(http.StatusNotFound)
}
}
}))
defer ts.Close()

defer resetPackageVars()
metadataURL = ts.URL
tokenURL = ts.URL
conf := configmock.New(t)
conf.SetWithoutSource("ec2_metadata_timeout", 1000)

subnets, err := GetVPCSubnetsForHost(ctx)
assert.NoError(t, err)

expected := []string{
"10.1.56.0/8",
"10.1.56.1/8",
"2600::/64",
"2601::/64",
"10.1.56.2/8",
"10.1.56.3/8",
"2602::/64",
"2603::/64",
}

// elements may come back in any order
require.ElementsMatch(t, expected, subnets)
}

0 comments on commit d384137

Please sign in to comment.