Switch unit tests to testify
This commit is contained in:
parent
50a535bb7f
commit
821cf58ca2
14 changed files with 481 additions and 1185 deletions
|
|
@ -6,43 +6,33 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Validate the cloud-init configuration parser/writer functions.
|
||||
func TestCloudinit(t *testing.T) {
|
||||
// Setup test file.
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
configPath := filepath.Join(tmpDir, "network.yaml")
|
||||
testDir, err := filepath.Abs("./tests/cloudinit")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
resultsDir := filepath.Join(testDir, "results")
|
||||
err = fileCopy(filepath.Join(testDir, "network.yaml"), configPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Setup ifupdown and parse test file.
|
||||
ci, err := newCloudInitWith(configPath, filepath.Join(tmpDir, "nothing.json"), filepath.Join(tmpDir, "cloud.cfg.d"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err := ci.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = ci.SetIfaceAddresses(context.Background(), "test_eth0.1556", []*net.IPNet{
|
||||
|
|
@ -59,9 +49,7 @@ func TestCloudinit(t *testing.T) {
|
|||
Mask: net.CIDRMask(64, 128),
|
||||
},
|
||||
}, net.ParseIP("1.2.3.1"), net.ParseIP("fc00::1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = ci.SetIfaceRoutes(context.Background(), "test_eth3", []*Route{
|
||||
|
|
@ -82,27 +70,19 @@ func TestCloudinit(t *testing.T) {
|
|||
Metric: 100,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = ci.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = ci.SetIfaceAddresses(context.Background(), "test_eth0", []*net.IPNet{
|
||||
|
|
@ -111,76 +91,52 @@ func TestCloudinit(t *testing.T) {
|
|||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}, net.ParseIP("1.2.10.254"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = ci.SetIfaceRoutes(context.Background(), "test_eth0.1556", []*Route{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = ci.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Cleanup.
|
||||
err = os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Validate the cloudbase-init configuration parser/writer functions.
|
||||
func TestCloudbaseinit(t *testing.T) {
|
||||
// Setup test file.
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
configPath := filepath.Join(tmpDir, "network.json")
|
||||
testDir, err := filepath.Abs("./tests/cloudinit/cloudbase")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
resultsDir := filepath.Join(testDir, "results")
|
||||
err = fileCopy(filepath.Join(testDir, "network.json"), configPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Setup ifupdown and parse test file.
|
||||
ci, err := newCloudInitWith(filepath.Join(tmpDir, "nothing.yaml"), configPath, filepath.Join(tmpDir, "cloud.cfg.d"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err := ci.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = ci.SetIfaceAddresses(context.Background(), "test_eth0.1556", []*net.IPNet{
|
||||
|
|
@ -197,9 +153,7 @@ func TestCloudbaseinit(t *testing.T) {
|
|||
Mask: net.CIDRMask(64, 128),
|
||||
},
|
||||
}, net.ParseIP("1.2.3.1"), net.ParseIP("fc00::1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = ci.SetIfaceRoutes(context.Background(), "test_eth3", []*Route{
|
||||
|
|
@ -220,27 +174,19 @@ func TestCloudbaseinit(t *testing.T) {
|
|||
Metric: 100,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = ci.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = ci.SetIfaceAddresses(context.Background(), "test_eth0", []*net.IPNet{
|
||||
|
|
@ -249,37 +195,25 @@ func TestCloudbaseinit(t *testing.T) {
|
|||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}, net.ParseIP("1.2.10.254"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = ci.SetIfaceRoutes(context.Background(), "test_eth0.1556", []*Route{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = ci.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Cleanup.
|
||||
err = os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netns"
|
||||
"golang.org/x/sys/unix"
|
||||
|
|
@ -24,18 +25,12 @@ func setupNetlinkTest(t testing.TB) func() {
|
|||
|
||||
runtime.LockOSThread()
|
||||
ns, err := netns.New()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create new netns", err)
|
||||
}
|
||||
require.NoError(t, err, "Failed to create new netns")
|
||||
|
||||
link, err := netlink.LinkByName("lo")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to find \"lo\" in new netns: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Failed to find \"lo\" in new netns")
|
||||
err = netlink.LinkSetUp(link)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to bring up \"lo\" in new netns: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Failed to bring up \"lo\" in new netns")
|
||||
|
||||
return func() {
|
||||
ns.Close()
|
||||
|
|
@ -49,9 +44,7 @@ func setupNetlinkTest(t testing.TB) func() {
|
|||
func isPrimary(t testing.TB, h *netlink.Handle, link netlink.Link, ip net.IP) (present, primary bool) {
|
||||
t.Helper()
|
||||
addrs, err := h.AddrList(link, netlink.FAMILY_ALL)
|
||||
if err != nil {
|
||||
t.Fatalf("AddrList: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "AddrList")
|
||||
for _, a := range addrs {
|
||||
if a.IPNet.IP.Equal(ip) {
|
||||
return true, a.Flags&unix.IFA_F_SECONDARY == 0
|
||||
|
|
@ -68,9 +61,7 @@ func TestLinuxSetPrimaryAddress(t *testing.T) {
|
|||
defer tearDown()
|
||||
|
||||
h, err := netlink.NewHandle()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
defer h.Close()
|
||||
|
||||
// Setup test link.
|
||||
|
|
@ -79,42 +70,30 @@ func TestLinuxSetPrimaryAddress(t *testing.T) {
|
|||
Name: name,
|
||||
HardwareAddr: net.HardwareAddr{0x52, 0x54, 0x00, 0x8b, 0x0d, 0x93},
|
||||
}})
|
||||
if err = h.LinkAdd(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = h.LinkSetUp(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, h.LinkAdd(link))
|
||||
require.NoError(t, h.LinkSetUp(link))
|
||||
|
||||
// Add two addresses in the same subnet. The first added is the primary.
|
||||
primaryIP := &net.IPNet{IP: net.ParseIP("1.2.3.4"), Mask: net.CIDRMask(24, 32)}
|
||||
secondaryIP := &net.IPNet{IP: net.ParseIP("1.2.3.5"), Mask: net.CIDRMask(24, 32)}
|
||||
if err = h.AddrAdd(link, &netlink.Addr{IPNet: primaryIP}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = h.AddrAdd(link, &netlink.Addr{IPNet: secondaryIP}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, h.AddrAdd(link, &netlink.Addr{IPNet: primaryIP}))
|
||||
require.NoError(t, h.AddrAdd(link, &netlink.Addr{IPNet: secondaryIP}))
|
||||
|
||||
// Add a default route via the subnet so connectivity verification has a
|
||||
// gateway to work with.
|
||||
gw := net.ParseIP("1.2.3.1")
|
||||
if err = h.RouteAdd(&netlink.Route{
|
||||
require.NoError(t, h.RouteAdd(&netlink.Route{
|
||||
Family: netlink.FAMILY_V4,
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Dst: &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)},
|
||||
Gw: gw,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}))
|
||||
|
||||
// Sanity check the initial primary/secondary assignment.
|
||||
if _, primary := isPrimary(t, h, link, primaryIP.IP); !primary {
|
||||
t.Fatal("expected 1.2.3.4 to start as primary")
|
||||
}
|
||||
if _, primary := isPrimary(t, h, link, secondaryIP.IP); primary {
|
||||
t.Fatal("expected 1.2.3.5 to start as secondary")
|
||||
}
|
||||
_, primary := isPrimary(t, h, link, primaryIP.IP)
|
||||
require.True(t, primary, "expected 1.2.3.4 to start as primary")
|
||||
_, primary = isPrimary(t, h, link, secondaryIP.IP)
|
||||
require.False(t, primary, "expected 1.2.3.5 to start as secondary")
|
||||
|
||||
// Configurator with the success sentinel and a capturing backend.
|
||||
backend := &fakeIfaceBackend{}
|
||||
|
|
@ -122,51 +101,36 @@ func TestLinuxSetPrimaryAddress(t *testing.T) {
|
|||
c.ifaceBackends = append(c.ifaceBackends, namedIfaceBackend{"fake", backend})
|
||||
|
||||
// Promote the secondary to primary.
|
||||
if err = c.SetPrimaryAddress(context.Background(), name, secondaryIP); err != nil {
|
||||
t.Fatalf("SetPrimaryAddress: %v", err)
|
||||
}
|
||||
require.NoError(t, c.SetPrimaryAddress(context.Background(), name, secondaryIP), "SetPrimaryAddress")
|
||||
|
||||
// The kernel should now treat 1.2.3.5 as primary and 1.2.3.4 as secondary,
|
||||
// with both addresses still present and the default route intact.
|
||||
if present, primary := isPrimary(t, h, link, secondaryIP.IP); !present || !primary {
|
||||
t.Errorf("after promotion 1.2.3.5: present=%v primary=%v, want both true", present, primary)
|
||||
}
|
||||
if present, primary := isPrimary(t, h, link, primaryIP.IP); !present || primary {
|
||||
t.Errorf("after promotion 1.2.3.4: present=%v primary=%v, want present true primary false", present, primary)
|
||||
}
|
||||
present, primary := isPrimary(t, h, link, secondaryIP.IP)
|
||||
assert.True(t, present && primary, "after promotion 1.2.3.5: present=%v primary=%v, want both true", present, primary)
|
||||
present, primary = isPrimary(t, h, link, primaryIP.IP)
|
||||
assert.True(t, present && !primary, "after promotion 1.2.3.4: present=%v primary=%v, want present true primary false", present, primary)
|
||||
routes, err := h.RouteList(link, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
haveDefault := false
|
||||
for _, r := range routes {
|
||||
if ones, _ := r.Dst.Mask.Size(); ones == 0 && r.Gw.Equal(gw) {
|
||||
haveDefault = true
|
||||
}
|
||||
}
|
||||
if !haveDefault {
|
||||
t.Error("default route missing after promotion")
|
||||
}
|
||||
assert.True(t, haveDefault, "default route missing after promotion")
|
||||
|
||||
// The persisted config must receive the reordered list, primary first.
|
||||
if len(backend.lastAddrs) == 0 || !backend.lastAddrs[0].IP.Equal(secondaryIP.IP) {
|
||||
t.Errorf("backend primary = %v, want 1.2.3.5 first", backend.lastAddrs)
|
||||
}
|
||||
assert.True(t, len(backend.lastAddrs) != 0 && backend.lastAddrs[0].IP.Equal(secondaryIP.IP), "backend primary = %v, want 1.2.3.5 first", backend.lastAddrs)
|
||||
|
||||
// Promoting the already-primary address is a no-op that still succeeds.
|
||||
if err = c.SetPrimaryAddress(context.Background(), name, secondaryIP); err != nil {
|
||||
t.Errorf("SetPrimaryAddress (idempotent): %v", err)
|
||||
}
|
||||
if _, primary := isPrimary(t, h, link, secondaryIP.IP); !primary {
|
||||
t.Error("1.2.3.5 should remain primary after idempotent call")
|
||||
}
|
||||
assert.NoError(t, c.SetPrimaryAddress(context.Background(), name, secondaryIP), "SetPrimaryAddress (idempotent)")
|
||||
_, primary = isPrimary(t, h, link, secondaryIP.IP)
|
||||
assert.True(t, primary, "1.2.3.5 should remain primary after idempotent call")
|
||||
|
||||
// Promoting an address not on the interface must error before any change.
|
||||
absent := &net.IPNet{IP: net.ParseIP("1.2.3.99"), Mask: net.CIDRMask(24, 32)}
|
||||
err = c.SetPrimaryAddress(context.Background(), name, absent)
|
||||
if err == nil || err.Error() != "address not found on interface" {
|
||||
t.Errorf("absent address error = %v, want \"address not found on interface\"", err)
|
||||
}
|
||||
assert.EqualError(t, err, "address not found on interface")
|
||||
}
|
||||
|
||||
// TestLinuxRemovePrimaryRefused verifies that RemoveAddress refuses to remove
|
||||
|
|
@ -177,43 +141,27 @@ func TestLinuxRemovePrimaryRefused(t *testing.T) {
|
|||
defer tearDown()
|
||||
|
||||
h, err := netlink.NewHandle()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
defer h.Close()
|
||||
|
||||
name := "test_enp1s0"
|
||||
link := netlink.Link(&netlink.Dummy{LinkAttrs: netlink.LinkAttrs{Name: name}})
|
||||
if err = h.LinkAdd(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = h.LinkSetUp(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, h.LinkAdd(link))
|
||||
require.NoError(t, h.LinkSetUp(link))
|
||||
|
||||
primaryIP := &net.IPNet{IP: net.ParseIP("1.2.3.4"), Mask: net.CIDRMask(24, 32)}
|
||||
if err = h.AddrAdd(link, &netlink.Addr{IPNet: primaryIP}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, h.AddrAdd(link, &netlink.Addr{IPNet: primaryIP}))
|
||||
|
||||
c := &linuxConfigurator{configOptions: &configOptions{testAddress: "test_success"}}
|
||||
c.ifaceBackends = append(c.ifaceBackends, namedIfaceBackend{"fake", &fakeIfaceBackend{}})
|
||||
|
||||
// Default: removing the primary is refused.
|
||||
err = c.RemoveAddress(context.Background(), name, primaryIP)
|
||||
if err == nil || !contains(err.Error(), "refusing to remove primary address") {
|
||||
t.Errorf("RemoveAddress primary = %v, want refusal error", err)
|
||||
}
|
||||
assert.ErrorContains(t, err, "refusing to remove primary address")
|
||||
|
||||
// With the override enabled, removal succeeds.
|
||||
c.allowPrimaryRemoval = true
|
||||
if err = c.RemoveAddress(context.Background(), name, primaryIP); err != nil {
|
||||
t.Errorf("RemoveAddress with allowPrimaryRemoval: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
return strings.Contains(s, substr)
|
||||
assert.NoError(t, c.RemoveAddress(context.Background(), name, primaryIP), "RemoveAddress with allowPrimaryRemoval")
|
||||
}
|
||||
|
||||
func TestLinuxConfigurator(t *testing.T) {
|
||||
|
|
@ -222,9 +170,7 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
|
||||
// Connect to netlink.
|
||||
h, err := netlink.NewHandle()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
defer h.Close()
|
||||
|
||||
// Setup test link.
|
||||
|
|
@ -234,15 +180,11 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
HardwareAddr: net.HardwareAddr{0x52, 0x54, 0x00, 0x8b, 0x0d, 0x93},
|
||||
}})
|
||||
err = h.LinkAdd(eth0Link)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set test link up.
|
||||
err = h.LinkSetUp(eth0Link)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add test IP.
|
||||
testIP1 := &net.IPNet{
|
||||
|
|
@ -250,9 +192,7 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
Mask: net.CIDRMask(24, 32),
|
||||
}
|
||||
err = h.AddrAdd(eth0Link, &netlink.Addr{IPNet: testIP1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add default route.
|
||||
testGW1 := net.ParseIP("1.2.3.1")
|
||||
|
|
@ -266,9 +206,7 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
Gw: testGW1,
|
||||
}
|
||||
err = h.RouteAdd(defaultRoute)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Setup test link.
|
||||
eth1Name := "test_enp2s0"
|
||||
|
|
@ -277,15 +215,11 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
HardwareAddr: net.HardwareAddr{0x52, 0x54, 0x00, 0x8b, 0xad, 0x93},
|
||||
}}
|
||||
err = h.LinkAdd(eth1Link)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set test link up.
|
||||
err = h.LinkSetUp(eth1Link)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add test IP.
|
||||
testIP2 := &net.IPNet{
|
||||
|
|
@ -293,9 +227,7 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
Mask: net.CIDRMask(64, 128),
|
||||
}
|
||||
err = h.AddrAdd(eth1Link, &netlink.Addr{IPNet: testIP2})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add default route.
|
||||
testGW2 := net.ParseIP("fe80::1")
|
||||
|
|
@ -311,9 +243,7 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
Priority: 200,
|
||||
}
|
||||
err = h.RouteAdd(ipv6Route)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Setup configurator with test URL to test server.
|
||||
c := &linuxConfigurator{configOptions: &configOptions{}}
|
||||
|
|
@ -324,218 +254,146 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
|
||||
// Setup test results path.
|
||||
testDir, err := filepath.Abs("./tests/configurator_linux")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
resultsDir := filepath.Join(testDir, "results")
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
configPath := filepath.Join(tmpDir, "50-cloud-init.yaml")
|
||||
err = fileCopy(filepath.Join(testDir, "50-cloud-init.yaml"), configPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Setup ifupdown and parse test file.
|
||||
ci, err := newCloudInitWith(configPath, filepath.Join(tmpDir, "nothing.json"), filepath.Join(tmpDir, "cloud.cfg.d"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
c.ifaceBackends = append(c.ifaceBackends, namedIfaceBackend{"cloud-init", ci})
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err := c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test add addresses.
|
||||
testIP3 := &net.IPNet{IP: net.ParseIP("1.2.3.5"), Mask: net.CIDRMask(24, 32)}
|
||||
err = c.AddAddress(context.Background(), eth0Name, testIP3, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
testIP4 := &net.IPNet{IP: net.ParseIP("fc00:5aa8:7160:d9eb:1:0:1:5"), Mask: net.CIDRMask(64, 128)}
|
||||
err = c.AddAddress(context.Background(), eth1Name, testIP4, net.ParseIP("fc00:5aa8:7160:d9eb::"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err = c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test remove addresses.
|
||||
err = c.RemoveAddress(context.Background(), eth0Name, testIP1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
err = c.RemoveAddress(context.Background(), eth1Name, testIP2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err = c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test rollback on failures.
|
||||
c.testAddress = "test_fail"
|
||||
err = c.AddAddress(context.Background(), eth0Name, testIP1, nil)
|
||||
if err == nil || err.Error() != "aborted operation due to loss of internet" {
|
||||
t.Errorf("Failed rollback test: %v", err)
|
||||
}
|
||||
assert.EqualError(t, err, "aborted operation due to loss of internet", "Failed rollback test")
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err = c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test remove gateway.
|
||||
err = c.AddAddress(context.Background(), eth0Name, testIP3, make(net.IP, 4))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err = c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 4)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test add gateway rollback.
|
||||
err = c.AddAddress(context.Background(), eth0Name, testIP3, testGW1)
|
||||
if err == nil || err.Error() != "aborted operation due to loss of internet" {
|
||||
t.Errorf("Failed rollback test: %v", err)
|
||||
}
|
||||
assert.EqualError(t, err, "aborted operation due to loss of internet", "Failed rollback test")
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err = c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 4)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test remove gateway.
|
||||
c.testAddress = "test_success"
|
||||
err = c.AddAddress(context.Background(), eth0Name, testIP3, testGW1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err = c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test removing route.
|
||||
err = c.RemoveRoute(context.Background(), eth1Name, ipv6Dest, testGW2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err = c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 5)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 4)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test add route.
|
||||
ipv4Dest := &net.IPNet{
|
||||
|
|
@ -544,25 +402,17 @@ func TestLinuxConfigurator(t *testing.T) {
|
|||
}
|
||||
testGW3 := net.ParseIP("1.2.3.254")
|
||||
err = c.AddRoute(context.Background(), eth0Name, ipv4Dest, testGW3, 100)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get list of interfaces.
|
||||
interfaces, err = c.GetInterfaces(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 6)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 5)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
104
cpanel_test.go
104
cpanel_test.go
|
|
@ -4,6 +4,9 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// parseJSON unmarshals a single line of whmapi1 output; verify its guard on
|
||||
|
|
@ -14,33 +17,24 @@ func TestCpanelParseJSON(t *testing.T) {
|
|||
t.Run("valid single line", func(t *testing.T) {
|
||||
var v cpanelBase
|
||||
err := c.parseJSON([]string{`{"metadata":{"command":"listips","result":1}}`}, &v)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if v.Metadata.Command != "listips" || v.Metadata.Result != 1 {
|
||||
t.Errorf("decoded = %+v, want command=listips result=1", v.Metadata)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "listips", v.Metadata.Command)
|
||||
assert.Equal(t, 1, v.Metadata.Result)
|
||||
})
|
||||
|
||||
t.Run("no output errors", func(t *testing.T) {
|
||||
var v cpanelBase
|
||||
if err := c.parseJSON(nil, &v); err == nil {
|
||||
t.Error("expected error for empty output")
|
||||
}
|
||||
assert.Error(t, c.parseJSON(nil, &v))
|
||||
})
|
||||
|
||||
t.Run("multiple lines errors", func(t *testing.T) {
|
||||
var v cpanelBase
|
||||
if err := c.parseJSON([]string{"{}", "{}"}, &v); err == nil {
|
||||
t.Error("expected error for multi-line output")
|
||||
}
|
||||
assert.Error(t, c.parseJSON([]string{"{}", "{}"}, &v))
|
||||
})
|
||||
|
||||
t.Run("invalid json errors", func(t *testing.T) {
|
||||
var v cpanelBase
|
||||
if err := c.parseJSON([]string{"not json"}, &v); err == nil {
|
||||
t.Error("expected error for invalid json")
|
||||
}
|
||||
assert.Error(t, c.parseJSON([]string{"not json"}, &v))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -51,93 +45,53 @@ func TestSetWWWAcctAddr(t *testing.T) {
|
|||
t.Run("replaces existing ADDR and preserves other lines", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "wwwacct.conf")
|
||||
content := "HOST server.example.com\nADDR 203.0.113.10\nNS ns1.example.com\n"
|
||||
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := setWWWAcctAddr(path, "ADDR", "203.0.113.20"); err != nil {
|
||||
t.Fatalf("setWWWAcctAddr: %v", err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(path, []byte(content), 0644))
|
||||
require.NoError(t, setWWWAcctAddr(path, "ADDR", "203.0.113.20"))
|
||||
got, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
want := "HOST server.example.com\nADDR 203.0.113.20\nNS ns1.example.com\n"
|
||||
if string(got) != want {
|
||||
t.Errorf("got:\n%s\nwant:\n%s", got, want)
|
||||
}
|
||||
assert.Equal(t, want, string(got))
|
||||
})
|
||||
|
||||
t.Run("appends ADDR when absent", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "wwwacct.conf")
|
||||
if err := os.WriteFile(path, []byte("HOST server.example.com\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := setWWWAcctAddr(path, "ADDR", "203.0.113.20"); err != nil {
|
||||
t.Fatalf("setWWWAcctAddr: %v", err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(path, []byte("HOST server.example.com\n"), 0644))
|
||||
require.NoError(t, setWWWAcctAddr(path, "ADDR", "203.0.113.20"))
|
||||
got, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
want := "HOST server.example.com\nADDR 203.0.113.20\n"
|
||||
if string(got) != want {
|
||||
t.Errorf("got:\n%q\nwant:\n%q", got, want)
|
||||
}
|
||||
assert.Equal(t, want, string(got))
|
||||
})
|
||||
|
||||
t.Run("setting ADDR does not touch ADDR6", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "wwwacct.conf")
|
||||
content := "ADDR 203.0.113.10\nADDR6 2001:db8::1\n"
|
||||
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := setWWWAcctAddr(path, "ADDR", "203.0.113.20"); err != nil {
|
||||
t.Fatalf("setWWWAcctAddr: %v", err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(path, []byte(content), 0644))
|
||||
require.NoError(t, setWWWAcctAddr(path, "ADDR", "203.0.113.20"))
|
||||
got, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
want := "ADDR 203.0.113.20\nADDR6 2001:db8::1\n"
|
||||
if string(got) != want {
|
||||
t.Errorf("got:\n%s\nwant:\n%s", got, want)
|
||||
}
|
||||
assert.Equal(t, want, string(got))
|
||||
})
|
||||
|
||||
t.Run("setting ADDR6 replaces it and leaves ADDR alone", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "wwwacct.conf")
|
||||
content := "ADDR 203.0.113.10\nADDR6 2001:db8::1\n"
|
||||
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := setWWWAcctAddr(path, "ADDR6", "2001:db8::20"); err != nil {
|
||||
t.Fatalf("setWWWAcctAddr: %v", err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(path, []byte(content), 0644))
|
||||
require.NoError(t, setWWWAcctAddr(path, "ADDR6", "2001:db8::20"))
|
||||
got, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
want := "ADDR 203.0.113.10\nADDR6 2001:db8::20\n"
|
||||
if string(got) != want {
|
||||
t.Errorf("got:\n%s\nwant:\n%s", got, want)
|
||||
}
|
||||
assert.Equal(t, want, string(got))
|
||||
})
|
||||
|
||||
t.Run("appends ADDR6 when absent", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "wwwacct.conf")
|
||||
if err := os.WriteFile(path, []byte("ADDR 203.0.113.10\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := setWWWAcctAddr(path, "ADDR6", "2001:db8::20"); err != nil {
|
||||
t.Fatalf("setWWWAcctAddr: %v", err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(path, []byte("ADDR 203.0.113.10\n"), 0644))
|
||||
require.NoError(t, setWWWAcctAddr(path, "ADDR6", "2001:db8::20"))
|
||||
got, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
want := "ADDR 203.0.113.10\nADDR6 2001:db8::20\n"
|
||||
if string(got) != want {
|
||||
t.Errorf("got:\n%s\nwant:\n%s", got, want)
|
||||
}
|
||||
assert.Equal(t, want, string(got))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// readIfcfg parses a written ifcfg-<iface> file back into a key/value map so
|
||||
|
|
@ -13,9 +16,7 @@ import (
|
|||
func readIfcfg(t *testing.T, dir, iface string) map[string]string {
|
||||
t.Helper()
|
||||
data, err := os.ReadFile(filepath.Join(dir, "ifcfg-"+iface))
|
||||
if err != nil {
|
||||
t.Fatalf("read ifcfg-%s: %v", iface, err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
out := make(map[string]string)
|
||||
for _, line := range splitLines(string(data)) {
|
||||
k, v, ok := cutKV(line)
|
||||
|
|
@ -68,32 +69,21 @@ func TestNetworkScriptsDNSPeerDNS(t *testing.T) {
|
|||
err := ns.SetIfaceDNS(context.Background(), "eth0",
|
||||
[]net.IP{net.ParseIP("1.1.1.1"), net.ParseIP("8.8.8.8")},
|
||||
[]string{"example.com"})
|
||||
if err != nil {
|
||||
t.Fatalf("SetIfaceDNS: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
cfg := readIfcfg(t, dir, "eth0")
|
||||
if cfg["PEERDNS"] != "no" {
|
||||
t.Errorf("PEERDNS = %q, want \"no\"", cfg["PEERDNS"])
|
||||
}
|
||||
if cfg["DNS1"] != "1.1.1.1" || cfg["DNS2"] != "8.8.8.8" {
|
||||
t.Errorf("DNS1/DNS2 = %q/%q, want 1.1.1.1/8.8.8.8", cfg["DNS1"], cfg["DNS2"])
|
||||
}
|
||||
if cfg["DOMAIN"] != "example.com" {
|
||||
t.Errorf("DOMAIN = %q, want example.com", cfg["DOMAIN"])
|
||||
}
|
||||
assert.Equal(t, "no", cfg["PEERDNS"])
|
||||
assert.Equal(t, "1.1.1.1", cfg["DNS1"])
|
||||
assert.Equal(t, "8.8.8.8", cfg["DNS2"])
|
||||
assert.Equal(t, "example.com", cfg["DOMAIN"])
|
||||
|
||||
// Clearing DNS should drop PEERDNS so DHCP-provided resolvers resume.
|
||||
err = ns.SetIfaceDNS(context.Background(), "eth0", nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("SetIfaceDNS clear: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
cfg = readIfcfg(t, dir, "eth0")
|
||||
if _, ok := cfg["PEERDNS"]; ok {
|
||||
t.Errorf("PEERDNS still present after clear: %q", cfg["PEERDNS"])
|
||||
}
|
||||
if _, ok := cfg["DNS1"]; ok {
|
||||
t.Errorf("DNS1 still present after clear: %q", cfg["DNS1"])
|
||||
}
|
||||
_, ok := cfg["PEERDNS"]
|
||||
assert.False(t, ok)
|
||||
_, ok = cfg["DNS1"]
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
// TestIfUpDownDNSEnsuresInterface verifies that SetIfaceDNS creates the
|
||||
|
|
@ -102,30 +92,21 @@ func TestNetworkScriptsDNSPeerDNS(t *testing.T) {
|
|||
func TestIfUpDownDNSEnsuresInterface(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
cfgPath := filepath.Join(dir, "interfaces")
|
||||
if err := os.WriteFile(cfgPath, []byte("auto lo\niface lo inet loopback\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := os.WriteFile(cfgPath, []byte("auto lo\niface lo inet loopback\n"), 0644)
|
||||
require.NoError(t, err)
|
||||
i := &ifUpDown{BaseConfig: cfgPath, BackupDir: cfgPath + ".backup"}
|
||||
if err := i.ReadFile(cfgPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, i.ReadFile(cfgPath))
|
||||
|
||||
// eth0 is not present in the file; SetIfaceDNS must create it.
|
||||
err := i.SetIfaceDNS(context.Background(), "eth0",
|
||||
err = i.SetIfaceDNS(context.Background(), "eth0",
|
||||
[]net.IP{net.ParseIP("1.1.1.1")}, []string{"example.com"})
|
||||
if err != nil {
|
||||
t.Fatalf("SetIfaceDNS: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Re-read from disk and confirm the stanzas were persisted.
|
||||
i.Interfaces = nil
|
||||
if err := i.ReadFile(cfgPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, i.ReadFile(cfgPath))
|
||||
interfaces, err := i.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
var found *Interface
|
||||
for _, iface := range interfaces {
|
||||
if iface.Name == "eth0" {
|
||||
|
|
@ -133,13 +114,8 @@ func TestIfUpDownDNSEnsuresInterface(t *testing.T) {
|
|||
break
|
||||
}
|
||||
}
|
||||
if found == nil {
|
||||
t.Fatal("eth0 was not persisted; SetIfaceDNS silently no-opped")
|
||||
}
|
||||
if len(found.DNS) != 1 || !found.DNS[0].Equal(net.ParseIP("1.1.1.1")) {
|
||||
t.Errorf("DNS = %v, want [1.1.1.1]", found.DNS)
|
||||
}
|
||||
if len(found.SearchDomains) != 1 || found.SearchDomains[0] != "example.com" {
|
||||
t.Errorf("SearchDomains = %v, want [example.com]", found.SearchDomains)
|
||||
}
|
||||
require.NotNil(t, found, "eth0 was not persisted; SetIfaceDNS silently no-opped")
|
||||
require.Len(t, found.DNS, 1)
|
||||
assert.True(t, found.DNS[0].Equal(net.ParseIP("1.1.1.1")), "DNS = %v, want [1.1.1.1]", found.DNS)
|
||||
assert.Equal(t, []string{"example.com"}, found.SearchDomains)
|
||||
}
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -12,6 +12,7 @@ require (
|
|||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/prometheus-community/pro-bing v0.7.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/vishvananda/netns v0.0.5
|
||||
golang.org/x/sys v0.37.0
|
||||
|
|
@ -21,8 +22,9 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,46 +6,36 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Validate the netplan configuration parser/writer functions.
|
||||
func TestIfUpDown(t *testing.T) {
|
||||
// Setup test file.
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
configPath := filepath.Join(tmpDir, "interfaces")
|
||||
testDir, err := filepath.Abs("./tests/ifupdown")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
resultsDir := filepath.Join(testDir, "results")
|
||||
err = fileCopy(filepath.Join(testDir, "interfaces"), configPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Setup ifupdown and parse test file.
|
||||
i := new(ifUpDown)
|
||||
i.BaseConfig = configPath
|
||||
i.BackupDir = configPath + ".backup"
|
||||
err = i.ReadFile(i.BaseConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err := i.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = i.SetIfaceAddresses(context.Background(), "test_eth0", []*net.IPNet{
|
||||
|
|
@ -62,9 +52,7 @@ func TestIfUpDown(t *testing.T) {
|
|||
Mask: net.CIDRMask(64, 128),
|
||||
},
|
||||
}, net.ParseIP("203.0.113.6"), net.ParseIP("fc00::1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = i.SetIfaceRoutes(context.Background(), "test_eth1", []*Route{
|
||||
|
|
@ -85,34 +73,24 @@ func TestIfUpDown(t *testing.T) {
|
|||
Metric: 100,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify we can read the modified files.
|
||||
i.Interfaces = nil
|
||||
err = i.ReadFile(i.BaseConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = i.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = i.SetIfaceAddresses(context.Background(), "test_backend", []*net.IPNet{
|
||||
|
|
@ -121,44 +99,30 @@ func TestIfUpDown(t *testing.T) {
|
|||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}, net.ParseIP("1.2.10.254"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = i.SetIfaceRoutes(context.Background(), "test_eth0", []*Route{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify we can read the modified files.
|
||||
i.Interfaces = nil
|
||||
err = i.ReadFile(i.BaseConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = i.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Cleanup.
|
||||
err = os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,47 +6,36 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Validate the netplan configuration parser/writer functions.
|
||||
func TestNetplan(t *testing.T) {
|
||||
// Setup test file.
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
configPath := filepath.Join(tmpDir, "netplan.yaml")
|
||||
testDir, err := filepath.Abs("./tests/netplan")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
resultsDir := filepath.Join(testDir, "results")
|
||||
err = fileCopy(filepath.Join(testDir, "netplan.yaml"), configPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
err = fileCopy(filepath.Join(testDir, "netplan2.yaml"), filepath.Join(tmpDir, "netplan2.yaml"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Setup ifupdown and parse test file.
|
||||
np, err := readNetplanConfigDirectory(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err := np.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = np.SetIfaceAddresses(context.Background(), "test_eth0.1556", []*net.IPNet{
|
||||
|
|
@ -63,9 +52,7 @@ func TestNetplan(t *testing.T) {
|
|||
Mask: net.CIDRMask(64, 128),
|
||||
},
|
||||
}, net.ParseIP("1.2.3.1"), net.ParseIP("fc00::1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = np.SetIfaceRoutes(context.Background(), "test_eth3", []*Route{
|
||||
|
|
@ -86,27 +73,19 @@ func TestNetplan(t *testing.T) {
|
|||
Metric: 100,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = np.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = np.SetIfaceAddresses(context.Background(), "test_eth0", []*net.IPNet{
|
||||
|
|
@ -115,37 +94,25 @@ func TestNetplan(t *testing.T) {
|
|||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}, net.ParseIP("1.2.10.254"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = np.SetIfaceRoutes(context.Background(), "test_eth0.1556", []*Route{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = np.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Cleanup.
|
||||
err = os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,15 @@ import (
|
|||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func mustCIDR(t *testing.T, s string) *net.IPNet {
|
||||
t.Helper()
|
||||
_, n, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseCIDR(%q): %v", s, err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
@ -22,9 +23,7 @@ func TestRouteString(t *testing.T) {
|
|||
Gateway: net.ParseIP("10.0.0.1"),
|
||||
Metric: 100,
|
||||
}
|
||||
if got, want := r.String(), "10.0.0.0/24 via 10.0.0.1 metric 100"; got != want {
|
||||
t.Errorf("Route.String() = %q, want %q", got, want)
|
||||
}
|
||||
assert.Equal(t, "10.0.0.0/24 via 10.0.0.1 metric 100", r.String())
|
||||
}
|
||||
|
||||
func TestInterfaceString(t *testing.T) {
|
||||
|
|
@ -38,11 +37,8 @@ func TestInterfaceString(t *testing.T) {
|
|||
{Destination: mustCIDR(t, "10.0.0.0/24"), Gateway: net.ParseIP("10.0.0.1"), Metric: 5},
|
||||
},
|
||||
}
|
||||
got := iface.String()
|
||||
want := "Name: eth0 MAC: 00:11:22:33:44:55 Addresses: [192.168.1.0/24] Gateway4: 192.168.1.1 Gateway6: <nil> Routes: [10.0.0.0/24 via 10.0.0.1 metric 5]"
|
||||
if got != want {
|
||||
t.Errorf("Interface.String()\n got %q\nwant %q", got, want)
|
||||
}
|
||||
assert.Equal(t, want, iface.String())
|
||||
}
|
||||
|
||||
func TestFindInterfaceByName(t *testing.T) {
|
||||
|
|
@ -52,39 +48,27 @@ func TestFindInterfaceByName(t *testing.T) {
|
|||
ifaces := []*Interface{eth1, eth0, pub6}
|
||||
|
||||
t.Run("by name", func(t *testing.T) {
|
||||
if got := FindInterfaceByName("eth1", ifaces); got != eth1 {
|
||||
t.Errorf("got %v, want eth1", got)
|
||||
}
|
||||
assert.Equal(t, eth1, FindInterfaceByName("eth1", ifaces))
|
||||
})
|
||||
|
||||
t.Run("public picks gateway4 interface", func(t *testing.T) {
|
||||
if got := FindInterfaceByName(Public, ifaces); got != eth0 {
|
||||
t.Errorf("got %v, want eth0", got)
|
||||
}
|
||||
assert.Equal(t, eth0, FindInterfaceByName(Public, ifaces))
|
||||
})
|
||||
|
||||
t.Run("public6 picks gateway6 interface", func(t *testing.T) {
|
||||
if got := FindInterfaceByName(Public6, ifaces); got != pub6 {
|
||||
t.Errorf("got %v, want pub6", got)
|
||||
}
|
||||
assert.Equal(t, pub6, FindInterfaceByName(Public6, ifaces))
|
||||
})
|
||||
|
||||
t.Run("not found", func(t *testing.T) {
|
||||
if got := FindInterfaceByName("missing", ifaces); got != nil {
|
||||
t.Errorf("got %v, want nil", got)
|
||||
}
|
||||
assert.Nil(t, FindInterfaceByName("missing", ifaces))
|
||||
})
|
||||
|
||||
t.Run("public with no gateway returns nil", func(t *testing.T) {
|
||||
if got := FindInterfaceByName(Public, []*Interface{eth1}); got != nil {
|
||||
t.Errorf("got %v, want nil", got)
|
||||
}
|
||||
assert.Nil(t, FindInterfaceByName(Public, []*Interface{eth1}))
|
||||
})
|
||||
|
||||
t.Run("public6 with no gateway returns nil", func(t *testing.T) {
|
||||
if got := FindInterfaceByName(Public6, []*Interface{eth1}); got != nil {
|
||||
t.Errorf("got %v, want nil", got)
|
||||
}
|
||||
assert.Nil(t, FindInterfaceByName(Public6, []*Interface{eth1}))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -97,17 +81,6 @@ func TestReorderPrimaryAddress(t *testing.T) {
|
|||
}
|
||||
return out
|
||||
}
|
||||
equal := func(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// hostIP keeps the host bits so IP.Equal matching is exercised, unlike the
|
||||
// network address returned by mustCIDR.
|
||||
|
|
@ -123,43 +96,27 @@ func TestReorderPrimaryAddress(t *testing.T) {
|
|||
|
||||
t.Run("middle moves to front", func(t *testing.T) {
|
||||
got, ok := reorderPrimaryAddress([]*net.IPNet{a, b, c}, b)
|
||||
if !ok {
|
||||
t.Fatal("ok = false, want true")
|
||||
}
|
||||
if want := []string{"192.168.1.11", "192.168.1.10", "192.168.1.12"}; !equal(addrStrings(got), want) {
|
||||
t.Errorf("got %v, want %v", addrStrings(got), want)
|
||||
}
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, []string{"192.168.1.11", "192.168.1.10", "192.168.1.12"}, addrStrings(got))
|
||||
})
|
||||
|
||||
t.Run("already first is unchanged", func(t *testing.T) {
|
||||
got, ok := reorderPrimaryAddress([]*net.IPNet{a, b, c}, a)
|
||||
if !ok {
|
||||
t.Fatal("ok = false, want true")
|
||||
}
|
||||
if want := []string{"192.168.1.10", "192.168.1.11", "192.168.1.12"}; !equal(addrStrings(got), want) {
|
||||
t.Errorf("got %v, want %v", addrStrings(got), want)
|
||||
}
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, []string{"192.168.1.10", "192.168.1.11", "192.168.1.12"}, addrStrings(got))
|
||||
})
|
||||
|
||||
t.Run("v6 target preserves v4 relative order", func(t *testing.T) {
|
||||
got, ok := reorderPrimaryAddress([]*net.IPNet{a, b, v6}, v6)
|
||||
if !ok {
|
||||
t.Fatal("ok = false, want true")
|
||||
}
|
||||
if want := []string{"2001:db8::5", "192.168.1.10", "192.168.1.11"}; !equal(addrStrings(got), want) {
|
||||
t.Errorf("got %v, want %v", addrStrings(got), want)
|
||||
}
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, []string{"2001:db8::5", "192.168.1.10", "192.168.1.11"}, addrStrings(got))
|
||||
})
|
||||
|
||||
t.Run("absent target returns false", func(t *testing.T) {
|
||||
got, ok := reorderPrimaryAddress([]*net.IPNet{a, b}, c)
|
||||
if ok {
|
||||
t.Error("ok = true, want false")
|
||||
}
|
||||
assert.False(t, ok)
|
||||
// The original slice is returned unchanged.
|
||||
if want := []string{"192.168.1.10", "192.168.1.11"}; !equal(addrStrings(got), want) {
|
||||
t.Errorf("got %v, want %v", addrStrings(got), want)
|
||||
}
|
||||
assert.Equal(t, []string{"192.168.1.10", "192.168.1.11"}, addrStrings(got))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -221,9 +178,8 @@ func TestApplyIfaceAddresses(t *testing.T) {
|
|||
{name: "ok", backend: ok},
|
||||
}
|
||||
applyIfaceAddresses(context.Background(), backends, "eth0", nil, nil, nil)
|
||||
if failing.addrCalls != 1 || ok.addrCalls != 1 {
|
||||
t.Errorf("addr calls: failing=%d ok=%d, want 1 each", failing.addrCalls, ok.addrCalls)
|
||||
}
|
||||
assert.Equal(t, 1, failing.addrCalls)
|
||||
assert.Equal(t, 1, ok.addrCalls)
|
||||
}
|
||||
|
||||
func TestApplyIfaceRoutes(t *testing.T) {
|
||||
|
|
@ -234,9 +190,8 @@ func TestApplyIfaceRoutes(t *testing.T) {
|
|||
{name: "ok", backend: ok},
|
||||
}
|
||||
applyIfaceRoutes(context.Background(), backends, "eth0", nil)
|
||||
if failing.routeCalls != 1 || ok.routeCalls != 1 {
|
||||
t.Errorf("route calls: failing=%d ok=%d, want 1 each", failing.routeCalls, ok.routeCalls)
|
||||
}
|
||||
assert.Equal(t, 1, failing.routeCalls)
|
||||
assert.Equal(t, 1, ok.routeCalls)
|
||||
}
|
||||
|
||||
func TestReloadPanels(t *testing.T) {
|
||||
|
|
@ -247,9 +202,8 @@ func TestReloadPanels(t *testing.T) {
|
|||
{name: "ok", backend: ok},
|
||||
}
|
||||
reloadPanels(context.Background(), backends)
|
||||
if failing.reloadCalls != 1 || ok.reloadCalls != 1 {
|
||||
t.Errorf("reload calls: failing=%d ok=%d, want 1 each", failing.reloadCalls, ok.reloadCalls)
|
||||
}
|
||||
assert.Equal(t, 1, failing.reloadCalls)
|
||||
assert.Equal(t, 1, ok.reloadCalls)
|
||||
}
|
||||
|
||||
func TestSetMainIPOnPanels(t *testing.T) {
|
||||
|
|
@ -260,9 +214,8 @@ func TestSetMainIPOnPanels(t *testing.T) {
|
|||
{name: "ok", backend: ok},
|
||||
}
|
||||
setMainIPOnPanels(context.Background(), backends, net.ParseIP("192.0.2.5"))
|
||||
if failing.setMainIPCalls != 1 || ok.setMainIPCalls != 1 {
|
||||
t.Errorf("setMainIP calls: failing=%d ok=%d, want 1 each", failing.setMainIPCalls, ok.setMainIPCalls)
|
||||
}
|
||||
assert.Equal(t, 1, failing.setMainIPCalls)
|
||||
assert.Equal(t, 1, ok.setMainIPCalls)
|
||||
}
|
||||
|
||||
func TestRemoveIPFromPanels(t *testing.T) {
|
||||
|
|
@ -273,9 +226,8 @@ func TestRemoveIPFromPanels(t *testing.T) {
|
|||
{name: "ok", backend: ok},
|
||||
}
|
||||
removeIPFromPanels(context.Background(), backends, net.ParseIP("192.0.2.5"))
|
||||
if failing.removeIPCalls != 1 || ok.removeIPCalls != 1 {
|
||||
t.Errorf("removeIP calls: failing=%d ok=%d, want 1 each", failing.removeIPCalls, ok.removeIPCalls)
|
||||
}
|
||||
assert.Equal(t, 1, failing.removeIPCalls)
|
||||
assert.Equal(t, 1, ok.removeIPCalls)
|
||||
}
|
||||
|
||||
// fakeDNSReaderBackend is a file backend that also reports back persisted
|
||||
|
|
@ -319,21 +271,13 @@ func TestMergeDNSFromBackends(t *testing.T) {
|
|||
|
||||
eth0 := runtime[0]
|
||||
wantDNS := []net.IP{net.ParseIP("8.8.8.8"), net.ParseIP("2001:4860:4860::8888"), net.ParseIP("1.1.1.1")}
|
||||
if !equalIPs(eth0.DNS, wantDNS) {
|
||||
t.Errorf("eth0 DNS = %v, want %v", eth0.DNS, wantDNS)
|
||||
}
|
||||
assert.True(t, equalIPs(eth0.DNS, wantDNS))
|
||||
wantSearch := []string{"example.com", "corp.example"}
|
||||
if len(eth0.SearchDomains) != len(wantSearch) || eth0.SearchDomains[0] != wantSearch[0] || eth0.SearchDomains[1] != wantSearch[1] {
|
||||
t.Errorf("eth0 SearchDomains = %v, want %v", eth0.SearchDomains, wantSearch)
|
||||
}
|
||||
assert.Equal(t, wantSearch, eth0.SearchDomains)
|
||||
|
||||
eth1 := runtime[1]
|
||||
if !equalIPs(eth1.DNS, []net.IP{net.ParseIP("9.9.9.9")}) {
|
||||
t.Errorf("eth1 DNS = %v, want [9.9.9.9]", eth1.DNS)
|
||||
}
|
||||
if len(eth1.SearchDomains) != 1 || eth1.SearchDomains[0] != "a.test" {
|
||||
t.Errorf("eth1 SearchDomains = %v, want [a.test]", eth1.SearchDomains)
|
||||
}
|
||||
assert.True(t, equalIPs(eth1.DNS, []net.IP{net.ParseIP("9.9.9.9")}))
|
||||
assert.Equal(t, []string{"a.test"}, eth1.SearchDomains)
|
||||
}
|
||||
|
||||
func equalIPs(a, b []net.IP) bool {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import (
|
|||
|
||||
"github.com/Wifx/gonetworkmanager/v3"
|
||||
"github.com/godbus/dbus/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type mockNMConnection struct {
|
||||
|
|
@ -321,9 +323,7 @@ func TestNetworkManager(t *testing.T) {
|
|||
// Setup test file.
|
||||
tmpDir := "/tmp/networkManager-netconfig-Test"
|
||||
testDir, err := filepath.Abs("./tests/networkManager")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
resultsDir := filepath.Join(testDir, "results")
|
||||
|
||||
// Update the PATH environment variable so that our nmcli is used instead of the systems.
|
||||
|
|
@ -336,15 +336,11 @@ func TestNetworkManager(t *testing.T) {
|
|||
|
||||
// Get the interfaces state.
|
||||
interfaces, err := n.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = n.SetIfaceAddresses(context.Background(), "test_eth0.1556", []*net.IPNet{
|
||||
|
|
@ -361,9 +357,7 @@ func TestNetworkManager(t *testing.T) {
|
|||
Mask: net.CIDRMask(64, 128),
|
||||
},
|
||||
}, net.ParseIP("1.2.3.1"), net.ParseIP("fc00::1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = n.SetIfaceRoutes(context.Background(), "test_eth2", []*Route{
|
||||
|
|
@ -384,9 +378,7 @@ func TestNetworkManager(t *testing.T) {
|
|||
Metric: 100,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting DNS on an interface; static DNS should disable automatic DNS.
|
||||
err = n.SetIfaceDNS(context.Background(), "test_eth0", []net.IP{
|
||||
|
|
@ -394,15 +386,11 @@ func TestNetworkManager(t *testing.T) {
|
|||
net.ParseIP("1.1.1.1"),
|
||||
net.ParseIP("2001:4860:4860::8888"),
|
||||
}, []string{"example.com"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = n.SetIfaceAddresses(context.Background(), "test_eth0", []*net.IPNet{
|
||||
|
|
@ -411,27 +399,19 @@ func TestNetworkManager(t *testing.T) {
|
|||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}, net.ParseIP("1.2.10.254"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = n.SetIfaceRoutes(context.Background(), "test_eth0.1556", []*Route{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Cleanup.
|
||||
err = os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// nmNameservers must read the modern dns-data (strings) as well as the legacy
|
||||
|
|
@ -445,30 +425,21 @@ func TestNMDNSParsing(t *testing.T) {
|
|||
}
|
||||
got := nmNameservers(group)
|
||||
want := []net.IP{net.ParseIP("8.8.8.8"), net.ParseIP("1.1.1.1")}
|
||||
if !equalIPs(got, want) {
|
||||
t.Errorf("dns-data = %v, want %v", got, want)
|
||||
}
|
||||
if search := nmSearchDomains(group); len(search) != 2 || search[0] != "a.test" || search[1] != "b.test" {
|
||||
t.Errorf("dns-search = %v, want [a.test b.test]", search)
|
||||
}
|
||||
assert.Truef(t, equalIPs(got, want), "dns-data = %v, want %v", got, want)
|
||||
search := nmSearchDomains(group)
|
||||
assert.Falsef(t, len(search) != 2 || search[0] != "a.test" || search[1] != "b.test", "dns-search = %v, want [a.test b.test]", search)
|
||||
|
||||
// Legacy ipv4 "dns" as []uint32 (decoded via uint2IP, matching addresses).
|
||||
ipv4Legacy := map[string]any{"dns": []uint32{ip2Uint(net.ParseIP("1.2.3.4"))}}
|
||||
if got := nmNameservers(ipv4Legacy); len(got) != 1 || !got[0].Equal(net.ParseIP("1.2.3.4")) {
|
||||
t.Errorf("legacy ipv4 dns = %v, want [1.2.3.4]", got)
|
||||
}
|
||||
gotV4 := nmNameservers(ipv4Legacy)
|
||||
assert.Falsef(t, len(gotV4) != 1 || !gotV4[0].Equal(net.ParseIP("1.2.3.4")), "legacy ipv4 dns = %v, want [1.2.3.4]", gotV4)
|
||||
|
||||
// Legacy ipv6 "dns" as [][]byte.
|
||||
ipv6Legacy := map[string]any{"dns": [][]byte{net.ParseIP("2001:4860:4860::8888").To16()}}
|
||||
if got := nmNameservers(ipv6Legacy); len(got) != 1 || !got[0].Equal(net.ParseIP("2001:4860:4860::8888")) {
|
||||
t.Errorf("legacy ipv6 dns = %v, want [2001:4860:4860::8888]", got)
|
||||
}
|
||||
gotV6 := nmNameservers(ipv6Legacy)
|
||||
assert.Falsef(t, len(gotV6) != 1 || !gotV6[0].Equal(net.ParseIP("2001:4860:4860::8888")), "legacy ipv6 dns = %v, want [2001:4860:4860::8888]", gotV6)
|
||||
|
||||
// Empty group yields nothing.
|
||||
if v := nmNameservers(map[string]any{}); len(v) != 0 {
|
||||
t.Errorf("empty group dns = %v, want empty", v)
|
||||
}
|
||||
if v := nmSearchDomains(map[string]any{}); len(v) != 0 {
|
||||
t.Errorf("empty group dns-search = %v, want empty", v)
|
||||
}
|
||||
assert.Emptyf(t, nmNameservers(map[string]any{}), "empty group dns, want empty")
|
||||
assert.Emptyf(t, nmSearchDomains(map[string]any{}), "empty group dns-search, want empty")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,26 +7,22 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Validate the network scripts configuration parser/writer functions.
|
||||
func TestNetworkScripts(t *testing.T) {
|
||||
// Setup test file.
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
testDir, err := filepath.Abs("./tests/networkScripts")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
resultsDir := filepath.Join(testDir, "results")
|
||||
|
||||
// Try to read the test directory for files to copy to our temporary directory.
|
||||
entries, err := os.ReadDir(testDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
for _, entry := range entries {
|
||||
if !strings.HasPrefix(entry.Name(), "ifcfg-") && !strings.HasPrefix(entry.Name(), "route-") && !strings.HasPrefix(entry.Name(), "route6-") {
|
||||
continue
|
||||
|
|
@ -35,28 +31,20 @@ func TestNetworkScripts(t *testing.T) {
|
|||
configPath := filepath.Join(testDir, entry.Name())
|
||||
tmpPath := filepath.Join(tmpDir, entry.Name())
|
||||
err = fileCopy(configPath, tmpPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Setup ifupdown and parse test file.
|
||||
ns, err := newNetworkScriptsWithConfig(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err := ns.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = ns.SetIfaceAddresses(context.Background(), "test_eth0.1556", []*net.IPNet{
|
||||
|
|
@ -73,9 +61,7 @@ func TestNetworkScripts(t *testing.T) {
|
|||
Mask: net.CIDRMask(64, 128),
|
||||
},
|
||||
}, net.ParseIP("1.2.3.1"), net.ParseIP("fc00::1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = ns.SetIfaceRoutes(context.Background(), "test_eth2", []*Route{
|
||||
|
|
@ -96,33 +82,23 @@ func TestNetworkScripts(t *testing.T) {
|
|||
Metric: 100,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify we can re-read configurations.
|
||||
ns, err = newNetworkScriptsWithConfig(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = ns.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = ns.SetIfaceAddresses(context.Background(), "test_eth0", []*net.IPNet{
|
||||
|
|
@ -131,43 +107,29 @@ func TestNetworkScripts(t *testing.T) {
|
|||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}, net.ParseIP("1.2.10.254"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = ns.SetIfaceRoutes(context.Background(), "test_eth0.1556", []*Route{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify we can re-read configurations.
|
||||
ns, err = newNetworkScriptsWithConfig(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = ns.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Cleanup.
|
||||
err = os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ package netconfig
|
|||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// parseIPRoutes is a pure transform from raw whitespace-split route fields to
|
||||
|
|
@ -12,40 +15,29 @@ func TestParseIPRoutes(t *testing.T) {
|
|||
routes := parseIPRoutes([][]string{
|
||||
{"10.0.0.0/24", "via", "10.0.0.1", "metric", "100"},
|
||||
})
|
||||
if len(routes) != 1 {
|
||||
t.Fatalf("got %d routes, want 1", len(routes))
|
||||
}
|
||||
require.Len(t, routes, 1)
|
||||
r := routes[0]
|
||||
if got := r.Destination.String(); got != "10.0.0.0/24" {
|
||||
t.Errorf("destination = %s, want 10.0.0.0/24", got)
|
||||
}
|
||||
if !r.Gateway.Equal(net.ParseIP("10.0.0.1")) {
|
||||
t.Errorf("gateway = %s, want 10.0.0.1", r.Gateway)
|
||||
}
|
||||
if r.Metric != 100 {
|
||||
t.Errorf("metric = %d, want 100", r.Metric)
|
||||
}
|
||||
assert.Equal(t, "10.0.0.0/24", r.Destination.String())
|
||||
assert.True(t, r.Gateway.Equal(net.ParseIP("10.0.0.1")))
|
||||
assert.Equal(t, 100, r.Metric)
|
||||
})
|
||||
|
||||
t.Run("default metric when absent", func(t *testing.T) {
|
||||
routes := parseIPRoutes([][]string{{"10.0.0.0/24", "via", "10.0.0.1"}})
|
||||
if len(routes) != 1 || routes[0].Metric != 256 {
|
||||
t.Fatalf("expected single route with default metric 256, got %+v", routes)
|
||||
}
|
||||
require.Len(t, routes, 1)
|
||||
assert.Equal(t, 256, routes[0].Metric)
|
||||
})
|
||||
|
||||
t.Run("metric zero falls back to default", func(t *testing.T) {
|
||||
routes := parseIPRoutes([][]string{{"10.0.0.0/24", "metric", "0"}})
|
||||
if len(routes) != 1 || routes[0].Metric != 256 {
|
||||
t.Fatalf("expected default metric 256 for metric 0, got %+v", routes)
|
||||
}
|
||||
require.Len(t, routes, 1)
|
||||
assert.Equal(t, 256, routes[0].Metric)
|
||||
})
|
||||
|
||||
t.Run("invalid metric falls back to default", func(t *testing.T) {
|
||||
routes := parseIPRoutes([][]string{{"10.0.0.0/24", "metric", "notanumber"}})
|
||||
if len(routes) != 1 || routes[0].Metric != 256 {
|
||||
t.Fatalf("expected default metric 256 for bad metric, got %+v", routes)
|
||||
}
|
||||
require.Len(t, routes, 1)
|
||||
assert.Equal(t, 256, routes[0].Metric)
|
||||
})
|
||||
|
||||
t.Run("empty and invalid entries are skipped", func(t *testing.T) {
|
||||
|
|
@ -55,12 +47,8 @@ func TestParseIPRoutes(t *testing.T) {
|
|||
{"10.0.0.0/24", "via", "nope"}, // bad gateway: skipped
|
||||
{"192.168.0.0/16", "via", "192.168.0.1"}, // valid
|
||||
})
|
||||
if len(routes) != 1 {
|
||||
t.Fatalf("got %d routes, want 1", len(routes))
|
||||
}
|
||||
if got := routes[0].Destination.String(); got != "192.168.0.0/16" {
|
||||
t.Errorf("destination = %s, want 192.168.0.0/16", got)
|
||||
}
|
||||
require.Len(t, routes, 1)
|
||||
assert.Equal(t, "192.168.0.0/16", routes[0].Destination.String())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -69,67 +57,45 @@ func TestNetworkScriptsParseIP(t *testing.T) {
|
|||
ns := &networkScripts{}
|
||||
|
||||
t.Run("missing IPADDR returns nil", func(t *testing.T) {
|
||||
if got := ns.ParseIP(map[string]string{}, ""); got != nil {
|
||||
t.Errorf("got %v, want nil", got)
|
||||
}
|
||||
assert.Nil(t, ns.ParseIP(map[string]string{}, ""))
|
||||
})
|
||||
|
||||
t.Run("empty IPADDR returns nil", func(t *testing.T) {
|
||||
if got := ns.ParseIP(map[string]string{"IPADDR": ""}, ""); got != nil {
|
||||
t.Errorf("got %v, want nil", got)
|
||||
}
|
||||
assert.Nil(t, ns.ParseIP(map[string]string{"IPADDR": ""}, ""))
|
||||
})
|
||||
|
||||
t.Run("explicit prefix", func(t *testing.T) {
|
||||
got := ns.ParseIP(map[string]string{"IPADDR": "192.168.1.5", "PREFIX": "24"}, "")
|
||||
if got == nil {
|
||||
t.Fatal("got nil")
|
||||
}
|
||||
if !got.IP.Equal(net.ParseIP("192.168.1.5")) {
|
||||
t.Errorf("IP = %s, want 192.168.1.5", got.IP)
|
||||
}
|
||||
if ones, _ := got.Mask.Size(); ones != 24 {
|
||||
t.Errorf("prefix = %d, want 24", ones)
|
||||
}
|
||||
require.NotNil(t, got)
|
||||
assert.True(t, got.IP.Equal(net.ParseIP("192.168.1.5")))
|
||||
ones, _ := got.Mask.Size()
|
||||
assert.Equal(t, 24, ones)
|
||||
})
|
||||
|
||||
t.Run("prefix derived from netmask", func(t *testing.T) {
|
||||
got := ns.ParseIP(map[string]string{"IPADDR": "10.1.2.3", "NETMASK": "255.255.255.0"}, "")
|
||||
if got == nil {
|
||||
t.Fatal("got nil")
|
||||
}
|
||||
if ones, _ := got.Mask.Size(); ones != 24 {
|
||||
t.Errorf("prefix = %d, want 24 (from netmask)", ones)
|
||||
}
|
||||
require.NotNil(t, got)
|
||||
ones, _ := got.Mask.Size()
|
||||
assert.Equal(t, 24, ones)
|
||||
})
|
||||
|
||||
t.Run("defaults to /16 with no prefix or netmask", func(t *testing.T) {
|
||||
got := ns.ParseIP(map[string]string{"IPADDR": "10.1.2.3"}, "")
|
||||
if got == nil {
|
||||
t.Fatal("got nil")
|
||||
}
|
||||
if ones, _ := got.Mask.Size(); ones != 16 {
|
||||
t.Errorf("prefix = %d, want default 16", ones)
|
||||
}
|
||||
require.NotNil(t, got)
|
||||
ones, _ := got.Mask.Size()
|
||||
assert.Equal(t, 16, ones)
|
||||
})
|
||||
|
||||
t.Run("indexed keys", func(t *testing.T) {
|
||||
cfg := map[string]string{"IPADDR0": "172.16.0.9", "PREFIX0": "30"}
|
||||
got := ns.ParseIP(cfg, "0")
|
||||
if got == nil {
|
||||
t.Fatal("got nil")
|
||||
}
|
||||
if !got.IP.Equal(net.ParseIP("172.16.0.9")) {
|
||||
t.Errorf("IP = %s, want 172.16.0.9", got.IP)
|
||||
}
|
||||
if ones, _ := got.Mask.Size(); ones != 30 {
|
||||
t.Errorf("prefix = %d, want 30", ones)
|
||||
}
|
||||
require.NotNil(t, got)
|
||||
assert.True(t, got.IP.Equal(net.ParseIP("172.16.0.9")))
|
||||
ones, _ := got.Mask.Size()
|
||||
assert.Equal(t, 30, ones)
|
||||
})
|
||||
|
||||
t.Run("invalid address returns nil", func(t *testing.T) {
|
||||
if got := ns.ParseIP(map[string]string{"IPADDR": "not-an-ip", "PREFIX": "24"}, ""); got != nil {
|
||||
t.Errorf("got %v, want nil", got)
|
||||
}
|
||||
assert.Nil(t, ns.ParseIP(map[string]string{"IPADDR": "not-an-ip", "PREFIX": "24"}, ""))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,26 +7,23 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Validate the networkd configuration parser/writer functions.
|
||||
func TestNetworkd(t *testing.T) {
|
||||
// Setup test file.
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
testDir, err := filepath.Abs("./tests/networkd")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
resultsDir := filepath.Join(testDir, "results")
|
||||
|
||||
// Try to read the test directory for files to copy to our temporary directory.
|
||||
entries, err := os.ReadDir(testDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
for _, entry := range entries {
|
||||
if !strings.HasSuffix(entry.Name(), ".network") {
|
||||
continue
|
||||
|
|
@ -35,28 +32,20 @@ func TestNetworkd(t *testing.T) {
|
|||
configPath := filepath.Join(testDir, entry.Name())
|
||||
tmpPath := filepath.Join(tmpDir, entry.Name())
|
||||
err = fileCopy(configPath, tmpPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Setup ifupdown and parse test file.
|
||||
n, err := readNetworkdConfigDirectory(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err := n.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = n.SetIfaceAddresses(context.Background(), "test_eth0.1556", []*net.IPNet{
|
||||
|
|
@ -73,9 +62,7 @@ func TestNetworkd(t *testing.T) {
|
|||
Mask: net.CIDRMask(64, 128),
|
||||
},
|
||||
}, net.ParseIP("1.2.3.1"), net.ParseIP("fc00::1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = n.SetIfaceRoutes(context.Background(), "test_eth2", []*Route{
|
||||
|
|
@ -96,33 +83,23 @@ func TestNetworkd(t *testing.T) {
|
|||
Metric: 100,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify we can re-read configurations.
|
||||
n, err = readNetworkdConfigDirectory(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = n.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test setting the IP addresses on an interface.
|
||||
err = n.SetIfaceAddresses(context.Background(), "test_eth0", []*net.IPNet{
|
||||
|
|
@ -131,43 +108,29 @@ func TestNetworkd(t *testing.T) {
|
|||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}, net.ParseIP("1.2.10.254"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test setting routes on an interface.
|
||||
err = n.SetIfaceRoutes(context.Background(), "test_eth0.1556", []*Route{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify we can re-read configurations.
|
||||
n, err = readNetworkdConfigDirectory(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the interfaces state.
|
||||
interfaces, err = n.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify interfaces read from file.
|
||||
err = testVerifyInterfaces(interfaces, resultsDir, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Read the current file and expected state.
|
||||
err = testVerifyResults(resultsDir, tmpDir, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Cleanup.
|
||||
err = os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
174
options_test.go
174
options_test.go
|
|
@ -8,6 +8,9 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// captureLogger records the last formatted message so SetLogger can be
|
||||
|
|
@ -22,57 +25,34 @@ func (c *captureLogger) Println(args ...interface{}) { c.printlnCa
|
|||
|
||||
func TestConfigOptionsDefaults(t *testing.T) {
|
||||
o := newConfigOptions()
|
||||
if o.testAddress != defaultInternetTestAddress {
|
||||
t.Errorf("default testAddress = %q, want %q", o.testAddress, defaultInternetTestAddress)
|
||||
}
|
||||
if o.skipConnectivityCheck {
|
||||
t.Error("skipConnectivityCheck = true, want false by default")
|
||||
}
|
||||
if o.connectivityTimeout != defaultConnectivityTimeout {
|
||||
t.Errorf("default connectivityTimeout = %v, want %v", o.connectivityTimeout, defaultConnectivityTimeout)
|
||||
}
|
||||
if o.pingCount != defaultPingCount {
|
||||
t.Errorf("default pingCount = %d, want %d", o.pingCount, defaultPingCount)
|
||||
}
|
||||
if o.pingTimeout != defaultPingTimeout {
|
||||
t.Errorf("default pingTimeout = %v, want %v", o.pingTimeout, defaultPingTimeout)
|
||||
}
|
||||
if o.backupRetention != defaultBackupRetention {
|
||||
t.Errorf("default backupRetention = %d, want %d", o.backupRetention, defaultBackupRetention)
|
||||
}
|
||||
if o.allowPrimaryRemoval {
|
||||
t.Error("allowPrimaryRemoval = true, want false by default")
|
||||
}
|
||||
if o.skipPanels {
|
||||
t.Error("skipPanels = true, want false by default")
|
||||
}
|
||||
assert.Equal(t, defaultInternetTestAddress, o.testAddress)
|
||||
assert.False(t, o.skipConnectivityCheck)
|
||||
assert.Equal(t, defaultConnectivityTimeout, o.connectivityTimeout)
|
||||
assert.Equal(t, defaultPingCount, o.pingCount)
|
||||
assert.Equal(t, defaultPingTimeout, o.pingTimeout)
|
||||
assert.Equal(t, defaultBackupRetention, o.backupRetention)
|
||||
assert.False(t, o.allowPrimaryRemoval)
|
||||
assert.False(t, o.skipPanels)
|
||||
}
|
||||
|
||||
func TestWithTestAddress(t *testing.T) {
|
||||
o := newConfigOptions(WithTestAddress("http://canary.example/health"))
|
||||
if o.testAddress != "http://canary.example/health" {
|
||||
t.Errorf("testAddress = %q, want the overridden value", o.testAddress)
|
||||
}
|
||||
assert.Equal(t, "http://canary.example/health", o.testAddress)
|
||||
// An empty address must not clobber the default.
|
||||
o = newConfigOptions(WithTestAddress(""))
|
||||
if o.testAddress != defaultInternetTestAddress {
|
||||
t.Errorf("empty WithTestAddress changed default to %q", o.testAddress)
|
||||
}
|
||||
assert.Equal(t, defaultInternetTestAddress, o.testAddress)
|
||||
}
|
||||
|
||||
func TestWithConnectivityCheck(t *testing.T) {
|
||||
if o := newConfigOptions(WithConnectivityCheck(false)); !o.skipConnectivityCheck {
|
||||
t.Error("WithConnectivityCheck(false) did not set skipConnectivityCheck")
|
||||
}
|
||||
if o := newConfigOptions(WithConnectivityCheck(true)); o.skipConnectivityCheck {
|
||||
t.Error("WithConnectivityCheck(true) set skipConnectivityCheck")
|
||||
}
|
||||
o := newConfigOptions(WithConnectivityCheck(false))
|
||||
assert.True(t, o.skipConnectivityCheck)
|
||||
o = newConfigOptions(WithConnectivityCheck(true))
|
||||
assert.False(t, o.skipConnectivityCheck)
|
||||
}
|
||||
|
||||
func TestWithSkipConnectivityCheck(t *testing.T) {
|
||||
if o := newConfigOptions(WithSkipConnectivityCheck()); !o.skipConnectivityCheck {
|
||||
t.Error("WithSkipConnectivityCheck did not set skipConnectivityCheck")
|
||||
}
|
||||
o := newConfigOptions(WithSkipConnectivityCheck())
|
||||
assert.True(t, o.skipConnectivityCheck)
|
||||
}
|
||||
|
||||
func TestSetLogger(t *testing.T) {
|
||||
|
|
@ -81,74 +61,58 @@ func TestSetLogger(t *testing.T) {
|
|||
|
||||
cap := &captureLogger{}
|
||||
SetLogger(cap)
|
||||
if logger != cap {
|
||||
t.Fatal("SetLogger did not replace the package logger")
|
||||
}
|
||||
require.Equal(t, cap, logger)
|
||||
logger.Printf("hi %d", 1)
|
||||
logger.Println("hi")
|
||||
if cap.printfCalls != 1 || cap.printlnCalls != 1 {
|
||||
t.Errorf("logger not used: printf=%d println=%d", cap.printfCalls, cap.printlnCalls)
|
||||
}
|
||||
assert.Equal(t, 1, cap.printfCalls)
|
||||
assert.Equal(t, 1, cap.printlnCalls)
|
||||
|
||||
// A nil logger must be ignored, leaving the current logger in place.
|
||||
SetLogger(nil)
|
||||
if logger != cap {
|
||||
t.Error("SetLogger(nil) replaced the logger")
|
||||
}
|
||||
assert.Equal(t, cap, logger)
|
||||
}
|
||||
|
||||
func TestWithConnectivityTimeout(t *testing.T) {
|
||||
if o := newConfigOptions(WithConnectivityTimeout(5 * time.Second)); o.connectivityTimeout != 5*time.Second {
|
||||
t.Errorf("connectivityTimeout = %v, want 5s", o.connectivityTimeout)
|
||||
}
|
||||
o := newConfigOptions(WithConnectivityTimeout(5 * time.Second))
|
||||
assert.Equal(t, 5*time.Second, o.connectivityTimeout)
|
||||
// Non-positive values must not clobber the default.
|
||||
if o := newConfigOptions(WithConnectivityTimeout(0)); o.connectivityTimeout != defaultConnectivityTimeout {
|
||||
t.Errorf("zero WithConnectivityTimeout changed default to %v", o.connectivityTimeout)
|
||||
}
|
||||
o = newConfigOptions(WithConnectivityTimeout(0))
|
||||
assert.Equal(t, defaultConnectivityTimeout, o.connectivityTimeout)
|
||||
}
|
||||
|
||||
func TestWithPingCount(t *testing.T) {
|
||||
if o := newConfigOptions(WithPingCount(3)); o.pingCount != 3 {
|
||||
t.Errorf("pingCount = %d, want 3", o.pingCount)
|
||||
}
|
||||
o := newConfigOptions(WithPingCount(3))
|
||||
assert.Equal(t, 3, o.pingCount)
|
||||
// Non-positive values must not clobber the default.
|
||||
if o := newConfigOptions(WithPingCount(0)); o.pingCount != defaultPingCount {
|
||||
t.Errorf("zero WithPingCount changed default to %d", o.pingCount)
|
||||
}
|
||||
o = newConfigOptions(WithPingCount(0))
|
||||
assert.Equal(t, defaultPingCount, o.pingCount)
|
||||
}
|
||||
|
||||
func TestWithPingTimeout(t *testing.T) {
|
||||
if o := newConfigOptions(WithPingTimeout(30 * time.Second)); o.pingTimeout != 30*time.Second {
|
||||
t.Errorf("pingTimeout = %v, want 30s", o.pingTimeout)
|
||||
}
|
||||
if o := newConfigOptions(WithPingTimeout(0)); o.pingTimeout != defaultPingTimeout {
|
||||
t.Errorf("zero WithPingTimeout changed default to %v", o.pingTimeout)
|
||||
}
|
||||
o := newConfigOptions(WithPingTimeout(30 * time.Second))
|
||||
assert.Equal(t, 30*time.Second, o.pingTimeout)
|
||||
o = newConfigOptions(WithPingTimeout(0))
|
||||
assert.Equal(t, defaultPingTimeout, o.pingTimeout)
|
||||
}
|
||||
|
||||
func TestWithBackupRetention(t *testing.T) {
|
||||
if o := newConfigOptions(WithBackupRetention(10)); o.backupRetention != 10 {
|
||||
t.Errorf("backupRetention = %d, want 10", o.backupRetention)
|
||||
}
|
||||
o := newConfigOptions(WithBackupRetention(10))
|
||||
assert.Equal(t, 10, o.backupRetention)
|
||||
// Zero/negative disables pruning (keeps all backups).
|
||||
if o := newConfigOptions(WithBackupRetention(0)); o.backupRetention != 0 {
|
||||
t.Errorf("backupRetention = %d, want 0", o.backupRetention)
|
||||
}
|
||||
o = newConfigOptions(WithBackupRetention(0))
|
||||
assert.Equal(t, 0, o.backupRetention)
|
||||
}
|
||||
|
||||
func TestWithAllowPrimaryRemoval(t *testing.T) {
|
||||
if o := newConfigOptions(WithAllowPrimaryRemoval(true)); !o.allowPrimaryRemoval {
|
||||
t.Error("WithAllowPrimaryRemoval(true) did not set allowPrimaryRemoval")
|
||||
}
|
||||
o := newConfigOptions(WithAllowPrimaryRemoval(true))
|
||||
assert.True(t, o.allowPrimaryRemoval)
|
||||
}
|
||||
|
||||
func TestWithSkipPanels(t *testing.T) {
|
||||
if o := newConfigOptions(WithSkipPanels(true)); !o.skipPanels {
|
||||
t.Error("WithSkipPanels(true) did not set skipPanels")
|
||||
}
|
||||
if o := newConfigOptions(WithSkipPanels(false)); o.skipPanels {
|
||||
t.Error("WithSkipPanels(false) set skipPanels")
|
||||
}
|
||||
o := newConfigOptions(WithSkipPanels(true))
|
||||
assert.True(t, o.skipPanels)
|
||||
o = newConfigOptions(WithSkipPanels(false))
|
||||
assert.False(t, o.skipPanels)
|
||||
}
|
||||
|
||||
// applyIfaceDNS must invoke every backend even when an earlier one fails.
|
||||
|
|
@ -160,22 +124,14 @@ func TestApplyIfaceDNS(t *testing.T) {
|
|||
{name: "ok", backend: ok},
|
||||
}
|
||||
applyIfaceDNS(context.Background(), backends, "eth0", []net.IP{net.ParseIP("8.8.8.8")}, []string{"example.com"})
|
||||
if failing.dnsCalls != 1 || ok.dnsCalls != 1 {
|
||||
t.Errorf("dns calls: failing=%d ok=%d, want 1 each", failing.dnsCalls, ok.dnsCalls)
|
||||
}
|
||||
assert.Equal(t, 1, failing.dnsCalls)
|
||||
assert.Equal(t, 1, ok.dnsCalls)
|
||||
}
|
||||
|
||||
func TestIPStrings(t *testing.T) {
|
||||
got := ipStrings([]net.IP{net.ParseIP("8.8.8.8"), nil, net.ParseIP("2001:4860:4860::8888")})
|
||||
want := []string{"8.8.8.8", "2001:4860:4860::8888"}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("ipStrings = %v, want %v", got, want)
|
||||
}
|
||||
for i := range want {
|
||||
if got[i] != want[i] {
|
||||
t.Errorf("ipStrings[%d] = %q, want %q", i, got[i], want[i])
|
||||
}
|
||||
}
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
// TestNetplanDNS round-trips DNS through the netplan backend: SetIfaceDNS writes
|
||||
|
|
@ -183,29 +139,21 @@ func TestIPStrings(t *testing.T) {
|
|||
func TestNetplanDNS(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
config := "network:\n version: 2\n ethernets:\n eth0:\n addresses: [192.0.2.10/24]\n"
|
||||
if err := os.WriteFile(filepath.Join(tmpDir, "01-test.yaml"), []byte(config), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := os.WriteFile(filepath.Join(tmpDir, "01-test.yaml"), []byte(config), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
np, err := readNetplanConfigDirectory(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
servers := []net.IP{net.ParseIP("8.8.8.8"), net.ParseIP("2001:4860:4860::8888")}
|
||||
if err := np.SetIfaceDNS(context.Background(), "eth0", servers, []string{"example.com", "corp.example"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = np.SetIfaceDNS(context.Background(), "eth0", servers, []string{"example.com", "corp.example"})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Re-read from disk so we exercise the written config, not in-memory state.
|
||||
np, err = readNetplanConfigDirectory(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
ifaces, err := np.GetInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
var eth0 *Interface
|
||||
for _, i := range ifaces {
|
||||
|
|
@ -213,13 +161,7 @@ func TestNetplanDNS(t *testing.T) {
|
|||
eth0 = i
|
||||
}
|
||||
}
|
||||
if eth0 == nil {
|
||||
t.Fatal("eth0 not found after SetIfaceDNS")
|
||||
}
|
||||
if len(eth0.DNS) != 2 || !eth0.DNS[0].Equal(servers[0]) || !eth0.DNS[1].Equal(servers[1]) {
|
||||
t.Errorf("DNS = %v, want %v", eth0.DNS, servers)
|
||||
}
|
||||
if len(eth0.SearchDomains) != 2 || eth0.SearchDomains[0] != "example.com" || eth0.SearchDomains[1] != "corp.example" {
|
||||
t.Errorf("SearchDomains = %v, want [example.com corp.example]", eth0.SearchDomains)
|
||||
}
|
||||
require.NotNil(t, eth0)
|
||||
assert.True(t, len(eth0.DNS) == 2 && eth0.DNS[0].Equal(servers[0]) && eth0.DNS[1].Equal(servers[1]))
|
||||
assert.True(t, len(eth0.SearchDomains) == 2 && eth0.SearchDomains[0] == "example.com" && eth0.SearchDomains[1] == "corp.example")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
|
@ -19,17 +20,11 @@ func TestIP2UintRoundTrip(t *testing.T) {
|
|||
cases := []string{"0.0.0.0", "1.2.3.4", "192.168.1.255", "255.255.255.255"}
|
||||
for _, c := range cases {
|
||||
ip := net.ParseIP(c)
|
||||
if ip == nil {
|
||||
t.Fatalf("could not parse %q", c)
|
||||
}
|
||||
require.NotNil(t, ip, "could not parse %q", c)
|
||||
got := uint2IP(ip2Uint(ip))
|
||||
if !got.Equal(ip) {
|
||||
t.Errorf("round trip of %s: got %s", c, got)
|
||||
}
|
||||
assert.True(t, got.Equal(ip), "round trip of %s: got %s", c, got)
|
||||
// uint2IP should produce the canonical four-byte representation.
|
||||
if len(got) != net.IPv4len {
|
||||
t.Errorf("uint2IP(%s) length = %d, want %d", c, len(got), net.IPv4len)
|
||||
}
|
||||
assert.Equal(t, net.IPv4len, len(got), "uint2IP(%s) length", c)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -38,13 +33,9 @@ func TestIP2UintRoundTrip(t *testing.T) {
|
|||
func TestIP2UintAcceptsBothRepresentations(t *testing.T) {
|
||||
ip16 := net.ParseIP("10.20.30.40")
|
||||
ip4 := ip16.To4()
|
||||
if ip4 == nil {
|
||||
t.Fatal("expected an IPv4 address")
|
||||
}
|
||||
if ip2Uint(ip16) != ip2Uint(ip4) {
|
||||
t.Errorf("ip2Uint disagrees for 16-byte (%d) and 4-byte (%d) forms",
|
||||
ip2Uint(ip16), ip2Uint(ip4))
|
||||
}
|
||||
require.NotNil(t, ip4, "expected an IPv4 address")
|
||||
assert.Equal(t, ip2Uint(ip16), ip2Uint(ip4),
|
||||
"ip2Uint disagrees for 16-byte and 4-byte forms")
|
||||
}
|
||||
|
||||
func TestAllFF(t *testing.T) {
|
||||
|
|
@ -60,9 +51,7 @@ func TestAllFF(t *testing.T) {
|
|||
{[]byte{0xff, 0xff, 0xfe}, false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := allFF(c.in); got != c.want {
|
||||
t.Errorf("allFF(%v) = %v, want %v", c.in, got, c.want)
|
||||
}
|
||||
assert.Equal(t, c.want, allFF(c.in), "allFF(%v)", c.in)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,14 +68,10 @@ func TestGetBroadcast(t *testing.T) {
|
|||
}
|
||||
for _, c := range cases {
|
||||
_, network, err := net.ParseCIDR(c.cidr)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseCIDR(%q): %v", c.cidr, err)
|
||||
}
|
||||
require.NoError(t, err, "ParseCIDR(%q)", c.cidr)
|
||||
got := getBroadcast(network)
|
||||
want := net.ParseIP(c.want)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("getBroadcast(%s) = %s, want %s", c.cidr, got, c.want)
|
||||
}
|
||||
assert.True(t, got.Equal(want), "getBroadcast(%s) = %s, want %s", c.cidr, got, c.want)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,243 +83,159 @@ func TestGetBroadcastMixedFamily(t *testing.T) {
|
|||
Mask: net.CIDRMask(96+24, 128), // /24 expressed as a 16-byte mask.
|
||||
}
|
||||
got := getBroadcast(network)
|
||||
if want := net.ParseIP("192.168.1.255"); !got.Equal(want) {
|
||||
t.Errorf("getBroadcast mixed family = %s, want %s", got, want)
|
||||
}
|
||||
want := net.ParseIP("192.168.1.255")
|
||||
assert.True(t, got.Equal(want), "getBroadcast mixed family = %s, want %s", got, want)
|
||||
}
|
||||
|
||||
func TestSortableDirEntries(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
names := []string{"zebra", "alpha", "mike", "bravo"}
|
||||
for _, n := range names {
|
||||
if err := os.WriteFile(filepath.Join(dir, n), nil, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, n), nil, 0o644))
|
||||
}
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
// Shuffle into a known unsorted order before sorting.
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
return entries[i].Name() > entries[j].Name()
|
||||
})
|
||||
|
||||
sortable := sortableDirEntries(entries)
|
||||
if sortable.Len() != len(names) {
|
||||
t.Errorf("Len() = %d, want %d", sortable.Len(), len(names))
|
||||
}
|
||||
assert.Equal(t, len(names), sortable.Len(), "Len()")
|
||||
sort.Sort(sortable)
|
||||
|
||||
want := []string{"alpha", "bravo", "mike", "zebra"}
|
||||
for i, w := range want {
|
||||
if entries[i].Name() != w {
|
||||
t.Errorf("sorted[%d] = %s, want %s", i, entries[i].Name(), w)
|
||||
}
|
||||
assert.Equal(t, w, entries[i].Name(), "sorted[%d]", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntStringYAML(t *testing.T) {
|
||||
t.Run("int", func(t *testing.T) {
|
||||
var v intString
|
||||
if err := yaml.Unmarshal([]byte("42\n"), &v); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.Int == nil || *v.Int != 42 {
|
||||
t.Fatalf("Int = %v, want 42", v.Int)
|
||||
}
|
||||
if v.String != nil {
|
||||
t.Errorf("String should be nil, got %v", *v.String)
|
||||
}
|
||||
require.NoError(t, yaml.Unmarshal([]byte("42\n"), &v))
|
||||
require.NotNil(t, v.Int, "Int = %v, want 42", v.Int)
|
||||
assert.Equal(t, 42, *v.Int)
|
||||
assert.Nil(t, v.String, "String should be nil")
|
||||
out, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := string(out); got != "42\n" {
|
||||
t.Errorf("marshal = %q, want %q", got, "42\n")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "42\n", string(out), "marshal")
|
||||
})
|
||||
|
||||
t.Run("string", func(t *testing.T) {
|
||||
var v intString
|
||||
if err := yaml.Unmarshal([]byte("auto\n"), &v); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.String == nil || *v.String != "auto" {
|
||||
t.Fatalf("String = %v, want auto", v.String)
|
||||
}
|
||||
if v.Int != nil {
|
||||
t.Errorf("Int should be nil, got %v", *v.Int)
|
||||
}
|
||||
require.NoError(t, yaml.Unmarshal([]byte("auto\n"), &v))
|
||||
require.NotNil(t, v.String, "String = %v, want auto", v.String)
|
||||
assert.Equal(t, "auto", *v.String)
|
||||
assert.Nil(t, v.Int, "Int should be nil")
|
||||
out, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := string(out); got != "auto\n" {
|
||||
t.Errorf("marshal = %q, want %q", got, "auto\n")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "auto\n", string(out), "marshal")
|
||||
})
|
||||
|
||||
t.Run("empty marshals to null", func(t *testing.T) {
|
||||
out, err := yaml.Marshal(intString{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := string(out); got != "null\n" {
|
||||
t.Errorf("marshal of empty = %q, want %q", got, "null\n")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "null\n", string(out), "marshal of empty")
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntStringJSON(t *testing.T) {
|
||||
t.Run("int", func(t *testing.T) {
|
||||
var v intString
|
||||
if err := json.Unmarshal([]byte("42"), &v); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.Int == nil || *v.Int != 42 {
|
||||
t.Fatalf("Int = %v, want 42", v.Int)
|
||||
}
|
||||
require.NoError(t, json.Unmarshal([]byte("42"), &v))
|
||||
require.NotNil(t, v.Int, "Int = %v, want 42", v.Int)
|
||||
assert.Equal(t, 42, *v.Int)
|
||||
out, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := string(out); got != "42" {
|
||||
t.Errorf("marshal = %q, want %q", got, "42")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "42", string(out), "marshal")
|
||||
})
|
||||
|
||||
t.Run("string", func(t *testing.T) {
|
||||
var v intString
|
||||
if err := json.Unmarshal([]byte(`"auto"`), &v); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.String == nil || *v.String != "auto" {
|
||||
t.Fatalf("String = %v, want auto", v.String)
|
||||
}
|
||||
require.NoError(t, json.Unmarshal([]byte(`"auto"`), &v))
|
||||
require.NotNil(t, v.String, "String = %v, want auto", v.String)
|
||||
assert.Equal(t, "auto", *v.String)
|
||||
out, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := string(out); got != `"auto"` {
|
||||
t.Errorf("marshal = %q, want %q", got, `"auto"`)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, `"auto"`, string(out), "marshal")
|
||||
})
|
||||
|
||||
t.Run("invalid", func(t *testing.T) {
|
||||
var v intString
|
||||
if err := json.Unmarshal([]byte("{}"), &v); err == nil {
|
||||
t.Error("expected error for object input, got nil")
|
||||
}
|
||||
err := json.Unmarshal([]byte("{}"), &v)
|
||||
assert.Error(t, err, "expected error for object input, got nil")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRunCommand(t *testing.T) {
|
||||
t.Run("stdout", func(t *testing.T) {
|
||||
out, err := runCommand(context.Background(), "printf", "line1\nline2\n")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "unexpected error")
|
||||
want := []string{"line1", "line2"}
|
||||
if !reflect.DeepEqual(out, want) {
|
||||
t.Errorf("out = %v, want %v", out, want)
|
||||
}
|
||||
assert.Equal(t, want, out, "out")
|
||||
})
|
||||
|
||||
t.Run("nonzero exit", func(t *testing.T) {
|
||||
_, err := runCommand(context.Background(), "false")
|
||||
if err == nil {
|
||||
t.Error("expected error for failing command, got nil")
|
||||
}
|
||||
assert.Error(t, err, "expected error for failing command, got nil")
|
||||
})
|
||||
|
||||
t.Run("missing binary", func(t *testing.T) {
|
||||
_, err := runCommand(context.Background(), "this-binary-should-not-exist-12345")
|
||||
if err == nil {
|
||||
t.Error("expected error for missing binary, got nil")
|
||||
}
|
||||
assert.Error(t, err, "expected error for missing binary, got nil")
|
||||
})
|
||||
}
|
||||
|
||||
func TestTestInternet(t *testing.T) {
|
||||
if !testInternet(context.Background(), "test_success", 0) {
|
||||
t.Error("test_success sentinel should report success")
|
||||
}
|
||||
if testInternet(context.Background(), "test_fail", 0) {
|
||||
t.Error("test_fail sentinel should report failure")
|
||||
}
|
||||
assert.True(t, testInternet(context.Background(), "test_success", 0),
|
||||
"test_success sentinel should report success")
|
||||
assert.False(t, testInternet(context.Background(), "test_fail", 0),
|
||||
"test_fail sentinel should report failure")
|
||||
}
|
||||
|
||||
func TestFileCopyAndMove(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
src := filepath.Join(dir, "src.txt")
|
||||
content := []byte("hello world\n")
|
||||
if err := os.WriteFile(src, content, 0o640); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(src, content, 0o640))
|
||||
|
||||
t.Run("fileCopy preserves contents and mode", func(t *testing.T) {
|
||||
dst := filepath.Join(dir, "copy.txt")
|
||||
if err := fileCopy(src, dst); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, fileCopy(src, dst))
|
||||
got, err := os.ReadFile(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, content) {
|
||||
t.Errorf("copied contents = %q, want %q", got, content)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, content, got, "copied contents")
|
||||
fi, err := os.Stat(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fi.Mode().Perm() != 0o640 {
|
||||
t.Errorf("copied mode = %v, want 0640", fi.Mode().Perm())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, os.FileMode(0o640), fi.Mode().Perm(), "copied mode")
|
||||
})
|
||||
|
||||
t.Run("fileCopy missing source errors", func(t *testing.T) {
|
||||
if err := fileCopy(filepath.Join(dir, "nope"), filepath.Join(dir, "out")); err == nil {
|
||||
t.Error("expected error for missing source")
|
||||
}
|
||||
err := fileCopy(filepath.Join(dir, "nope"), filepath.Join(dir, "out"))
|
||||
assert.Error(t, err, "expected error for missing source")
|
||||
})
|
||||
|
||||
t.Run("fileMoveCopy removes source", func(t *testing.T) {
|
||||
moveSrc := filepath.Join(dir, "movesrc.txt")
|
||||
if err := os.WriteFile(moveSrc, content, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(moveSrc, content, 0o644))
|
||||
dst := filepath.Join(dir, "moved.txt")
|
||||
if err := fileMoveCopy(moveSrc, dst); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := os.Stat(moveSrc); !os.IsNotExist(err) {
|
||||
t.Errorf("source should be gone, stat err = %v", err)
|
||||
}
|
||||
require.NoError(t, fileMoveCopy(moveSrc, dst))
|
||||
_, err := os.Stat(moveSrc)
|
||||
assert.True(t, os.IsNotExist(err), "source should be gone, stat err = %v", err)
|
||||
got, err := os.ReadFile(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, content) {
|
||||
t.Errorf("moved contents = %q, want %q", got, content)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, content, got, "moved contents")
|
||||
})
|
||||
|
||||
t.Run("fileMove same device renames", func(t *testing.T) {
|
||||
moveSrc := filepath.Join(dir, "rename-src.txt")
|
||||
if err := os.WriteFile(moveSrc, content, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, os.WriteFile(moveSrc, content, 0o644))
|
||||
dst := filepath.Join(dir, "renamed.txt")
|
||||
if err := fileMove(moveSrc, dst); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := os.Stat(moveSrc); !os.IsNotExist(err) {
|
||||
t.Errorf("source should be gone after move, stat err = %v", err)
|
||||
}
|
||||
if _, err := os.Stat(dst); err != nil {
|
||||
t.Errorf("destination missing after move: %v", err)
|
||||
}
|
||||
require.NoError(t, fileMove(moveSrc, dst))
|
||||
_, err := os.Stat(moveSrc)
|
||||
assert.True(t, os.IsNotExist(err), "source should be gone after move, stat err = %v", err)
|
||||
_, err = os.Stat(dst)
|
||||
assert.NoError(t, err, "destination missing after move")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue