From c124d3c61479bc44e2b7ab9ecbb044218b0ecdbf Mon Sep 17 00:00:00 2001 From: Johannes Kimmel Date: Mon, 13 Nov 2023 22:31:08 +0100 Subject: [PATCH] add more test coverage --- ipalloc/ipalloc.go | 6 +-- ipalloc/ipalloc_test.go | 82 +++++++++++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/ipalloc/ipalloc.go b/ipalloc/ipalloc.go index ae4b5a4..69860d1 100644 --- a/ipalloc/ipalloc.go +++ b/ipalloc/ipalloc.go @@ -440,14 +440,14 @@ func placeIntoRect(p, into netip.Prefix, r Rect) Rect { subr.W = r.W } return placeIntoRect(p, hi, subr) - } else { - panic("unreachable") } + + panic("unreachable") } func prepareSplit(p netip.Prefix) netip.Prefix { if p.IsSingleIP() { - log.Fatal("can't split single ip prefix", p) + panic(fmt.Sprint("can't split single ip prefix ", p)) } return p.Masked() } diff --git a/ipalloc/ipalloc_test.go b/ipalloc/ipalloc_test.go index 0508923..bf6a4b5 100644 --- a/ipalloc/ipalloc_test.go +++ b/ipalloc/ipalloc_test.go @@ -21,6 +21,18 @@ func TestSplitPrefix(t *testing.T) { t.Fatal(test.in, lo, hi) } } + + singles := []string{"0.0.0.0/32", "::/128"} + for _, test := range singles { + func() { + defer func() { + _ = recover() + }() + _, _ = splitPrefix(netip.MustParsePrefix(test)) + t.Fatalf("Expected panic when splitting %q", test) + }() + } + } func TestTreeAllocSmall(t *testing.T) { @@ -124,7 +136,9 @@ func TestTreeDealloc(t *testing.T) { first := root.Alloc(2).prefix root.Alloc(2) - root.Dealloc(first) + if err := root.Dealloc(first); err != nil { + t.Fatal("failed to remove", first) + } if first != root.Alloc(2).prefix { root.Walk(func(t *tree) bool { log.Println(t.prefix, t.Leaf()) @@ -205,11 +219,15 @@ func TestInsert(t *testing.T) { } func expectAlloc(t *testing.T, root *tree, bits int, expect string) { - if alloc := root.Alloc(bits); alloc.prefix != netip.MustParsePrefix(expect) { + alloc := root.Alloc(bits) + if alloc == nil { + t.Log("graph:\n", root.Dot()) + t.Fatal() + } + if alloc.prefix != netip.MustParsePrefix(expect) { t.Logf("allocating %d bits failed: got %s, want %s", bits, alloc.prefix, expect) t.Log("graph:\n", root.Dot()) t.Fatal() - } } func TestAllocDealloc(t *testing.T) { @@ -223,24 +241,64 @@ func TestAllocDealloc(t *testing.T) { expectAlloc(t, root, 32, "0.0.0.0/32") expectAlloc(t, root, 32, "0.0.0.1/32") } - -func benchRunN(b *testing.B, bits int) { - root := &tree{ - prefix: netip.PrefixFrom(netip.MustParseAddr("0.0.0.0"), bits), +func TestAllocDealloc2(t *testing.T) { + root := &tree{prefix: netip.MustParsePrefix("0.0.0.0/29")} + expectAlloc(t, root, 31, "0.0.0.0/31") + expectAlloc(t, root, 31, "0.0.0.2/31") + expectAlloc(t, root, 32, "0.0.0.4/32") + if err := root.Dealloc(netip.MustParsePrefix("0.0.0.0/31")); err != nil { + t.Fatalf("%s", err) } + expectAlloc(t, root, 32, "0.0.0.5/32") + expectAlloc(t, root, 32, "0.0.0.0/32") + expectAlloc(t, root, 32, "0.0.0.1/32") +} +func TestAllocFull(t *testing.T) { + root := &tree{prefix: netip.MustParsePrefix("0.0.0.0/31")} + expectAlloc(t, root, 32, "0.0.0.0/32") + expectAlloc(t, root, 32, "0.0.0.1/32") + if alloc := root.Alloc(32); alloc != nil { + t.Fatalf("expected nil for allocation in full tree, got %v", alloc) + } +} +func TestFindNotAvailable(t *testing.T) { + root := &tree{prefix: netip.MustParsePrefix("0.0.0.0/31")} + if match := root.Find(netip.MustParsePrefix("0.0.0.0/32")); match != nil { + t.Fatalf("expected not to find %q in empty tree", match.prefix) + } + if match := root.Find(netip.MustParsePrefix("128.0.0.0/32")); match != nil { + t.Fatalf("expected not to find %q in empty tree", match.prefix) + } + if match := root.Find(netip.MustParsePrefix("::/32")); match != nil { + t.Fatalf("expected not to find %q in empty tree", match.prefix) + } +} + +func benchRunN(b *testing.B, base netip.Addr, bits int) { + root := &tree{ + prefix: netip.PrefixFrom(base, bits), + } + bitlen := base.BitLen() for i := 0; i < b.N; i++ { - if alloc := root.Alloc(32); alloc == nil { + if alloc := root.Alloc(bitlen); alloc == nil { root = &tree{ - prefix: netip.PrefixFrom(netip.MustParseAddr("0.0.0.0"), bits), + prefix: netip.PrefixFrom(base, bits), } } } } -func BenchmarkFill(b *testing.B) { +func BenchmarkFillv4(b *testing.B) { for bits := 24; bits >= 0; bits -= 8 { - b.Run(fmt.Sprintf("BenchmarkFill-%2d", bits), func(b *testing.B) { - benchRunN(b, bits) + b.Run(fmt.Sprintf("%s-%02d", b.Name(), bits), func(b *testing.B) { + benchRunN(b, netip.MustParseAddr("0.0.0.0"), bits) + }) + } +} +func BenchmarkFillv6(b *testing.B) { + for bits := 96; bits >= 0; bits -= 16 { + b.Run(fmt.Sprintf("%s-%02d", b.Name(), bits), func(b *testing.B) { + benchRunN(b, netip.MustParseAddr("::"), bits) }) } }