← Back to team overview

sts-sponsors team mailing list archive

[Merge] ~troyanov/maas:refactor-maasagent-tests into maas:master

 

Anton Troyanov has proposed merging ~troyanov/maas:refactor-maasagent-tests into maas:master.

Commit message:
refactor(maasagent): tests refactoring and cleanup

Requested reviews:
  MAAS Maintainers (maas-maintainers)

For more details, see:
https://code.launchpad.net/~troyanov/maas/+git/maas/+merge/442489
-- 
Your team MAAS Maintainers is requested to review the proposed merge of ~troyanov/maas:refactor-maasagent-tests into maas:master.
diff --git a/.golangci.yaml b/.golangci.yaml
index 91aed41..9f41cd2 100644
--- a/.golangci.yaml
+++ b/.golangci.yaml
@@ -175,10 +175,15 @@ issues:
       linters:
         - revive
 
-    - path: main.go
+    - path: main\.go
       text: "package-comments:"
       linters:
         - revive
+
+    - path: _test\.go
+      text: "fieldalignment:"
+      linters:
+        - govet
   # Independently of option `exclude` we use default exclude patterns,
   # it can be disabled by this option.
   # To list all excluded by default patterns execute `golangci-lint run --help`.
diff --git a/src/maasagent/Makefile b/src/maasagent/Makefile
index 8541604..f22503f 100644
--- a/src/maasagent/Makefile
+++ b/src/maasagent/Makefile
@@ -36,22 +36,15 @@ test:
 	CGO_ENABLED=1 $(GO) test -race ./...
 
 .PHONY: generate
-generate: $(BIN_DIR)/mockgen
+generate:
 	$(GO) generate ./...
 
-.PHONY: tools
-tools: $(BIN_DIR)/mockgen
-
 .PHONY: vendor
 vendor: $(VENDOR_DIR)/modules.txt
 
 $(VENDOR_DIR)/modules.txt: go.mod
 	$(GO) mod vendor
 
-$(BIN_DIR)/mockgen: MOCKGEN_VERSION=1.6.0
-$(BIN_DIR)/mockgen: | $(BIN_DIR)
-	GOFLAGS="" GOBIN="$(realpath $(dir $@))" $(GO) install github.com/golang/mock/mockgen@v$(MOCKGEN_VERSION)
-
 .PHONY: clean
 clean:
 	rm -rf $(VENDOR_DIR) $(BIN_DIR) $(BUILD_DIR)
diff --git a/src/maasagent/go.mod b/src/maasagent/go.mod
index 0707adc..02dfb83 100644
--- a/src/maasagent/go.mod
+++ b/src/maasagent/go.mod
@@ -8,6 +8,7 @@ require (
 	github.com/rs/zerolog v1.29.1
 	github.com/stretchr/testify v1.7.0
 	golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
+	golang.org/x/tools v0.1.12
 )
 
 require (
@@ -17,6 +18,7 @@ require (
 	github.com/mattn/go-isatty v0.0.14 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/sirupsen/logrus v1.4.2 // indirect
+	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
 	golang.org/x/net v0.7.0 // indirect
 	golang.org/x/sys v0.5.0 // indirect
 	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
diff --git a/src/maasagent/go.sum b/src/maasagent/go.sum
index 9ac9620..cdacc6c 100644
--- a/src/maasagent/go.sum
+++ b/src/maasagent/go.sum
@@ -121,6 +121,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -168,6 +169,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
diff --git a/src/maasagent/internal/ethernet/arp.go b/src/maasagent/internal/ethernet/arp.go
index ef8dd2d..da3238f 100644
--- a/src/maasagent/internal/ethernet/arp.go
+++ b/src/maasagent/internal/ethernet/arp.go
@@ -14,49 +14,57 @@ import (
 	"net/netip"
 )
 
+type HardwareType uint16
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=HardwareType -trimprefix=HardwareType
+
 const (
 	// HardwareTypeReserved is a special value for hardware type
-	HardwareTypeReserved uint16 = 0 // see RFC5494
+	HardwareTypeReserved HardwareType = 0 // see RFC5494
 	// HardwareTypeEthernet is the hardware type value for Ethernet
 	// we only care about ethernet, but additional types are defined for
 	// testing and possible future use
-	HardwareTypeEthernet uint16 = 1
+	HardwareTypeEthernet HardwareType = 1
 	// HardwareTypeExpEth is the hardware type for experimental ethernet
-	HardwareTypeExpEth uint16 = 2
+	HardwareTypeExpEth HardwareType = 2
 	// HardwareTypeAX25 is the hardware type for Radio AX.25
-	HardwareTypeAX25 uint16 = 3
+	HardwareTypeAX25 HardwareType = 3
 	// HardwareTypeChaos is a chaos value for hardware type
-	HardwareTypeChaos uint16 = 4
+	HardwareTypeChaos HardwareType = 4
 	// HardwareTypeIEEE802 is for IEEE 802 networks
-	HardwareTypeIEEE802 uint16 = 5
+	HardwareTypeIEEE802 HardwareType = 5
 
 	// skipping propriatary networks
 
 	// HardwareTypeFiberChannel is the hardware type for fiber channel
-	HardwareTypeFiberChannel uint16 = 18
+	HardwareTypeFiberChannel HardwareType = 18
 	// HardwareTypeSerialLine is the hardware type for serial line
-	HardwareTypeSerialLine uint16 = 19
+	HardwareTypeSerialLine HardwareType = 19
 	// HardwareTypeHIPARP is the hardware type for HIPARP
-	HardwareTypeHIPARP uint16 = 28
+	HardwareTypeHIPARP HardwareType = 28
 	// HardwareTypeIPARPISO7163 is the hardware type for IP and ARP over ISO 7816-3
-	HardwareTypeIPARPISO7163 uint16 = 29
+	HardwareTypeIPARPISO7163 HardwareType = 29
 	// HardwareTypeARPSec is the hardware type for ARPSec
-	HardwareTypeARPSec uint16 = 30
+	HardwareTypeARPSec HardwareType = 30
 	// HardwareTypeIPSec is the hardware type for IPSec tunnel
-	HardwareTypeIPSec uint16 = 31
+	HardwareTypeIPSec HardwareType = 31
 	// HardwareTypeInfiniBand is the hardware type for InfiniBand
-	HardwareTypeInfiniBand uint16 = 32
+	HardwareTypeInfiniBand HardwareType = 32
 )
 
+type ProtocolType uint16
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=ProtocolType -trimprefix=ProtocolType
+
 const (
 	// ProtocolTypeIPv4 is the value for IPv4 ARP packets
-	ProtocolTypeIPv4 uint16 = 0x0800
+	ProtocolTypeIPv4 ProtocolType = 0x0800
 	// ProtocolTypeIPv6 is the value for IPv6 ARP packets,
 	// which shouldn't be used, this is defined for testing purposes
-	ProtocolTypeIPv6 uint16 = 0x86dd
+	ProtocolTypeIPv6 ProtocolType = 0x86dd
 	// ProtocolTypeARP is the value for ARP packets with a protocol
 	// value of ARP itself
-	ProtocolTypeARP uint16 = 0x0806
+	ProtocolTypeARP ProtocolType = 0x0806
 )
 
 const (
@@ -77,11 +85,11 @@ var (
 type ARPPacket struct {
 	SendIPAddr      netip.Addr
 	TgtIPAddr       netip.Addr
-	SendHwdAddr     net.HardwareAddr
-	TgtHwdAddr      net.HardwareAddr
-	HardwareType    uint16
+	SendHwAddr      net.HardwareAddr
+	TgtHwAddr       net.HardwareAddr
+	HardwareType    HardwareType
 	OpCode          uint16
-	ProtocolType    uint16
+	ProtocolType    ProtocolType
 	HardwareAddrLen uint8
 	ProtocolAddrLen uint8
 }
@@ -109,8 +117,8 @@ func (pkt *ARPPacket) UnmarshalBinary(buf []byte) error {
 		return fmt.Errorf("%w: packet missing initial ARP fields", err)
 	}
 
-	pkt.HardwareType = binary.BigEndian.Uint16(buf[0:2])
-	pkt.ProtocolType = binary.BigEndian.Uint16(buf[2:4])
+	pkt.HardwareType = HardwareType(binary.BigEndian.Uint16(buf[0:2]))
+	pkt.ProtocolType = ProtocolType(binary.BigEndian.Uint16(buf[2:4]))
 	pkt.HardwareAddrLen = buf[4]
 	pkt.ProtocolAddrLen = buf[5]
 	pkt.OpCode = binary.BigEndian.Uint16(buf[6:8])
@@ -124,9 +132,9 @@ func (pkt *ARPPacket) UnmarshalBinary(buf []byte) error {
 		return fmt.Errorf("%w: packet too short for sender hardware address", err)
 	}
 
-	sendHwdAddrBuf := make([]byte, hwdAddrLen)
-	copy(sendHwdAddrBuf, buf[bytesRead:bytesRead+hwdAddrLen])
-	pkt.SendHwdAddr = sendHwdAddrBuf
+	sendHwAddrBuf := make([]byte, hwdAddrLen)
+	copy(sendHwAddrBuf, buf[bytesRead:bytesRead+hwdAddrLen])
+	pkt.SendHwAddr = sendHwAddrBuf
 	bytesRead += hwdAddrLen
 
 	err = checkPacketLen(buf, bytesRead, ipAddrLen)
@@ -151,10 +159,10 @@ func (pkt *ARPPacket) UnmarshalBinary(buf []byte) error {
 		return fmt.Errorf("%w: packet too short for target hardware address", err)
 	}
 
-	tgtHwdAddrBuf := make([]byte, hwdAddrLen)
-	copy(tgtHwdAddrBuf, buf[bytesRead:bytesRead+hwdAddrLen])
+	tgtHwAddrBuf := make([]byte, hwdAddrLen)
+	copy(tgtHwAddrBuf, buf[bytesRead:bytesRead+hwdAddrLen])
 
-	pkt.TgtHwdAddr = tgtHwdAddrBuf
+	pkt.TgtHwAddr = tgtHwAddrBuf
 	bytesRead += hwdAddrLen
 
 	err = checkPacketLen(buf, bytesRead, ipAddrLen)
diff --git a/src/maasagent/internal/ethernet/arp_test.go b/src/maasagent/internal/ethernet/arp_test.go
index 8b2607c..469465e 100644
--- a/src/maasagent/internal/ethernet/arp_test.go
+++ b/src/maasagent/internal/ethernet/arp_test.go
@@ -7,82 +7,77 @@ package ethernet
 
 import (
 	"io"
+	"net/netip"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 )
 
 func TestUnmarshal(t *testing.T) {
-	table := []unmarshalCase{
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "ValidRequestPacket",
-				// generated from tcpdump
-				In: []byte{
-					0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
-					0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19,
-				},
+	t.Parallel()
+
+	testcases := map[string]struct {
+		in  []byte
+		out *ARPPacket
+		err error
+	}{
+		"valid request packet": {
+			in: []byte{
+				0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
+				0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19,
 			},
-			Out: &ARPPacket{
+			out: &ARPPacket{
 				HardwareType:    HardwareTypeEthernet,
 				ProtocolType:    ProtocolTypeIPv4,
 				HardwareAddrLen: 6,
 				ProtocolAddrLen: 4,
 				OpCode:          OpRequest,
-				SendHwdAddr:     parseMACNoError("84:39:c0:0b:22:25"),
-				SendIPAddr:      parseAddrNoError("192.168.10.26"),
-				TgtHwdAddr:      parseMACNoError("00:00:00:00:00:00"),
-				TgtIPAddr:       parseAddrNoError("192.168.10.25"),
+				SendHwAddr:      []byte{0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25},
+				SendIPAddr:      netip.MustParseAddr("192.168.10.26"),
+				TgtHwAddr:       []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x0},
+				TgtIPAddr:       netip.MustParseAddr("192.168.10.25"),
 			},
 		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "ValidReplyPacket",
-				// generated from tcpdump
-				In: []byte{
-					0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0xc0, 0xa8,
-					0x01, 0x6c, 0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
-				},
+		"valid reply packet": {
+			in: []byte{
+				0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16,
+				0xc0, 0xa8, 0x01, 0x6c, 0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
 			},
-			Out: &ARPPacket{
+			out: &ARPPacket{
 				HardwareType:    HardwareTypeEthernet,
 				ProtocolType:    ProtocolTypeIPv4,
 				HardwareAddrLen: 6,
 				ProtocolAddrLen: 4,
 				OpCode:          OpReply,
-				SendHwdAddr:     parseMACNoError("80:61:5f:08:fc:16"),
-				SendIPAddr:      parseAddrNoError("192.168.1.108"),
-				TgtHwdAddr:      parseMACNoError("24:4b:fe:e1:ea:26"),
-				TgtIPAddr:       parseAddrNoError("192.168.1.80"),
+				SendHwAddr:      []byte{0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16},
+				SendIPAddr:      netip.MustParseAddr("192.168.1.108"),
+				TgtHwAddr:       []byte{0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26},
+				TgtIPAddr:       netip.MustParseAddr("192.168.1.80"),
 			},
 		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "EmptyPacket",
-				Err:  io.ErrUnexpectedEOF,
-			},
+		"empty packet": {
+			err: io.ErrUnexpectedEOF,
 		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "TooShortPacket",
-				In: []byte{
-					0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
-					0xc0, 0xa8,
-				},
-				Err: ErrMalformedARPPacket,
+		"too stort packet": {
+			in: []byte{
+				0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
+				0xc0, 0xa8,
 			},
+			err: ErrMalformedARPPacket,
 		},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
-			res := &ARPPacket{}
+	for name, tc := range testcases {
+		tc := tc
 
-			err := res.UnmarshalBinary(tcase.In)
-			assert.ErrorIsf(tt, err, tcase.Err, "expected Unmarshal to return an error of %s", tcase.Err)
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+			res := &ARPPacket{}
 
-			if tcase.Out != nil {
-				compareARPPacket(tt, tcase.Out, res)
+			err := res.UnmarshalBinary(tc.in)
+			assert.ErrorIsf(t, err, tc.err, "expected Unmarshal to return an error of %s", tc.err)
+			if err == nil {
+				assert.Equal(t, tc.out, res)
 			}
 		})
 	}
diff --git a/src/maasagent/internal/ethernet/ethernet.go b/src/maasagent/internal/ethernet/ethernet.go
index 7128286..8356d54 100644
--- a/src/maasagent/internal/ethernet/ethernet.go
+++ b/src/maasagent/internal/ethernet/ethernet.go
@@ -16,22 +16,26 @@ const (
 	minEthernetLen = 14
 )
 
+type EthernetType uint16
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=EthernetType -trimprefix=EthernetType
+
 const (
 	// EthernetTypeLLC is a special ethernet type, if found the frame is truncated
-	EthernetTypeLLC uint16 = 0
+	EthernetTypeLLC EthernetType = 0
 	// EthernetTypeIPv4 is the ethernet type for a frame containing an IPv4 packet
-	EthernetTypeIPv4 uint16 = 0x0800
+	EthernetTypeIPv4 EthernetType = 0x0800
 	// EthernetTypeARP is the ethernet type for a frame containing an ARP packet
-	EthernetTypeARP uint16 = 0x0806
+	EthernetTypeARP EthernetType = 0x0806
 	// EthernetTypeIPv6 is the ethernet type for a frame containing an IPv6 packet
-	EthernetTypeIPv6 uint16 = 0x86dd
+	EthernetTypeIPv6 EthernetType = 0x86dd
 	// EthernetTypeVLAN is the ethernet type for a frame containing a VLAN tag,
 	// the VLAN tag bytes will indicate the actual type of packet the frame contains
-	EthernetTypeVLAN uint16 = 0x8100
+	EthernetTypeVLAN EthernetType = 0x8100
 
 	// NonStdLenEthernetTypes is a magic number to find any non-standard types
 	// and mark them as EthernetTypeLLC
-	NonStdLenEthernetTypes uint16 = 0x600
+	NonStdLenEthernetTypes EthernetType = 0x600
 )
 
 var (
@@ -51,7 +55,7 @@ type VLAN struct {
 	Priority     uint8
 	DropEligible bool
 	ID           uint16
-	EthernetType uint16
+	EthernetType EthernetType
 }
 
 // UnmarshalBinary will take the ethernet frame's payload
@@ -68,7 +72,7 @@ func (v *VLAN) UnmarshalBinary(buf []byte) error {
 	// extract the next 12 bits for an ID
 	v.ID = binary.BigEndian.Uint16(buf[:2]) & 0x0fff
 	// last 2 bytes are ethernet type
-	v.EthernetType = binary.BigEndian.Uint16(buf[2:])
+	v.EthernetType = EthernetType(binary.BigEndian.Uint16(buf[2:]))
 
 	return nil
 }
@@ -79,7 +83,7 @@ type EthernetFrame struct {
 	DstMAC       net.HardwareAddr
 	Payload      []byte
 	Len          uint16
-	EthernetType uint16
+	EthernetType EthernetType
 }
 
 // ExtractARPPacket will extract an ARP packet from the ethernet frame's
@@ -131,14 +135,14 @@ func (e *EthernetFrame) UnmarshalBinary(buf []byte) error {
 
 	e.DstMAC = buf[0:6]
 	e.SrcMAC = buf[6:12]
-	e.EthernetType = binary.BigEndian.Uint16(buf[12:14])
+	e.EthernetType = EthernetType(binary.BigEndian.Uint16(buf[12:14]))
 	e.Payload = buf[14:]
 
 	if e.EthernetType < NonStdLenEthernetTypes {
 		// see IEEE 802.3, non-standard ethernet may contain padding
 		// this calculation is used to truncate the payload to the length
 		// specified for that ethernet type
-		e.Len = e.EthernetType
+		e.Len = uint16(e.EthernetType)
 		e.EthernetType = EthernetTypeLLC
 
 		cmp := len(e.Payload) - int(e.Len)
diff --git a/src/maasagent/internal/ethernet/ethernet_test.go b/src/maasagent/internal/ethernet/ethernet_test.go
index 64e5595..a3be96e 100644
--- a/src/maasagent/internal/ethernet/ethernet_test.go
+++ b/src/maasagent/internal/ethernet/ethernet_test.go
@@ -7,62 +7,69 @@ package ethernet
 
 import (
 	"io"
+	"net/netip"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 )
 
 func TestVLANUnmarshal(t *testing.T) {
-	table := []unmarshalVLANCase{
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "ValidVLANTag",
-				In:   []byte{0x00, 0x02, 0x08, 0x06},
-			},
-			Out: &VLAN{
+	t.Parallel()
+
+	testcases := map[string]struct {
+		in  []byte
+		out *VLAN
+		err error
+	}{
+		"valid VLAN tag": {
+			in: []byte{0x00, 0x02, 0x08, 0x06},
+			out: &VLAN{
 				Priority:     0,
 				DropEligible: false,
 				ID:           2,
 				EthernetType: EthernetTypeARP,
 			},
 		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "InvalidVLANTag",
-				In:   []byte{0x00, 0x02},
-				Err:  ErrMalformedVLAN,
-			},
+		"invalid VLAN tag": {
+			in:  []byte{0x00, 0x02},
+			err: ErrMalformedVLAN,
 		},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
+	for name, tc := range testcases {
+		tc := tc
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
 			res := &VLAN{}
 
-			err := res.UnmarshalBinary(tcase.In)
-			assert.ErrorIsf(tt, err, tcase.Err, "expected UnmarshalVLAN to return an error of %s", tcase.Err)
+			err := res.UnmarshalBinary(tc.in)
+			assert.ErrorIsf(t, err, tc.err, "expected UnmarshalVLAN to return an error of %s", tc.err)
 
-			if tcase.Out != nil {
-				compareVLANs(tt, tcase.Out, res)
+			if err == nil {
+				assert.Equal(t, tc.out, res)
 			}
 		})
 	}
 }
 
 func TestEthernetUnmarshal(t *testing.T) {
-	table := []unmarshalEthernetCase{
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "ValidEthernetFrameWithoutVLAN",
-				In: []byte{
-					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0x08, 0x06, 0x00, 0x01,
-					0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0xc0, 0xa8, 0x01, 0x6c,
-					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
-				},
-			},
-			Out: &EthernetFrame{
-				SrcMAC:       parseMACNoError("80:61:5f:08:fc:16"),
-				DstMAC:       parseMACNoError("24:4b:fe:e1:ea:26"),
+	t.Parallel()
+
+	testcases := map[string]struct {
+		in  []byte
+		out *EthernetFrame
+		err error
+	}{
+		"valid ethernet frame without VLAN": {
+			in: []byte{
+				0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0x08, 0x06, 0x00, 0x01,
+				0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0xc0, 0xa8, 0x01, 0x6c,
+				0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
+			},
+			out: &EthernetFrame{
+				SrcMAC:       []byte{0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16},
+				DstMAC:       []byte{0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26},
 				EthernetType: EthernetTypeARP,
 				Payload: []byte{
 					0x00, 0x01,
@@ -71,19 +78,16 @@ func TestEthernetUnmarshal(t *testing.T) {
 				},
 			},
 		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "ValidEthernetFrameWithVLAN",
-				In: []byte{
-					0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x81, 0x00, 0x00, 0x02,
-					0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
-					0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19, 0x00, 0x00,
-					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				},
-			},
-			Out: &EthernetFrame{
-				SrcMAC:       parseMACNoError("84:39:c0:0b:22:25"),
-				DstMAC:       parseMACNoError("ff:ff:ff:ff:ff:ff"),
+		"valid ethernet frame with VLAN": {
+			in: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x81, 0x00, 0x00, 0x02,
+				0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
+				0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			},
+			out: &EthernetFrame{
+				SrcMAC:       []byte{0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25},
+				DstMAC:       []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
 				EthernetType: EthernetTypeVLAN,
 				Payload: []byte{
 					0x00, 0x02,
@@ -93,148 +97,148 @@ func TestEthernetUnmarshal(t *testing.T) {
 				},
 			},
 		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "NoEthernetFrame",
-				Err:  io.ErrUnexpectedEOF,
-			},
-		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "InvalidEthernetFrame",
-				In: []byte{
-					0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x00, 0x02,
-					0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
-					0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19,
-				},
-				Err: ErrMalformedFrame,
+		"no ethernet frame": {err: io.ErrUnexpectedEOF},
+		"invalid ethernet frame": {
+			in: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x00, 0x02,
+				0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
+				0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19,
 			},
-		},
+
+			err: ErrMalformedFrame},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
-			res := &EthernetFrame{}
+	for name, tc := range testcases {
+		tc := tc
 
-			err := res.UnmarshalBinary(tcase.In)
-			assert.ErrorIsf(tt, err, tcase.Err, "expected UnmarshalEthernet to return an error of %s", tcase.Err)
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+
+			res := &EthernetFrame{}
+			err := res.UnmarshalBinary(tc.in)
+			assert.ErrorIsf(t, err, tc.err, "expected UnmarshalEthernet to return an error of %s", tc.err)
 
-			if tcase.Out != nil {
-				compareEthernetFrames(tt, tcase.Out, res)
+			if err == nil {
+				assert.Equal(t, tc.out, res)
 			}
 		})
 	}
 }
 
 func TestEthernetFrameExtractVLAN(t *testing.T) {
-	table := []unmarshalVLANCase{
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "EthernetFrameIsVLAN",
-				In: []byte{
-					0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x81, 0x00, 0x00, 0x02,
-					0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
-					0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19, 0x00, 0x00,
-					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				},
-			},
-			Out: &VLAN{
+	t.Parallel()
+
+	testcases := map[string]struct {
+		in  []byte
+		out *VLAN
+		err error
+	}{
+		"ethernet frame is VLAN": {
+			in: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x81, 0x00, 0x00, 0x02,
+				0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
+				0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			},
+			out: &VLAN{
 				ID:           2,
 				EthernetType: EthernetTypeARP,
-			},
-		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "EthernetFrameIsNotVLAN",
-				In: []byte{
-					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0x08, 0x06, 0x00, 0x01,
-					0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0xc0, 0xa8, 0x01, 0x6c,
-					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
-				},
-				Err: ErrNotVLAN,
-			},
+			}},
+		"ethernet frame is not VLAN": {
+			in: []byte{
+				0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0x08, 0x06, 0x00, 0x01,
+				0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0xc0, 0xa8, 0x01, 0x6c,
+				0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
+			},
+			err: ErrNotVLAN,
 		},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
+	for name, tc := range testcases {
+		tc := tc
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
 			eth := &EthernetFrame{}
 
-			err := eth.UnmarshalBinary(tcase.In)
+			err := eth.UnmarshalBinary(tc.in)
 			if err != nil {
-				tt.Fatal(err)
+				t.Fatal(err)
 			}
 
 			vlan, err := eth.ExtractVLAN()
-			assert.ErrorIsf(tt, err, tcase.Err, "expected ExtractVLAN to return an error of: %s", tcase.Err)
+			assert.ErrorIsf(t, err, tc.err, "expected ExtractVLAN to return an error of: %s", tc.err)
 
-			if tcase.Out != nil {
-				compareVLANs(tt, tcase.Out, vlan)
+			if err == nil {
+				assert.Equal(t, tc.out, vlan)
 			}
 		})
 	}
 }
 
 func TestEthernetFrameExtractARP(t *testing.T) {
-	table := []unmarshalCase{
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "EthernetFrameIsVLAN",
-				In: []byte{
-					0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x81, 0x00, 0x00, 0x02,
-					0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
-					0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19, 0x00, 0x00,
-					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				},
-			},
-			Out: &ARPPacket{
+	t.Parallel()
+
+	testcases := map[string]struct {
+		in  []byte
+		out *ARPPacket
+		err error
+	}{
+		"ethernet frame is VLAN": {
+			in: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x81, 0x00, 0x00, 0x02,
+				0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25,
+				0xc0, 0xa8, 0x0a, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x19, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			},
+			out: &ARPPacket{
 				HardwareType:    HardwareTypeEthernet,
 				ProtocolType:    ProtocolTypeIPv4,
 				HardwareAddrLen: 6,
 				ProtocolAddrLen: 4,
 				OpCode:          OpRequest,
-				SendHwdAddr:     parseMACNoError("84:39:c0:0b:22:25"),
-				SendIPAddr:      parseAddrNoError("192.168.10.26"),
-				TgtHwdAddr:      parseMACNoError("00:00:00:00:00:00"),
-				TgtIPAddr:       parseAddrNoError("192.168.10.25"),
+				SendHwAddr:      []byte{0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25},
+				SendIPAddr:      netip.MustParseAddr("192.168.10.26"),
+				TgtHwAddr:       []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+				TgtIPAddr:       netip.MustParseAddr("192.168.10.25"),
 			},
 		},
-		{
-			basePacketTestCase: basePacketTestCase{
-				Name: "EthernetFrameIsNotVLAN",
-				In: []byte{
-					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0x08, 0x06, 0x00, 0x01,
-					0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0xc0, 0xa8, 0x01, 0x6c,
-					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
-				},
+		"ethernet frame is not VLAN": {
+			in: []byte{
+				0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0x08, 0x06, 0x00, 0x01,
+				0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0xc0, 0xa8, 0x01, 0x6c,
+				0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
 			},
-			Out: &ARPPacket{
+			out: &ARPPacket{
 				HardwareType:    HardwareTypeEthernet,
 				ProtocolType:    ProtocolTypeIPv4,
 				HardwareAddrLen: 6,
 				ProtocolAddrLen: 4,
 				OpCode:          OpReply,
-				SendHwdAddr:     parseMACNoError("80:61:5f:08:fc:16"),
-				SendIPAddr:      parseAddrNoError("192.168.1.108"),
-				TgtHwdAddr:      parseMACNoError("24:4b:fe:e1:ea:26"),
-				TgtIPAddr:       parseAddrNoError("192.168.1.80"),
+				SendHwAddr:      []byte{0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16},
+				SendIPAddr:      netip.MustParseAddr("192.168.1.108"),
+				TgtHwAddr:       []byte{0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26},
+				TgtIPAddr:       netip.MustParseAddr("192.168.1.80"),
 			},
 		},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
+	for name, tc := range testcases {
+		tc := tc
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
 			eth := &EthernetFrame{}
-			err := eth.UnmarshalBinary(tcase.In)
+			err := eth.UnmarshalBinary(tc.in)
 			if err != nil {
-				tt.Fatal(err)
+				t.Fatal(err)
 			}
 
 			pkt, err := eth.ExtractARPPacket()
-			assert.ErrorIsf(tt, err, tcase.Err, "expected ExtractARPPacket to return an error of: %s", tcase.Err)
+			assert.ErrorIsf(t, err, tc.err, "expected ExtractARPPacket to return an error of: %s", tc.err)
 
-			if tcase.Out != nil {
-				compareARPPacket(tt, tcase.Out, pkt)
+			if err == nil {
+				assert.Equal(t, tc.out, pkt)
 			}
 		})
 	}
diff --git a/src/maasagent/internal/ethernet/ethernettype_string.go b/src/maasagent/internal/ethernet/ethernettype_string.go
new file mode 100644
index 0000000..59f8c94
--- /dev/null
+++ b/src/maasagent/internal/ethernet/ethernettype_string.go
@@ -0,0 +1,45 @@
+// Code generated by "stringer -type=EthernetType -trimprefix=EthernetType"; DO NOT EDIT.
+
+package ethernet
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[EthernetTypeLLC-0]
+	_ = x[EthernetTypeIPv4-2048]
+	_ = x[EthernetTypeARP-2054]
+	_ = x[EthernetTypeIPv6-34525]
+	_ = x[EthernetTypeVLAN-33024]
+	_ = x[NonStdLenEthernetTypes-1536]
+}
+
+const (
+	_EthernetType_name_0 = "LLC"
+	_EthernetType_name_1 = "NonStdLenEthernetTypes"
+	_EthernetType_name_2 = "IPv4"
+	_EthernetType_name_3 = "ARP"
+	_EthernetType_name_4 = "VLAN"
+	_EthernetType_name_5 = "IPv6"
+)
+
+func (i EthernetType) String() string {
+	switch {
+	case i == 0:
+		return _EthernetType_name_0
+	case i == 1536:
+		return _EthernetType_name_1
+	case i == 2048:
+		return _EthernetType_name_2
+	case i == 2054:
+		return _EthernetType_name_3
+	case i == 33024:
+		return _EthernetType_name_4
+	case i == 34525:
+		return _EthernetType_name_5
+	default:
+		return "EthernetType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/src/maasagent/internal/ethernet/hardwaretype_string.go b/src/maasagent/internal/ethernet/hardwaretype_string.go
new file mode 100644
index 0000000..4b3fc04
--- /dev/null
+++ b/src/maasagent/internal/ethernet/hardwaretype_string.go
@@ -0,0 +1,51 @@
+// Code generated by "stringer -type=HardwareType -trimprefix=HardwareType"; DO NOT EDIT.
+
+package ethernet
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[HardwareTypeReserved-0]
+	_ = x[HardwareTypeEthernet-1]
+	_ = x[HardwareTypeExpEth-2]
+	_ = x[HardwareTypeAX25-3]
+	_ = x[HardwareTypeChaos-4]
+	_ = x[HardwareTypeIEEE802-5]
+	_ = x[HardwareTypeFiberChannel-18]
+	_ = x[HardwareTypeSerialLine-19]
+	_ = x[HardwareTypeHIPARP-28]
+	_ = x[HardwareTypeIPARPISO7163-29]
+	_ = x[HardwareTypeARPSec-30]
+	_ = x[HardwareTypeIPSec-31]
+	_ = x[HardwareTypeInfiniBand-32]
+}
+
+const (
+	_HardwareType_name_0 = "ReservedEthernetExpEthAX25ChaosIEEE802"
+	_HardwareType_name_1 = "FiberChannelSerialLine"
+	_HardwareType_name_2 = "HIPARPIPARPISO7163ARPSecIPSecInfiniBand"
+)
+
+var (
+	_HardwareType_index_0 = [...]uint8{0, 8, 16, 22, 26, 31, 38}
+	_HardwareType_index_1 = [...]uint8{0, 12, 22}
+	_HardwareType_index_2 = [...]uint8{0, 6, 18, 24, 29, 39}
+)
+
+func (i HardwareType) String() string {
+	switch {
+	case i <= 5:
+		return _HardwareType_name_0[_HardwareType_index_0[i]:_HardwareType_index_0[i+1]]
+	case 18 <= i && i <= 19:
+		i -= 18
+		return _HardwareType_name_1[_HardwareType_index_1[i]:_HardwareType_index_1[i+1]]
+	case 28 <= i && i <= 32:
+		i -= 28
+		return _HardwareType_name_2[_HardwareType_index_2[i]:_HardwareType_index_2[i+1]]
+	default:
+		return "HardwareType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/src/maasagent/internal/ethernet/helpers_test.go b/src/maasagent/internal/ethernet/helpers_test.go
deleted file mode 100644
index a1529b4..0000000
--- a/src/maasagent/internal/ethernet/helpers_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package ethernet
-
-/*
-	Copyright 2023 Canonical Ltd.  This software is licensed under the
-	GNU Affero General Public License version 3 (see the file LICENSE).
-*/
-
-import (
-	"net"
-	"net/netip"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-type basePacketTestCase struct {
-	Name string
-	Err  error
-	In   []byte
-}
-
-type unmarshalVLANCase struct {
-	Out *VLAN
-	basePacketTestCase
-}
-
-type unmarshalEthernetCase struct {
-	Out *EthernetFrame
-	basePacketTestCase
-}
-
-type unmarshalCase struct {
-	Out *ARPPacket
-	basePacketTestCase
-}
-
-func parseMACNoError(s string) net.HardwareAddr {
-	addr, _ := net.ParseMAC(s)
-	return addr
-}
-
-func parseAddrNoError(s string) netip.Addr {
-	addr, _ := netip.ParseAddr(s)
-	return addr
-}
-
-func ethernetTypeToString(t uint16) string {
-	switch t {
-	case EthernetTypeLLC:
-		return "LLC"
-	case EthernetTypeIPv4:
-		return "IPv4"
-	case EthernetTypeARP:
-		return "ARP"
-	case EthernetTypeIPv6:
-		return "IPv6"
-	case EthernetTypeVLAN:
-		return "VLAN"
-	}
-
-	return "unknown"
-}
-
-func hardwareTypeToString(t uint16) string {
-	switch t {
-	case HardwareTypeReserved:
-		return "Reserved"
-	case HardwareTypeEthernet:
-		return "Ethernet"
-	case HardwareTypeExpEth:
-		return "Experimetnal Ethernet"
-	case HardwareTypeAX25:
-		return "AX25"
-	case HardwareTypeChaos:
-		return "Chaos"
-	case HardwareTypeIEEE802:
-		return "802"
-	case HardwareTypeFiberChannel:
-		return "Fiber Channel"
-	case HardwareTypeSerialLine:
-		return "Serial Line"
-	case HardwareTypeHIPARP:
-		return "HIPARP"
-	case HardwareTypeIPARPISO7163:
-		return "IP-ARP"
-	case HardwareTypeARPSec:
-		return "ARP-Sec"
-	case HardwareTypeIPSec:
-		return "IP-Sec"
-	case HardwareTypeInfiniBand:
-		return "InfiniBand"
-	}
-
-	return "unknown"
-}
-
-func protocolTypeToString(t uint16) string {
-	switch t {
-	case ProtocolTypeIPv4:
-		return "IPv4"
-	case ProtocolTypeIPv6:
-		return "IPv6"
-	case ProtocolTypeARP:
-		return "ARP"
-	}
-
-	return "unknown"
-}
-
-func compareVLANs(t *testing.T, expected, actual *VLAN) {
-	assert.Equalf(t, expected.Priority, actual.Priority, "expected Priority to be %d", int(expected.Priority))
-	assert.Equalf(t, expected.DropEligible, actual.DropEligible, "exptected DropEligible to be %v", expected.DropEligible)
-	assert.Equalf(t, expected.ID, actual.ID, "expected ID to be %d", int(expected.ID))
-	assert.Equalf(t, expected.EthernetType, actual.EthernetType, "expected EthernetType to be %s", ethernetTypeToString(expected.EthernetType))
-}
-
-func compareEthernetFrames(t *testing.T, expected, actual *EthernetFrame) {
-	assert.Equalf(t, expected.SrcMAC, actual.SrcMAC, "expected SrcMAC to be %s", expected.SrcMAC)
-	assert.Equalf(t, expected.DstMAC, actual.DstMAC, "expected DstMAC to be %s", expected.DstMAC)
-	assert.Equalf(t, expected.EthernetType, actual.EthernetType, "expected EthernetType to be %s", ethernetTypeToString(expected.EthernetType))
-	assert.Equalf(t, expected.Len, actual.Len, "expected a length of %d", int(expected.Len))
-	assert.Equalf(t, expected.Payload, actual.Payload, "expected a payload of %x", expected.Payload)
-}
-
-func compareARPPacket(t *testing.T, expected, actual *ARPPacket) {
-	assert.Equalf(t, expected.HardwareType, actual.HardwareType, "expected a HardwareType of %s", hardwareTypeToString(expected.HardwareType))
-	assert.Equalf(t, expected.ProtocolType, actual.ProtocolType, "expected a ProtocolType of %s", protocolTypeToString(expected.ProtocolType))
-	assert.Equalf(t, expected.HardwareAddrLen, actual.HardwareAddrLen, "expected a HardwareAddrLen of %d", int(expected.HardwareAddrLen))
-	assert.Equalf(t, expected.ProtocolAddrLen, actual.ProtocolAddrLen, "expected a ProtocolAddrLen of %d", int(expected.ProtocolAddrLen))
-	assert.Equalf(t, expected.OpCode, actual.OpCode, "expected a ProtocolLen of %d", int(expected.OpCode))
-	assert.Equalf(t, expected.SendHwdAddr, actual.SendHwdAddr, "expected a SendHwdAddr of %s", expected.SendHwdAddr)
-	assert.Equalf(t, expected.SendIPAddr, actual.SendIPAddr, "expected a SendIPAddr of %s", expected.SendIPAddr)
-	assert.Equalf(t, expected.TgtHwdAddr, actual.TgtHwdAddr, "expected a TgtHwdAddr of %s", expected.TgtHwdAddr)
-	assert.Equalf(t, expected.TgtIPAddr, actual.TgtIPAddr, "expected a TgtIPAddr of %s", expected.TgtIPAddr)
-}
diff --git a/src/maasagent/internal/ethernet/protocoltype_string.go b/src/maasagent/internal/ethernet/protocoltype_string.go
new file mode 100644
index 0000000..6d3ba87
--- /dev/null
+++ b/src/maasagent/internal/ethernet/protocoltype_string.go
@@ -0,0 +1,33 @@
+// Code generated by "stringer -type=ProtocolType -trimprefix=ProtocolType"; DO NOT EDIT.
+
+package ethernet
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[ProtocolTypeIPv4-2048]
+	_ = x[ProtocolTypeIPv6-34525]
+	_ = x[ProtocolTypeARP-2054]
+}
+
+const (
+	_ProtocolType_name_0 = "IPv4"
+	_ProtocolType_name_1 = "ARP"
+	_ProtocolType_name_2 = "IPv6"
+)
+
+func (i ProtocolType) String() string {
+	switch {
+	case i == 2048:
+		return _ProtocolType_name_0
+	case i == 2054:
+		return _ProtocolType_name_1
+	case i == 34525:
+		return _ProtocolType_name_2
+	default:
+		return "ProtocolType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
diff --git a/src/maasagent/internal/netmon/event_test.go b/src/maasagent/internal/netmon/event_test.go
index 1064c6b..06c4664 100644
--- a/src/maasagent/internal/netmon/event_test.go
+++ b/src/maasagent/internal/netmon/event_test.go
@@ -7,166 +7,120 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-type eventStringCase struct {
-	Name string
-	Out  string
-	In   Event
-}
-
 func TestEventString(t *testing.T) {
-	table := []eventStringCase{
-		{
-			Name: "EventNew",
-			In:   EventNew,
-			Out:  eventNewStr,
-		},
-		{
-			Name: "EventRefreshed",
-			In:   EventRefreshed,
-			Out:  eventRefreshedStr,
-		},
-		{
-			Name: "EventMoved",
-			In:   EventMoved,
-			Out:  eventMovedStr,
-		},
-		{
-			Name: "Unknown",
-			In:   Event(0xff),
-			Out:  "UNKNOWN",
-		},
-	}
-
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
-			assert.Equalf(tt, tcase.Out, tcase.In.String(), "expected a string of %s", tcase.Out)
-		})
-	}
-}
-
-type eventValidStringCase struct {
-	Err error
-	eventStringCase
-}
+	t.Parallel()
 
-func TestEventValidString(t *testing.T) {
-	table := []eventValidStringCase{
-		{
-			eventStringCase: eventStringCase{
-				Name: "EventNew",
-				In:   EventNew,
-				Out:  eventNewStr,
-			},
-		},
-		{
-			eventStringCase: eventStringCase{
-				Name: "EventRefreshed",
-				In:   EventRefreshed,
-				Out:  eventRefreshedStr,
-			},
-		},
-		{
-			eventStringCase: eventStringCase{
-				Name: "EventMoved",
-				In:   EventMoved,
-				Out:  eventMovedStr,
-			},
-		},
-		{
-			eventStringCase: eventStringCase{
-				Name: "Unknown",
-				In:   Event(0xff),
-			},
-			Err: errInvalidEvent,
+	testcases := map[string]struct {
+		in  Event
+		out string
+		err error
+	}{
+		"event new": {
+			in:  EventNew,
+			out: eventNewStr,
+		},
+		"event refreshed": {
+			in:  EventRefreshed,
+			out: eventRefreshedStr,
+		},
+		"event moved": {
+			in:  EventMoved,
+			out: eventMovedStr,
+		},
+		"unknown": {
+			in:  Event(0xff),
+			out: "UNKNOWN",
+			err: errInvalidEvent,
 		},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
-			str, err := tcase.In.ValidString()
-			assert.Equalf(tt, tcase.Out, str, "expected a string of %s", tcase.Out)
-			assert.ErrorIs(tt, err, tcase.Err)
+	for name, tc := range testcases {
+		tc := tc
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+			assert.Equalf(t, tc.out, tc.in.String(), "expected a string of %s", tc.out)
+			_, err := tc.in.ValidString()
+			if err != nil {
+				assert.ErrorIsf(t, err, tc.err, "expected ValidString to return an error of %s", tc.err)
+			}
 		})
 	}
 }
 
-type eventMarshalJSONCase struct {
-	Err  error
-	Name string
-	Out  []byte
-	In   Event
-}
-
 func TestMarshalJSON(t *testing.T) {
-	table := []eventMarshalJSONCase{
-		{
-			Name: "EventNew",
-			In:   EventNew,
-			Out:  []byte("\"" + eventNewStr + "\""),
-		},
-		{
-			Name: "EventRefreshed",
-			In:   EventRefreshed,
-			Out:  []byte("\"" + eventRefreshedStr + "\""),
-		},
-		{
-			Name: "EventMoved",
-			In:   EventMoved,
-			Out:  []byte("\"" + eventMovedStr + "\""),
-		},
-		{
-			Name: "Uknown",
-			In:   Event(0xff),
-			Err:  errInvalidEvent,
+	t.Parallel()
+
+	testcases := map[string]struct {
+		in  Event
+		out []byte
+		err error
+	}{
+		"event new": {
+			in:  EventNew,
+			out: []byte("\"" + eventNewStr + "\""),
+		},
+		"event refreshed": {
+			in:  EventRefreshed,
+			out: []byte("\"" + eventRefreshedStr + "\""),
+		},
+		"event moved": {
+			in:  EventMoved,
+			out: []byte("\"" + eventMovedStr + "\""),
+		},
+		"unknown": {
+			in:  Event(0xff),
+			err: errInvalidEvent,
 		},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
-			b, err := tcase.In.MarshalJSON()
-			assert.Equalf(tt, b, tcase.Out, "expected event to marshal to %s", tcase.Out)
-			assert.ErrorIs(tt, err, tcase.Err)
+	for name, tc := range testcases {
+		tc := tc
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+			b, err := tc.in.MarshalJSON()
+			assert.Equalf(t, b, tc.out, "expected event to marshal to %s", tc.out)
+			assert.ErrorIs(t, err, tc.err)
 		})
 	}
 }
 
-type eventUnmarshalJSONCase struct {
-	Name string
-	Err  error
-	In   []byte
-	Out  Event
-}
-
 func TestEventUnmarshalJSON(t *testing.T) {
-	table := []eventUnmarshalJSONCase{
-		{
-			Name: "EventNew",
-			In:   []byte("\"NEW\""),
-			Out:  EventNew,
-		},
-		{
-			Name: "EventRefreshed",
-			In:   []byte("\"REFRESHED\""),
-			Out:  EventRefreshed,
-		},
-		{
-			Name: "EventMoved",
-			In:   []byte("\"MOVED\""),
-			Out:  EventMoved,
-		},
-		{
-			Name: "Empty",
-			Err:  &json.SyntaxError{},
+	t.Parallel()
+
+	testcases := map[string]struct {
+		in  []byte
+		out Event
+		err error
+	}{
+		"event new": {
+			in:  []byte("\"NEW\""),
+			out: EventNew,
+		},
+		"event refreshed": {
+			in:  []byte("\"REFRESHED\""),
+			out: EventRefreshed,
+		},
+		"event moved": {
+			in:  []byte("\"MOVED\""),
+			out: EventMoved,
+		},
+		"unknown": {
+			err: &json.SyntaxError{},
 		},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
+	for name, tc := range testcases {
+		tc := tc
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
 			var e Event
-			err := e.UnmarshalJSON(tcase.In)
-			assert.Equalf(tt, tcase.Out, e, "expected event to equal %s", tcase.Out)
-			if tcase.Err != nil {
-				assert.ErrorAs(tt, err, &tcase.Err)
+			err := e.UnmarshalJSON(tc.in)
+			assert.Equalf(t, tc.out, e, "expected event to equal %s", tc.out)
+			if tc.err != nil {
+				assert.ErrorAs(t, err, &tc.err)
 			}
 		})
 	}
diff --git a/src/maasagent/internal/netmon/service.go b/src/maasagent/internal/netmon/service.go
index a7116cb..580a5ca 100644
--- a/src/maasagent/internal/netmon/service.go
+++ b/src/maasagent/internal/netmon/service.go
@@ -95,7 +95,7 @@ func (s *Service) updateBindings(pkt *ethernet.ARPPacket, vid *uint16, timestamp
 	discoveredBindings := []Binding{
 		{
 			IP:   pkt.SendIPAddr,
-			MAC:  pkt.SendHwdAddr,
+			MAC:  pkt.SendHwAddr,
 			VID:  vid,
 			Time: timestamp,
 		},
@@ -104,7 +104,7 @@ func (s *Service) updateBindings(pkt *ethernet.ARPPacket, vid *uint16, timestamp
 	if pkt.OpCode == ethernet.OpReply {
 		discoveredBindings = append(discoveredBindings, Binding{
 			IP:   pkt.TgtIPAddr,
-			MAC:  pkt.TgtHwdAddr,
+			MAC:  pkt.TgtHwAddr,
 			VID:  vid,
 			Time: timestamp,
 		})
diff --git a/src/maasagent/internal/netmon/service_test.go b/src/maasagent/internal/netmon/service_test.go
index 94e0762..f5fbf5f 100644
--- a/src/maasagent/internal/netmon/service_test.go
+++ b/src/maasagent/internal/netmon/service_test.go
@@ -22,106 +22,95 @@ func uint16Pointer(v uint16) *uint16 {
 	return &v
 }
 
-type isValidARPPacketCase struct {
-	In   *ethernet.ARPPacket
-	Name string
-	Out  bool
-}
-
 func TestIsValidARPPacket(t *testing.T) {
-	table := []isValidARPPacketCase{
-		{
-			Name: "ValidARPPacket",
-			In: &ethernet.ARPPacket{
+	t.Parallel()
+
+	testcases := map[string]struct {
+		in  *ethernet.ARPPacket
+		out bool
+	}{
+		"valid ARP packet": {
+			in: &ethernet.ARPPacket{
 				HardwareType:    ethernet.HardwareTypeEthernet,
 				ProtocolType:    ethernet.ProtocolTypeIPv4,
 				HardwareAddrLen: 6,
 				ProtocolAddrLen: 4,
 			},
-			Out: true,
+			out: true,
 		},
-		{
-			Name: "InvalidHardwareTypeARPPacket",
-			In: &ethernet.ARPPacket{
+		"invalid hardware type ARP packet": {
+			in: &ethernet.ARPPacket{
 				HardwareType:    ethernet.HardwareTypeChaos,
 				ProtocolType:    ethernet.ProtocolTypeIPv4,
 				HardwareAddrLen: 6,
 				ProtocolAddrLen: 4,
 			},
-			Out: false,
+			out: false,
 		},
-		{
-			Name: "InvalidProtocolTypeARPPacket",
-			In: &ethernet.ARPPacket{
+		"invalid protocol type ARP packet": {
+			in: &ethernet.ARPPacket{
 				HardwareType:    ethernet.HardwareTypeEthernet,
 				ProtocolType:    ethernet.ProtocolTypeIPv6,
 				HardwareAddrLen: 6,
 				ProtocolAddrLen: 4,
 			},
-			Out: false,
+			out: false,
 		},
-		{
-			Name: "InvalidHardwareAddrLenARPPacket",
-			In: &ethernet.ARPPacket{
+		"invalid hardware address length ARP packet": {
+			in: &ethernet.ARPPacket{
 				HardwareType:    ethernet.HardwareTypeEthernet,
 				ProtocolType:    ethernet.ProtocolTypeIPv4,
 				HardwareAddrLen: 8,
 				ProtocolAddrLen: 4,
 			},
-			Out: false,
+			out: false,
 		},
-		{
-			Name: "InvalidProtocolAddrLenARPPacket",
-			In: &ethernet.ARPPacket{
+		"invalid protocol address lenth ARP packet": {
+			in: &ethernet.ARPPacket{
 				HardwareType:    ethernet.HardwareTypeEthernet,
 				ProtocolType:    ethernet.ProtocolTypeIPv4,
 				HardwareAddrLen: 6,
 				ProtocolAddrLen: 16,
 			},
-			Out: false,
+			out: false,
 		},
 	}
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
-			assert.Equalf(tt, tcase.Out, isValidARPPacket(tcase.In), "expected the result to be %v", tcase.Out)
-		})
-	}
-}
 
-type updateBindingsArgs struct {
-	Pkt  *ethernet.ARPPacket
-	VID  *uint16
-	Time time.Time
-}
+	for name, tc := range testcases {
+		tc := tc
 
-type updateBindingsCase struct {
-	Name            string
-	BindingsFixture map[string]Binding
-	In              updateBindingsArgs
-	Out             []Result
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+			assert.Equalf(t, tc.out, isValidARPPacket(tc.in),
+				"expected the result to be %v", tc.out)
+		})
+	}
 }
 
 func TestUpdateBindings(t *testing.T) {
+	t.Parallel()
+
 	timestamp := time.Now()
-	testIP1 := net.ParseIP("10.0.0.1").To4()
-	testIP2 := net.ParseIP("10.0.0.2").To4()
-	table := []updateBindingsCase{
-		{
-			Name: "NewRequestPacket",
-			In: updateBindingsArgs{
-				Pkt: &ethernet.ARPPacket{
-					HardwareType:    ethernet.HardwareTypeEthernet,
-					ProtocolType:    ethernet.ProtocolTypeIPv4,
-					HardwareAddrLen: 6,
-					ProtocolAddrLen: 4,
-					OpCode:          ethernet.OpRequest,
-					SendHwdAddr:     net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01},
-					SendIPAddr:      netip.AddrFrom4([4]byte{testIP1[0], testIP1[1], testIP1[2], testIP1[3]}),
-					TgtIPAddr:       netip.AddrFrom4([4]byte{testIP2[0], testIP2[1], testIP2[2], testIP2[3]}),
+
+	type in struct {
+		p               func(p *ethernet.ARPPacket)
+		vid             *uint16
+		time            time.Time
+		bindingsFixture map[string]Binding
+	}
+
+	testcases := map[string]struct {
+		in  in
+		out []Result
+	}{
+		"new request packet": {
+			in: in{
+				p: func(p *ethernet.ARPPacket) {
+					p.SendHwAddr = net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01}
 				},
-				Time: timestamp,
+				time: timestamp,
 			},
-			Out: []Result{
+			out: []Result{
 				{
 					IP:    "10.0.0.1",
 					MAC:   "c0:ff:ee:15:c0:01",
@@ -130,23 +119,16 @@ func TestUpdateBindings(t *testing.T) {
 				},
 			},
 		},
-		{
-			Name: "NewReplyPacket",
-			In: updateBindingsArgs{
-				Pkt: &ethernet.ARPPacket{
-					HardwareType:    ethernet.HardwareTypeEthernet,
-					ProtocolType:    ethernet.ProtocolTypeIPv4,
-					HardwareAddrLen: 6,
-					ProtocolAddrLen: 4,
-					OpCode:          ethernet.OpReply,
-					SendHwdAddr:     net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01},
-					SendIPAddr:      netip.AddrFrom4([4]byte{testIP1[0], testIP1[1], testIP1[2], testIP1[3]}),
-					TgtHwdAddr:      net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x1d},
-					TgtIPAddr:       netip.AddrFrom4([4]byte{testIP2[0], testIP2[1], testIP2[2], testIP2[3]}),
+		"new reply packet": {
+			in: in{
+				p: func(p *ethernet.ARPPacket) {
+					p.OpCode = ethernet.OpReply
+					p.SendHwAddr = net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01}
+					p.TgtHwAddr = net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x1d}
 				},
-				Time: timestamp,
+				time: timestamp,
 			},
-			Out: []Result{
+			out: []Result{
 				{
 					IP:    "10.0.0.1",
 					MAC:   "c0:ff:ee:15:c0:01",
@@ -161,23 +143,15 @@ func TestUpdateBindings(t *testing.T) {
 				},
 			},
 		},
-		{
-			Name: "NewVLANPacket",
-			In: updateBindingsArgs{
-				Pkt: &ethernet.ARPPacket{
-					HardwareType:    ethernet.HardwareTypeEthernet,
-					ProtocolType:    ethernet.ProtocolTypeIPv4,
-					HardwareAddrLen: 6,
-					ProtocolAddrLen: 4,
-					OpCode:          ethernet.OpRequest,
-					SendHwdAddr:     net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01},
-					SendIPAddr:      netip.AddrFrom4([4]byte{testIP1[0], testIP1[1], testIP1[2], testIP1[3]}),
-					TgtIPAddr:       netip.AddrFrom4([4]byte{testIP2[0], testIP2[1], testIP2[2], testIP2[3]}),
+		"new VLAN packet": {
+			in: in{
+				p: func(p *ethernet.ARPPacket) {
+					p.SendHwAddr = net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01}
 				},
-				VID:  uint16Pointer(2),
-				Time: timestamp,
+				vid:  uint16Pointer(2),
+				time: timestamp,
 			},
-			Out: []Result{
+			out: []Result{
 				{
 					IP:    "10.0.0.1",
 					MAC:   "c0:ff:ee:15:c0:01",
@@ -187,29 +161,21 @@ func TestUpdateBindings(t *testing.T) {
 				},
 			},
 		},
-		{
-			Name: "Refresh",
-			BindingsFixture: map[string]Binding{
-				"0_10.0.0.1": {
-					IP:   netip.AddrFrom4([4]byte{testIP1[0], testIP1[1], testIP1[2], testIP1[3]}),
-					MAC:  net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01},
-					Time: timestamp,
+		"refresh": {
+			in: in{
+				p: func(p *ethernet.ARPPacket) {
+					p.SendHwAddr = net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01}
 				},
-			},
-			In: updateBindingsArgs{
-				Pkt: &ethernet.ARPPacket{
-					HardwareType:    ethernet.HardwareTypeEthernet,
-					ProtocolType:    ethernet.ProtocolTypeIPv4,
-					HardwareAddrLen: 6,
-					ProtocolAddrLen: 4,
-					OpCode:          ethernet.OpRequest,
-					SendHwdAddr:     net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01},
-					SendIPAddr:      netip.AddrFrom4([4]byte{testIP1[0], testIP1[1], testIP1[2], testIP1[3]}),
-					TgtIPAddr:       netip.AddrFrom4([4]byte{testIP2[0], testIP2[1], testIP2[2], testIP2[3]}),
+				time: timestamp.Add(seenAgainThreshold + time.Second),
+				bindingsFixture: map[string]Binding{
+					"0_10.0.0.1": {
+						IP:   netip.MustParseAddr("10.0.0.1"),
+						MAC:  net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01},
+						Time: timestamp,
+					},
 				},
-				Time: timestamp.Add(seenAgainThreshold + time.Second),
 			},
-			Out: []Result{
+			out: []Result{
 				{
 					IP:    "10.0.0.1",
 					MAC:   "c0:ff:ee:15:c0:01",
@@ -218,29 +184,21 @@ func TestUpdateBindings(t *testing.T) {
 				},
 			},
 		},
-		{
-			Name: "Move",
-			BindingsFixture: map[string]Binding{
-				"0_10.0.0.1": {
-					IP:   netip.AddrFrom4([4]byte{testIP1[0], testIP1[1], testIP1[2], testIP1[3]}),
-					MAC:  net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01},
-					Time: timestamp,
+		"move": {
+			in: in{
+				p: func(p *ethernet.ARPPacket) {
+					p.SendHwAddr = net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x1d}
 				},
-			},
-			In: updateBindingsArgs{
-				Pkt: &ethernet.ARPPacket{
-					HardwareType:    ethernet.HardwareTypeEthernet,
-					ProtocolType:    ethernet.ProtocolTypeIPv4,
-					HardwareAddrLen: 6,
-					ProtocolAddrLen: 4,
-					OpCode:          ethernet.OpRequest,
-					SendHwdAddr:     net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x1d},
-					SendIPAddr:      netip.AddrFrom4([4]byte{testIP1[0], testIP1[1], testIP1[2], testIP1[3]}),
-					TgtIPAddr:       netip.AddrFrom4([4]byte{testIP2[0], testIP2[1], testIP2[2], testIP2[3]}),
+				time: timestamp,
+				bindingsFixture: map[string]Binding{
+					"0_10.0.0.1": {
+						IP:   netip.MustParseAddr("10.0.0.1"),
+						MAC:  net.HardwareAddr{0xc0, 0xff, 0xee, 0x15, 0xc0, 0x01},
+						Time: timestamp,
+					},
 				},
-				Time: timestamp,
 			},
-			Out: []Result{
+			out: []Result{
 				{
 					IP:    "10.0.0.1",
 					MAC:   "c0:ff:ee:15:c0:1d",
@@ -251,43 +209,60 @@ func TestUpdateBindings(t *testing.T) {
 		},
 	}
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
+	for name, tc := range testcases {
+		tc := tc
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+			packet := testARPPacket()
+			if tc.in.p != nil {
+				tc.in.p(packet)
+			}
 			svc := NewService("lo")
-			if tcase.BindingsFixture != nil {
-				svc.bindings = tcase.BindingsFixture
+			if tc.in.bindingsFixture != nil {
+				svc.bindings = tc.in.bindingsFixture
 			}
 
-			res := svc.updateBindings(tcase.In.Pkt, tcase.In.VID, tcase.In.Time)
-			for i, expected := range tcase.Out {
+			res := svc.updateBindings(packet, tc.in.vid, tc.in.time)
+			for i, expected := range tc.out {
 				var expectedVID int
 				if expected.VID != nil {
 					expectedVID = int(*expected.VID)
 				}
 
-				assert.Equalf(tt, expected.IP, res[i].IP, "expected Result at index of %d to have the IP %s", i, expected.IP)
-				assert.Equalf(tt, expected.MAC, res[i].MAC, "expected Result at index of %d to have the MAC %s", i, expected.MAC)
-				assert.Equalf(tt, expected.VID, res[i].VID, "expected Result at index of %d to have the VID %d", i, expectedVID)
-				assert.Equalf(tt, expected.Time, res[i].Time, "expected Result at index of %d to have the Time of %d", i, int(expected.Time))
-				assert.Equalf(tt, expected.Event, res[i].Event, "expected Result at index of %d to have the Event of %s", i, expected.Event)
+				assert.Equalf(t, expected.IP, res[i].IP, "expected Result at index of %d to have the IP %s", i, expected.IP)
+				assert.Equalf(t, expected.MAC, res[i].MAC, "expected Result at index of %d to have the MAC %s", i, expected.MAC)
+				assert.Equalf(t, expected.VID, res[i].VID, "expected Result at index of %d to have the VID %d", i, expectedVID)
+				assert.Equalf(t, expected.Time, res[i].Time, "expected Result at index of %d to have the Time of %d", i, int(expected.Time))
+				assert.Equalf(t, expected.Event, res[i].Event, "expected Result at index of %d to have the Event of %s", i, expected.Event)
 			}
 		})
 	}
 }
 
-type handlePacketCase struct {
-	Err  error
-	In   pcap.Packet
-	Name string
-	Out  []Result
+func testARPPacket() *ethernet.ARPPacket {
+	return &ethernet.ARPPacket{
+		HardwareType:    ethernet.HardwareTypeEthernet,
+		ProtocolType:    ethernet.ProtocolTypeIPv4,
+		HardwareAddrLen: 6,
+		ProtocolAddrLen: 4,
+		OpCode:          ethernet.OpRequest,
+		SendIPAddr:      netip.MustParseAddr("10.0.0.1"),
+		TgtIPAddr:       netip.MustParseAddr("10.0.0.2"),
+	}
 }
 
 func TestServiceHandlePacket(t *testing.T) {
+	t.Parallel()
+
 	timestamp := time.Now()
-	table := []handlePacketCase{
-		{
-			Name: "ValidRequestPacket",
-			In: pcap.Packet{
+	testcases := map[string]struct {
+		in  pcap.Packet
+		out []Result
+		err error
+	}{
+		"valid request packet": {
+			in: pcap.Packet{
 				// generated from tcpdump
 				B: []byte{
 					0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22, 0x25, 0x81, 0x00, 0x00, 0x02,
@@ -299,7 +274,7 @@ func TestServiceHandlePacket(t *testing.T) {
 					Timestamp: timestamp,
 				},
 			},
-			Out: []Result{
+			out: []Result{
 				{
 					IP:    "192.168.10.26",
 					MAC:   "84:39:c0:0b:22:25",
@@ -309,16 +284,15 @@ func TestServiceHandlePacket(t *testing.T) {
 				},
 			},
 		},
-		{
-			Name: "ValidReplyPacket",
-			In: pcap.Packet{
+		"valid reply packet": {
+			in: pcap.Packet{
 				B: []byte{
 					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0x08, 0x06, 0x00, 0x01,
 					0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0xc0, 0xa8, 0x01, 0x6c,
 					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
 				},
 			},
-			Out: []Result{
+			out: []Result{
 				{
 					IP:    "192.168.1.108",
 					MAC:   "80:61:5f:08:fc:16",
@@ -335,13 +309,11 @@ func TestServiceHandlePacket(t *testing.T) {
 				},
 			},
 		},
-		{
-			Name: "EmptyPacket",
-			Err:  ErrEmptyPacket,
+		"empty packet": {
+			err: ErrEmptyPacket,
 		},
-		{
-			Name: "MalformedPacket",
-			In: pcap.Packet{
+		"malformed packet": {
+			in: pcap.Packet{
 				B: []byte{
 					0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x84, 0x39, 0xc0, 0x0b, 0x22,
 					0x08, 0x06, 0x00, 0x01, 0x08, 0x06, 0x04, 0x00, 0x01, 0x84,
@@ -349,37 +321,37 @@ func TestServiceHandlePacket(t *testing.T) {
 					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 				},
 			},
-			// should return nil, nil
 		},
-		{
-			Name: "ShortPacket",
-			In: pcap.Packet{
+		"short packet": {
+			in: pcap.Packet{
 				B: []byte{
 					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0x80, 0x61, 0x5f, 0x08, 0xfc, 0x16, 0x08, 0x06, 0x00, 0x01,
 					0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x80, 0xfc, 0x16, 0xc0, 0xa8, 0x01, 0x6c,
 					0x24, 0x4b, 0xfe, 0xe1, 0xea, 0x26, 0xc0, 0xa8, 0x01, 0x50,
 				},
 			},
-			Err: ethernet.ErrMalformedARPPacket,
+			err: ethernet.ErrMalformedARPPacket,
 		},
 	}
 
-	svc := NewService("")
+	for name, tc := range testcases {
+		tc := tc
 
-	for _, tcase := range table {
-		t.Run(tcase.Name, func(tt *testing.T) {
-			res, err := svc.handlePacket(tcase.In)
-			assert.ErrorIsf(tt, err, tcase.Err, "expected handlePacket to return an error of: %s", tcase.Err)
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+			svc := NewService("")
+			res, err := svc.handlePacket(tc.in)
+			assert.ErrorIsf(t, err, tc.err, "expected handlePacket to return an error of: %s", tc.err)
 
-			if tcase.Out != nil {
-				for i, expected := range tcase.Out {
-					assert.Equalf(tt, expected.IP, res[i].IP, "expected result at index %d to have an IP address of %s", i, expected.IP)
-					assert.Equalf(tt, expected.MAC, res[i].MAC, "expected result at index %d to have a MAC address of %s", i, expected.MAC)
-					assert.Equalf(tt, expected.VID, res[i].VID, "expected result at index %d to have a VID of %v", i, expected.VID)
-					assert.Equalf(tt, expected.Time, res[i].Time, "expected result at index %d to have a Time of %s", i, expected.Time)
+			if err == nil {
+				for i, expected := range tc.out {
+					assert.Equalf(t, expected.IP, res[i].IP, "expected result at index %d to have an IP address of %s", i, expected.IP)
+					assert.Equalf(t, expected.MAC, res[i].MAC, "expected result at index %d to have a MAC address of %s", i, expected.MAC)
+					assert.Equalf(t, expected.VID, res[i].VID, "expected result at index %d to have a VID of %v", i, expected.VID)
+					assert.Equalf(t, expected.Time, res[i].Time, "expected result at index %d to have a Time of %s", i, expected.Time)
 				}
 			} else {
-				assert.Nil(tt, res)
+				assert.Nil(t, res)
 			}
 		})
 	}
diff --git a/src/maasagent/tools.go b/src/maasagent/tools.go
new file mode 100644
index 0000000..10ac085
--- /dev/null
+++ b/src/maasagent/tools.go
@@ -0,0 +1,7 @@
+//go:build tools
+
+package main
+
+import (
+	_ "golang.org/x/tools/cmd/stringer"
+)

Follow ups