Files
akvorado/common/helpers/ipv6_test.go
Vincent Bernat 23518c3e2e
Some checks failed
CI / 🤖 Check dependabot status (push) Has been cancelled
CI / 🐧 Test on Linux (${{ github.ref_type == 'tag' }}, misc) (push) Has been cancelled
CI / 🐧 Test on Linux (coverage) (push) Has been cancelled
CI / 🐧 Test on Linux (regular) (push) Has been cancelled
CI / ❄️ Build on Nix (push) Has been cancelled
CI / 🍏 Build and test on macOS (push) Has been cancelled
CI / 🧪 End-to-end testing (push) Has been cancelled
CI / 🔍 Upload code coverage (push) Has been cancelled
CI / 🔬 Test only Go (push) Has been cancelled
CI / 🔬 Test only JS (${{ needs.dependabot.outputs.package-ecosystem }}, 20) (push) Has been cancelled
CI / 🔬 Test only JS (${{ needs.dependabot.outputs.package-ecosystem }}, 22) (push) Has been cancelled
CI / 🔬 Test only JS (${{ needs.dependabot.outputs.package-ecosystem }}, 24) (push) Has been cancelled
CI / ⚖️ Check licenses (push) Has been cancelled
CI / 🐋 Build Docker images (push) Has been cancelled
CI / 🐋 Tag Docker images (push) Has been cancelled
CI / 🚀 Publish release (push) Has been cancelled
Update Nix dependency hashes / Update dependency hashes (push) Has been cancelled
common/helpers: add a NetIPTo6() function
This should be netip.To6() but it does not exist and it was rejected.
There is a benchmark showing the improvment of such optimisation:

BenchmarkNetIPTo6/safe_v4-12            170152954                7.054 ns/op
BenchmarkNetIPTo6/unsafe_v4-12          764772190                1.553 ns/op

See https://github.com/golang/go/issues/54365.
2025-11-03 21:36:33 +01:00

117 lines
2.9 KiB
Go

// SPDX-FileCopyrightText: 2025 Free Mobile
// SPDX-License-Identifier: AGPL-3.0-only
package helpers_test
import (
"fmt"
"net/netip"
"reflect"
"testing"
"unsafe"
"akvorado/common/helpers"
)
func TestNetIPTo6(t *testing.T) {
cases := []struct {
input netip.Addr
output netip.Addr
}{
{netip.Addr{}, netip.Addr{}},
{netip.MustParseAddr("192.168.1.1"), netip.MustParseAddr("::ffff:192.168.1.1")},
{netip.MustParseAddr("2a01:db8::1"), netip.MustParseAddr("2a01:db8::1")},
}
for _, tc := range cases {
got := helpers.NetIPTo6(tc.input)
if diff := helpers.Diff(got, tc.output); diff != "" {
t.Errorf("NetIPTo6(%s) (-got, +want):\n%s", tc.input, diff)
}
}
}
func TestNetIPAddrStructure(t *testing.T) {
var addr netip.Addr
addrType := reflect.TypeOf(addr)
// Test total size: 24 bytes (16 for uint128 + 8 for unique.Handle)
if unsafe.Sizeof(addr) != 24 {
t.Errorf("netip.Addr size = %d, want 24", unsafe.Sizeof(addr))
}
// Test number of fields
if addrType.NumField() != 2 {
t.Errorf("netip.Addr has %d fields, want 2", addrType.NumField())
}
// Test field 0: addr (uint128, 16 bytes)
field0 := addrType.Field(0)
if field0.Name != "addr" {
t.Errorf("field 0 name = %q, want %q", field0.Name, "addr")
}
if field0.Type.String() != "netip.uint128" {
t.Errorf("field 0 type = %q, want %q", field0.Type.String(), "netip.uint128")
}
if field0.Offset != 0 {
t.Errorf("field 0 offset = %d, want 0", field0.Offset)
}
if field0.Type.Size() != 16 {
t.Errorf("field 0 (addr) size = %d, want 16", field0.Type.Size())
}
// Test field 1: z (unique.Handle, 8 bytes)
field1 := addrType.Field(1)
if field1.Name != "z" {
t.Errorf("field 1 name = %q, want %q", field1.Name, "z")
}
if field1.Type.String() != "unique.Handle[net/netip.addrDetail]" {
t.Errorf("field 0 type = %q, want %q", field1.Type.String(), "unique.Handle[net/netip.addrDetail]")
}
if field1.Offset != 16 {
t.Errorf("field 1 offset = %d, want 16", field1.Offset)
}
if field1.Type.Size() != 8 {
t.Errorf("field 1 (z) size = %d, want 8", field1.Type.Size())
}
t.Logf("netip.Addr structure verified: [addr %d bytes @ 0] [z %d bytes @ 16]",
field0.Type.Size(), field1.Type.Size())
}
func netIPTo6Safe(ip netip.Addr) netip.Addr {
if ip.Is4() {
return netip.AddrFrom16(ip.As16())
}
return ip
}
func netIPTo6SafeNocheck(ip netip.Addr) netip.Addr {
return netip.AddrFrom16(ip.As16())
}
func BenchmarkNetIPTo6(b *testing.B) {
ipv4 := netip.MustParseAddr("192.168.1.1")
ipv6 := netip.MustParseAddr("2a01:db8::1")
for _, ip := range []netip.Addr{ipv4, ipv6} {
version := "v4"
if ip.Is6() {
version = "v6"
}
b.Run(fmt.Sprintf("safe %s", version), func(b *testing.B) {
for b.Loop() {
_ = netIPTo6Safe(ip)
}
})
b.Run(fmt.Sprintf("safe nocheck %s", version), func(b *testing.B) {
for b.Loop() {
_ = netIPTo6SafeNocheck(ip)
}
})
b.Run(fmt.Sprintf("unsafe %s", version), func(b *testing.B) {
for b.Loop() {
_ = helpers.NetIPTo6(ip)
}
})
}
}