From 821cf58ca22f9a34bae25f4f9e676d8858ee3327 Mon Sep 17 00:00:00 2001 From: James Coleman Date: Wed, 1 Jul 2026 17:51:41 -0500 Subject: [PATCH] Switch unit tests to testify --- cloudinit_test.go | 138 ++++------------ configurator_linux_test.go | 318 ++++++++++-------------------------- cpanel_test.go | 104 ++++-------- dns_backends_test.go | 74 +++------ go.mod | 4 +- ifupdown_test.go | 78 +++------ netplan_test.go | 75 +++------ networkConfigurator_test.go | 124 ++++---------- networkManager_test.go | 73 +++------ networkScripts_test.go | 82 +++------- networkScripts_unit_test.go | 98 ++++------- networkd_test.go | 83 +++------- options_test.go | 174 +++++++------------- utils_unit_test.go | 241 ++++++++------------------- 14 files changed, 481 insertions(+), 1185 deletions(-) diff --git a/cloudinit_test.go b/cloudinit_test.go index 9821cd0..4589f50 100644 --- a/cloudinit_test.go +++ b/cloudinit_test.go @@ -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) } diff --git a/configurator_linux_test.go b/configurator_linux_test.go index ba50bd1..9ad9585 100644 --- a/configurator_linux_test.go +++ b/configurator_linux_test.go @@ -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) } diff --git a/cpanel_test.go b/cpanel_test.go index 2385c44..75a4533 100644 --- a/cpanel_test.go +++ b/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)) }) } diff --git a/dns_backends_test.go b/dns_backends_test.go index 11236d9..40a5276 100644 --- a/dns_backends_test.go +++ b/dns_backends_test.go @@ -6,6 +6,9 @@ import ( "os" "path/filepath" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // readIfcfg parses a written ifcfg- 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) } diff --git a/go.mod b/go.mod index f422a9b..c423ba3 100644 --- a/go.mod +++ b/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 ) diff --git a/ifupdown_test.go b/ifupdown_test.go index ded374e..33b64c4 100644 --- a/ifupdown_test.go +++ b/ifupdown_test.go @@ -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) } diff --git a/netplan_test.go b/netplan_test.go index 2aeccf0..19031c7 100644 --- a/netplan_test.go +++ b/netplan_test.go @@ -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) } diff --git a/networkConfigurator_test.go b/networkConfigurator_test.go index 5531778..e42c7f8 100644 --- a/networkConfigurator_test.go +++ b/networkConfigurator_test.go @@ -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: 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 { diff --git a/networkManager_test.go b/networkManager_test.go index 14c2a67..4c185ec 100644 --- a/networkManager_test.go +++ b/networkManager_test.go @@ -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") } diff --git a/networkScripts_test.go b/networkScripts_test.go index d2e8db0..fb2b0c9 100644 --- a/networkScripts_test.go +++ b/networkScripts_test.go @@ -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) } diff --git a/networkScripts_unit_test.go b/networkScripts_unit_test.go index 68f3eaa..2bf0949 100644 --- a/networkScripts_unit_test.go +++ b/networkScripts_unit_test.go @@ -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"}, "")) }) } diff --git a/networkd_test.go b/networkd_test.go index b3beb32..efa4dbd 100644 --- a/networkd_test.go +++ b/networkd_test.go @@ -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) } diff --git a/options_test.go b/options_test.go index cdf912e..b09e41a 100644 --- a/options_test.go +++ b/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") } diff --git a/utils_unit_test.go b/utils_unit_test.go index d057196..d33207b 100644 --- a/utils_unit_test.go +++ b/utils_unit_test.go @@ -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") }) }