diff --git a/table_test.go b/table_test.go index b0cf63d..d7fb5b6 100644 --- a/table_test.go +++ b/table_test.go @@ -119,6 +119,286 @@ func TestRegression(t *testing.T) { }) } +func TestInsert(t *testing.T) { + tbl := &Table[int]{} + + // Create a new leaf strideTable, with compressed path + tbl.Insert(mpp("192.168.0.1/32"), 1) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", -1}, + {"192.168.0.3", -1}, + {"192.168.0.255", -1}, + {"192.168.1.1", -1}, + {"192.170.1.1", -1}, + {"192.180.0.1", -1}, + {"192.180.3.5", -1}, + {"10.0.0.5", -1}, + {"10.0.0.15", -1}, + }) + + // Insert into previous leaf, no tree changes + tbl.Insert(mpp("192.168.0.2/32"), 2) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", 2}, + {"192.168.0.3", -1}, + {"192.168.0.255", -1}, + {"192.168.1.1", -1}, + {"192.170.1.1", -1}, + {"192.180.0.1", -1}, + {"192.180.3.5", -1}, + {"10.0.0.5", -1}, + {"10.0.0.15", -1}, + }) + + // Insert into previous leaf, unaligned prefix covering the /32s + tbl.Insert(mpp("192.168.0.0/26"), 7) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", 2}, + {"192.168.0.3", 7}, + {"192.168.0.255", -1}, + {"192.168.1.1", -1}, + {"192.170.1.1", -1}, + {"192.180.0.1", -1}, + {"192.180.3.5", -1}, + {"10.0.0.5", -1}, + {"10.0.0.15", -1}, + }) + + // Create a different leaf elsewhere + tbl.Insert(mpp("10.0.0.0/27"), 3) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", 2}, + {"192.168.0.3", 7}, + {"192.168.0.255", -1}, + {"192.168.1.1", -1}, + {"192.170.1.1", -1}, + {"192.180.0.1", -1}, + {"192.180.3.5", -1}, + {"10.0.0.5", 3}, + {"10.0.0.15", 3}, + }) + + // Insert that creates a new intermediate table and a new child + tbl.Insert(mpp("192.168.1.1/32"), 4) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", 2}, + {"192.168.0.3", 7}, + {"192.168.0.255", -1}, + {"192.168.1.1", 4}, + {"192.170.1.1", -1}, + {"192.180.0.1", -1}, + {"192.180.3.5", -1}, + {"10.0.0.5", 3}, + {"10.0.0.15", 3}, + }) + + // Insert that creates a new intermediate table but no new child + tbl.Insert(mpp("192.170.0.0/16"), 5) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", 2}, + {"192.168.0.3", 7}, + {"192.168.0.255", -1}, + {"192.168.1.1", 4}, + {"192.170.1.1", 5}, + {"192.180.0.1", -1}, + {"192.180.3.5", -1}, + {"10.0.0.5", 3}, + {"10.0.0.15", 3}, + }) + + // New leaf in a different subtree, so the next insert can test a + // variant of decompression. + tbl.Insert(mpp("192.180.0.1/32"), 8) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", 2}, + {"192.168.0.3", 7}, + {"192.168.0.255", -1}, + {"192.168.1.1", 4}, + {"192.170.1.1", 5}, + {"192.180.0.1", 8}, + {"192.180.3.5", -1}, + {"10.0.0.5", 3}, + {"10.0.0.15", 3}, + }) + + // Insert that creates a new intermediate table but no new child, + // with an unaligned intermediate + tbl.Insert(mpp("192.180.0.0/21"), 9) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", 2}, + {"192.168.0.3", 7}, + {"192.168.0.255", -1}, + {"192.168.1.1", 4}, + {"192.170.1.1", 5}, + {"192.180.0.1", 8}, + {"192.180.3.5", 9}, + {"10.0.0.5", 3}, + {"10.0.0.15", 3}, + }) + + // Insert a default route, those have their own codepath. + tbl.Insert(mpp("0.0.0.0/0"), 6) + checkRoutes(t, tbl, []tableTest{ + {"192.168.0.1", 1}, + {"192.168.0.2", 2}, + {"192.168.0.3", 7}, + {"192.168.0.255", 6}, + {"192.168.1.1", 4}, + {"192.170.1.1", 5}, + {"192.180.0.1", 8}, + {"192.180.3.5", 9}, + {"10.0.0.5", 3}, + {"10.0.0.15", 3}, + }) + + // Now all of the above again, but for IPv6. + + // Create a new leaf strideTable, with compressed path + tbl.Insert(mpp("ff:aaaa::1/128"), 1) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", -1}, + {"ff:aaaa::3", -1}, + {"ff:aaaa::255", -1}, + {"ff:aaaa:aaaa::1", -1}, + {"ff:aaaa:aaaa:bbbb::1", -1}, + {"ff:cccc::1", -1}, + {"ff:cccc::ff", -1}, + {"ffff:bbbb::5", -1}, + {"ffff:bbbb::15", -1}, + }) + + // Insert into previous leaf, no tree changes + tbl.Insert(mpp("ff:aaaa::2/128"), 2) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", 2}, + {"ff:aaaa::3", -1}, + {"ff:aaaa::255", -1}, + {"ff:aaaa:aaaa::1", -1}, + {"ff:aaaa:aaaa:bbbb::1", -1}, + {"ff:cccc::1", -1}, + {"ff:cccc::ff", -1}, + {"ffff:bbbb::5", -1}, + {"ffff:bbbb::15", -1}, + }) + + // Insert into previous leaf, unaligned prefix covering the /128s + tbl.Insert(mpp("ff:aaaa::/125"), 7) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", 2}, + {"ff:aaaa::3", 7}, + {"ff:aaaa::255", -1}, + {"ff:aaaa:aaaa::1", -1}, + {"ff:aaaa:aaaa:bbbb::1", -1}, + {"ff:cccc::1", -1}, + {"ff:cccc::ff", -1}, + {"ffff:bbbb::5", -1}, + {"ffff:bbbb::15", -1}, + }) + + // Create a different leaf elsewhere + tbl.Insert(mpp("ffff:bbbb::/120"), 3) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", 2}, + {"ff:aaaa::3", 7}, + {"ff:aaaa::255", -1}, + {"ff:aaaa:aaaa::1", -1}, + {"ff:aaaa:aaaa:bbbb::1", -1}, + {"ff:cccc::1", -1}, + {"ff:cccc::ff", -1}, + {"ffff:bbbb::5", 3}, + {"ffff:bbbb::15", 3}, + }) + + // Insert that creates a new intermediate table and a new child + tbl.Insert(mpp("ff:aaaa:aaaa::1/128"), 4) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", 2}, + {"ff:aaaa::3", 7}, + {"ff:aaaa::255", -1}, + {"ff:aaaa:aaaa::1", 4}, + {"ff:aaaa:aaaa:bbbb::1", -1}, + {"ff:cccc::1", -1}, + {"ff:cccc::ff", -1}, + {"ffff:bbbb::5", 3}, + {"ffff:bbbb::15", 3}, + }) + + // Insert that creates a new intermediate table but no new child + tbl.Insert(mpp("ff:aaaa:aaaa:bb00::/56"), 5) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", 2}, + {"ff:aaaa::3", 7}, + {"ff:aaaa::255", -1}, + {"ff:aaaa:aaaa::1", 4}, + {"ff:aaaa:aaaa:bbbb::1", 5}, + {"ff:cccc::1", -1}, + {"ff:cccc::ff", -1}, + {"ffff:bbbb::5", 3}, + {"ffff:bbbb::15", 3}, + }) + + // New leaf in a different subtree, so the next insert can test a + // variant of decompression. + tbl.Insert(mpp("ff:cccc::1/128"), 8) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", 2}, + {"ff:aaaa::3", 7}, + {"ff:aaaa::255", -1}, + {"ff:aaaa:aaaa::1", 4}, + {"ff:aaaa:aaaa:bbbb::1", 5}, + {"ff:cccc::1", 8}, + {"ff:cccc::ff", -1}, + {"ffff:bbbb::5", 3}, + {"ffff:bbbb::15", 3}, + }) + + // Insert that creates a new intermediate table but no new child, + // with an unaligned intermediate + tbl.Insert(mpp("ff:cccc::/37"), 9) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", 2}, + {"ff:aaaa::3", 7}, + {"ff:aaaa::255", -1}, + {"ff:aaaa:aaaa::1", 4}, + {"ff:aaaa:aaaa:bbbb::1", 5}, + {"ff:cccc::1", 8}, + {"ff:cccc::ff", 9}, + {"ffff:bbbb::5", 3}, + {"ffff:bbbb::15", 3}, + }) + + // Insert a default route, those have their own codepath. + tbl.Insert(mpp("::/0"), 6) + checkRoutes(t, tbl, []tableTest{ + {"ff:aaaa::1", 1}, + {"ff:aaaa::2", 2}, + {"ff:aaaa::3", 7}, + {"ff:aaaa::255", 6}, + {"ff:aaaa:aaaa::1", 4}, + {"ff:aaaa:aaaa:bbbb::1", 5}, + {"ff:cccc::1", 8}, + {"ff:cccc::ff", 9}, + {"ffff:bbbb::5", 3}, + {"ffff:bbbb::15", 3}, + }) +} + func TestDelete(t *testing.T) { t.Parallel() @@ -1391,7 +1671,7 @@ func checkRoutes(t *testing.T, tbl *Table[int], tt []tableTest) { v, ok := tbl.Lookup(mpa(tc.addr)) if !ok && tc.want != -1 { - t.Errorf("Lookup %q got (%v, %v), want (_, false)", tc.addr, v, ok) + t.Errorf("Lookup %q got (%v, %v), want (%v, false)", tc.addr, v, ok, tc.want) } if ok && v != tc.want { t.Errorf("Lookup %q got (%v, %v), want (%v, true)", tc.addr, v, ok, tc.want)