178 lines
3.5 KiB
Go
178 lines
3.5 KiB
Go
package ipalloc
|
|
|
|
import (
|
|
"log"
|
|
"net/netip"
|
|
"testing"
|
|
)
|
|
|
|
func TestSplitPrefix(t *testing.T) {
|
|
tests := []struct{ in, lo, hi string }{
|
|
{"0.0.0.0/0", "0.0.0.0/1", "128.0.0.0/1"},
|
|
{"0.0.0.0/29", "0.0.0.0/30", "0.0.0.4/30"},
|
|
{"0.0.0.0/31", "0.0.0.0/32", "0.0.0.1/32"},
|
|
{"0.0.0.1/0", "0.0.0.0/1", "128.0.0.0/1"},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
lo, hi := splitPrefix(netip.MustParsePrefix(test.in))
|
|
if lo != netip.MustParsePrefix(test.lo) || hi != netip.MustParsePrefix(test.hi) {
|
|
t.Fatal(test.in, lo, hi)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTreeAlloc(t *testing.T) {
|
|
tests := []struct {
|
|
bits int
|
|
best string
|
|
}{
|
|
{32, "0.0.0.0/32"},
|
|
{32, "0.0.0.1/32"},
|
|
{1, "128.0.0.0/1"},
|
|
{2, "64.0.0.0/2"},
|
|
{31, "0.0.0.2/31"},
|
|
{32, "0.0.0.4/32"},
|
|
}
|
|
root := &tree{prefix: netip.MustParsePrefix("0.0.0.0/0")}
|
|
|
|
for _, test := range tests {
|
|
best := root.Alloc(test.bits)
|
|
if best == nil {
|
|
t.Fatal(root, test.bits)
|
|
}
|
|
if best.prefix != netip.MustParsePrefix(test.best) {
|
|
t.Fatal(root, test.bits, best.prefix.String())
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestTreeDealloc(t *testing.T) {
|
|
tests := []struct {
|
|
bits int
|
|
best string
|
|
}{
|
|
{32, "0.0.0.0/32"},
|
|
{32, "0.0.0.1/32"},
|
|
{1, "128.0.0.0/1"},
|
|
{2, "64.0.0.0/2"},
|
|
{31, "0.0.0.2/31"},
|
|
{32, "0.0.0.4/32"},
|
|
}
|
|
root := &tree{prefix: netip.MustParsePrefix("0.0.0.0/0")}
|
|
|
|
for _, test := range tests {
|
|
best := root.Alloc(test.bits)
|
|
if best == nil {
|
|
t.Fatal(root, test.bits)
|
|
}
|
|
if best.prefix != netip.MustParsePrefix(test.best) {
|
|
t.Fatal(root, test.bits, best.prefix.String())
|
|
}
|
|
}
|
|
|
|
deallocs := []string{
|
|
"0.0.0.0/32",
|
|
"0.0.0.1/32",
|
|
"128.0.0.0/1",
|
|
"64.0.0.0/2",
|
|
"0.0.0.2/31",
|
|
"0.0.0.4/32",
|
|
}
|
|
|
|
for _, test := range deallocs {
|
|
if err := root.Dealloc(netip.MustParsePrefix(test)); err != nil {
|
|
t.Fatal(test, err)
|
|
}
|
|
}
|
|
|
|
if !root.Leaf() {
|
|
root.Walk(func(t *tree) bool {
|
|
log.Println(t.prefix, t.Leaf())
|
|
return true
|
|
})
|
|
t.Fatalf("root not empty: %#v", root)
|
|
}
|
|
|
|
first := root.Alloc(2).prefix
|
|
root.Alloc(2)
|
|
root.Dealloc(first)
|
|
if first != root.Alloc(2).prefix {
|
|
root.Walk(func(t *tree) bool {
|
|
log.Println(t.prefix, t.Leaf())
|
|
return true
|
|
})
|
|
t.Fatal(first)
|
|
}
|
|
}
|
|
func TestFindBest(t *testing.T) {
|
|
tests := []struct {
|
|
bits int
|
|
best string
|
|
}{
|
|
{32, "0.0.0.0/32"},
|
|
{32, "0.0.0.1/32"},
|
|
{1, "128.0.0.0/1"},
|
|
{2, "64.0.0.0/2"},
|
|
{31, "0.0.0.2/31"},
|
|
{32, "0.0.0.4/32"},
|
|
}
|
|
root := &tree{prefix: netip.MustParsePrefix("0.0.0.0/0")}
|
|
|
|
for _, test := range tests {
|
|
best := root.Alloc(test.bits)
|
|
if best == nil {
|
|
t.Fatal(root, test.bits)
|
|
}
|
|
if best.prefix != netip.MustParsePrefix(test.best) {
|
|
t.Fatal(root, test.bits, best.prefix.String())
|
|
}
|
|
}
|
|
|
|
best := [][2]string{
|
|
{"128.0.0.0/32", "128.0.0.0/1"},
|
|
{"128.0.0.1/32", "128.0.0.0/1"},
|
|
}
|
|
|
|
for _, test := range best {
|
|
best := root.FindBest(netip.MustParsePrefix(test[0]))
|
|
want := netip.MustParsePrefix(test[1])
|
|
|
|
if best.prefix != want {
|
|
t.Fatal(best, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInsert(t *testing.T) {
|
|
tests := []string{
|
|
"0.0.0.1/32",
|
|
"0.0.0.0/32",
|
|
"128.0.0.0/1",
|
|
"64.0.0.0/2",
|
|
"0.0.0.4/32",
|
|
"0.0.0.2/31",
|
|
}
|
|
root := &tree{prefix: netip.MustParsePrefix("0.0.0.0/0")}
|
|
|
|
for _, test := range tests {
|
|
p := netip.MustParsePrefix(test)
|
|
insert := root.Insert(p)
|
|
if insert == nil {
|
|
t.Fatal(root, test)
|
|
}
|
|
match := root.Find(p)
|
|
if match.prefix != p {
|
|
t.Fatal("unable to find", p, "in", root)
|
|
}
|
|
}
|
|
for _, test := range tests {
|
|
p := netip.MustParsePrefix(test)
|
|
insert := root.Insert(p)
|
|
if insert != nil {
|
|
t.Fatal(root, test)
|
|
}
|
|
}
|
|
}
|