616 lines
20 KiB
Go
616 lines
20 KiB
Go
|
// Copyright (C) 2019 Storj Labs, Inc.
|
||
|
// See LICENSE for copying information.
|
||
|
|
||
|
package kademlia
|
||
|
|
||
|
import (
|
||
|
"testing"
|
||
|
|
||
|
"github.com/stretchr/testify/require"
|
||
|
"storj.io/storj/internal/testcontext"
|
||
|
"storj.io/storj/pkg/dht"
|
||
|
"storj.io/storj/pkg/kademlia/testrouting"
|
||
|
"storj.io/storj/pkg/pb"
|
||
|
"storj.io/storj/pkg/storj"
|
||
|
)
|
||
|
|
||
|
type routingCtor func(storj.NodeID, int, int, int) dht.RoutingTable
|
||
|
|
||
|
func newRouting(self storj.NodeID, bucketSize, cacheSize, allowedFailures int) dht.RoutingTable {
|
||
|
if allowedFailures != 0 {
|
||
|
panic("failure counting currently unsupported")
|
||
|
}
|
||
|
return createRoutingTableWith(self, routingTableOpts{
|
||
|
bucketSize: bucketSize,
|
||
|
cacheSize: cacheSize,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func newTestRouting(self storj.NodeID, bucketSize, cacheSize, allowedFailures int) dht.RoutingTable {
|
||
|
return testrouting.New(self, bucketSize, cacheSize, allowedFailures)
|
||
|
}
|
||
|
|
||
|
func TestTableInit_Routing(t *testing.T) { testTableInit(t, newRouting) }
|
||
|
func TestTableInit_TestRouting(t *testing.T) { testTableInit(t, newTestRouting) }
|
||
|
func testTableInit(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
bucketSize := 5
|
||
|
cacheSize := 3
|
||
|
table := routingCtor(PadID("55", "5"), bucketSize, cacheSize, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
require.Equal(t, bucketSize, table.K())
|
||
|
require.Equal(t, cacheSize, table.CacheSize())
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("21", "0"), 3)
|
||
|
require.NoError(t, err)
|
||
|
require.Equal(t, 0, len(nodes))
|
||
|
}
|
||
|
|
||
|
func TestTableBasic_Routing(t *testing.T) { testTableBasic(t, newRouting) }
|
||
|
func TestTableBasic_TestRouting(t *testing.T) { testTableBasic(t, newTestRouting) }
|
||
|
func testTableBasic(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("5555", "5"), 5, 3, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
err := table.ConnectionSuccess(Node(PadID("5556", "5"), "address:1"))
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("21", "0"), 3)
|
||
|
require.NoError(t, err)
|
||
|
require.Equal(t, 1, len(nodes))
|
||
|
require.Equal(t, PadID("5556", "5"), nodes[0].Id)
|
||
|
require.Equal(t, "address:1", nodes[0].Address.Address)
|
||
|
}
|
||
|
|
||
|
func TestNoSelf_Routing(t *testing.T) { testNoSelf(t, newRouting) }
|
||
|
func TestNoSelf_TestRouting(t *testing.T) { testNoSelf(t, newTestRouting) }
|
||
|
func testNoSelf(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("55", "5"), 5, 3, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
err := table.ConnectionSuccess(Node(PadID("55", "5"), "address:2"))
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("21", "0"), 3)
|
||
|
require.NoError(t, err)
|
||
|
require.Equal(t, 0, len(nodes))
|
||
|
}
|
||
|
|
||
|
func TestSplits_Routing(t *testing.T) { testSplits(t, newRouting) }
|
||
|
func TestSplits_TestRouting(t *testing.T) { testSplits(t, newTestRouting) }
|
||
|
func testSplits(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("55", "5"), 5, 2, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
for _, prefix2 := range "18" {
|
||
|
for _, prefix1 := range "a69c23f1d7eb5408" {
|
||
|
require.NoError(t, table.ConnectionSuccess(
|
||
|
NodeFromPrefix(string([]rune{prefix1, prefix2}), "0")))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// we just put 32 nodes into the table. the bucket with a differing first
|
||
|
// bit should be full with 5 nodes. the bucket with the same first bit and
|
||
|
// differing second bit should be full with 5 nodes. the bucket with the
|
||
|
// same first two bits and differing third bit should not be full and have
|
||
|
// 4 nodes (60..., 68..., 70..., 78...). the bucket with the same first
|
||
|
// three bits should also not be full and have 4 nodes
|
||
|
// (40..., 48..., 50..., 58...). So we should be able to get no more than
|
||
|
// 18 nodes back
|
||
|
nodes, err := table.FindNear(PadID("55", "5"), 19)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
// bucket 010 (same first three bits)
|
||
|
NodeFromPrefix("51", "0"), NodeFromPrefix("58", "0"),
|
||
|
NodeFromPrefix("41", "0"), NodeFromPrefix("48", "0"),
|
||
|
|
||
|
// bucket 011 (same first two bits)
|
||
|
NodeFromPrefix("71", "0"), NodeFromPrefix("78", "0"),
|
||
|
NodeFromPrefix("61", "0"), NodeFromPrefix("68", "0"),
|
||
|
|
||
|
// bucket 00 (same first bit)
|
||
|
NodeFromPrefix("11", "0"),
|
||
|
NodeFromPrefix("01", "0"),
|
||
|
NodeFromPrefix("31", "0"),
|
||
|
// 20 is added first of this group, so it's the only one where there's
|
||
|
// room for the 28, before this bucket is full
|
||
|
NodeFromPrefix("21", "0"), NodeFromPrefix("28", "0"),
|
||
|
|
||
|
// bucket 1 (differing first bit)
|
||
|
NodeFromPrefix("d1", "0"),
|
||
|
NodeFromPrefix("c1", "0"),
|
||
|
NodeFromPrefix("f1", "0"),
|
||
|
NodeFromPrefix("91", "0"),
|
||
|
NodeFromPrefix("a1", "0"),
|
||
|
// e and f were added last so that bucket should have been full by then
|
||
|
}, nodes)
|
||
|
|
||
|
// let's cause some failures and make sure the replacement cache fills in
|
||
|
// the gaps
|
||
|
|
||
|
// bucket 010 shouldn't have anything in its replacement cache
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("41", "0")))
|
||
|
// bucket 011 shouldn't have anything in its replacement cache
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("68", "0")))
|
||
|
|
||
|
// bucket 00 should have two things in its replacement cache, 18... is one of them
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("18", "0")))
|
||
|
|
||
|
// now just one thing in its replacement cache
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("31", "0")))
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("28", "0")))
|
||
|
|
||
|
// bucket 1 should have two things in its replacement cache
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("a1", "0")))
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("d1", "0")))
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("91", "0")))
|
||
|
|
||
|
nodes, err = table.FindNear(PadID("55", "5"), 19)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
// bucket 010
|
||
|
NodeFromPrefix("51", "0"), NodeFromPrefix("58", "0"),
|
||
|
NodeFromPrefix("48", "0"),
|
||
|
|
||
|
// bucket 011
|
||
|
NodeFromPrefix("71", "0"), NodeFromPrefix("78", "0"),
|
||
|
NodeFromPrefix("61", "0"),
|
||
|
|
||
|
// bucket 00
|
||
|
NodeFromPrefix("11", "0"),
|
||
|
NodeFromPrefix("01", "0"),
|
||
|
NodeFromPrefix("08", "0"), // replacement cache
|
||
|
NodeFromPrefix("21", "0"),
|
||
|
|
||
|
// bucket 1
|
||
|
NodeFromPrefix("c1", "0"),
|
||
|
NodeFromPrefix("f1", "0"),
|
||
|
NodeFromPrefix("88", "0"), // replacement cache
|
||
|
NodeFromPrefix("b8", "0"), // replacement cache
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestUnbalanced_Routing(t *testing.T) { testUnbalanced(t, newRouting) }
|
||
|
func TestUnbalanced_TestRouting(t *testing.T) { testUnbalanced(t, newTestRouting) }
|
||
|
func testUnbalanced(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("ff", "f"), 5, 2, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
for _, prefix1 := range "0123456789abcdef" {
|
||
|
for _, prefix2 := range "18" {
|
||
|
require.NoError(t, table.ConnectionSuccess(
|
||
|
NodeFromPrefix(string([]rune{prefix1, prefix2}), "0")))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// in this case, we've blown out the routing table with a paradoxical
|
||
|
// case. every node we added should have been the closest node, so this
|
||
|
// would have forced every bucket to split, and we should have stored all
|
||
|
// possible nodes.
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("ff", "f"), 33)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("f8", "0"), NodeFromPrefix("f1", "0"),
|
||
|
NodeFromPrefix("e8", "0"), NodeFromPrefix("e1", "0"),
|
||
|
NodeFromPrefix("d8", "0"), NodeFromPrefix("d1", "0"),
|
||
|
NodeFromPrefix("c8", "0"), NodeFromPrefix("c1", "0"),
|
||
|
NodeFromPrefix("b8", "0"), NodeFromPrefix("b1", "0"),
|
||
|
NodeFromPrefix("a8", "0"), NodeFromPrefix("a1", "0"),
|
||
|
NodeFromPrefix("98", "0"), NodeFromPrefix("91", "0"),
|
||
|
NodeFromPrefix("88", "0"), NodeFromPrefix("81", "0"),
|
||
|
NodeFromPrefix("78", "0"), NodeFromPrefix("71", "0"),
|
||
|
NodeFromPrefix("68", "0"), NodeFromPrefix("61", "0"),
|
||
|
NodeFromPrefix("58", "0"), NodeFromPrefix("51", "0"),
|
||
|
NodeFromPrefix("48", "0"), NodeFromPrefix("41", "0"),
|
||
|
NodeFromPrefix("38", "0"), NodeFromPrefix("31", "0"),
|
||
|
NodeFromPrefix("28", "0"), NodeFromPrefix("21", "0"),
|
||
|
NodeFromPrefix("18", "0"), NodeFromPrefix("11", "0"),
|
||
|
NodeFromPrefix("08", "0"), NodeFromPrefix("01", "0"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestQuery_Routing(t *testing.T) { testQuery(t, newRouting) }
|
||
|
func TestQuery_TestRouting(t *testing.T) { testQuery(t, newTestRouting) }
|
||
|
func testQuery(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("a3", "3"), 5, 2, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
for _, prefix2 := range "18" {
|
||
|
for _, prefix1 := range "b4f25c896de03a71" {
|
||
|
require.NoError(t, table.ConnectionSuccess(
|
||
|
NodeFromPrefix(string([]rune{prefix1, prefix2}), "f")))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("c7139", "1"), 2)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("c1", "f"),
|
||
|
NodeFromPrefix("d1", "f"),
|
||
|
}, nodes)
|
||
|
|
||
|
nodes, err = table.FindNear(PadID("c7139", "1"), 7)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("c1", "f"),
|
||
|
NodeFromPrefix("d1", "f"),
|
||
|
NodeFromPrefix("e1", "f"),
|
||
|
NodeFromPrefix("f1", "f"),
|
||
|
NodeFromPrefix("f8", "f"),
|
||
|
NodeFromPrefix("81", "f"),
|
||
|
NodeFromPrefix("88", "f"),
|
||
|
}, nodes)
|
||
|
|
||
|
nodes, err = table.FindNear(PadID("c7139", "1"), 10)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("c1", "f"),
|
||
|
NodeFromPrefix("d1", "f"),
|
||
|
NodeFromPrefix("e1", "f"),
|
||
|
NodeFromPrefix("f1", "f"),
|
||
|
NodeFromPrefix("f8", "f"),
|
||
|
NodeFromPrefix("81", "f"),
|
||
|
NodeFromPrefix("88", "f"),
|
||
|
NodeFromPrefix("91", "f"),
|
||
|
NodeFromPrefix("98", "f"),
|
||
|
NodeFromPrefix("a1", "f"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestFailureCounting_Routing(t *testing.T) { t.Skip() }
|
||
|
func TestFailureCounting_TestRouting(t *testing.T) { testFailureCounting(t, newTestRouting) }
|
||
|
func testFailureCounting(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("a3", "3"), 5, 2, 2)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
for _, prefix2 := range "18" {
|
||
|
for _, prefix1 := range "b4f25c896de03a71" {
|
||
|
require.NoError(t, table.ConnectionSuccess(
|
||
|
NodeFromPrefix(string([]rune{prefix1, prefix2}), "f")))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nochange := func() {
|
||
|
nodes, err := table.FindNear(PadID("c7139", "1"), 7)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("c1", "f"),
|
||
|
NodeFromPrefix("d1", "f"),
|
||
|
NodeFromPrefix("e1", "f"),
|
||
|
NodeFromPrefix("f1", "f"),
|
||
|
NodeFromPrefix("f8", "f"),
|
||
|
NodeFromPrefix("81", "f"),
|
||
|
NodeFromPrefix("88", "f"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
nochange()
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("d1", "f")))
|
||
|
nochange()
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("d1", "f")))
|
||
|
nochange()
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("d1", "f")))
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("c7139", "1"), 7)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("c1", "f"),
|
||
|
NodeFromPrefix("e1", "f"),
|
||
|
NodeFromPrefix("e8", "f"),
|
||
|
NodeFromPrefix("f1", "f"),
|
||
|
NodeFromPrefix("f8", "f"),
|
||
|
NodeFromPrefix("81", "f"),
|
||
|
NodeFromPrefix("88", "f"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestUpdateBucket_Routing(t *testing.T) { testUpdateBucket(t, newRouting) }
|
||
|
func TestUpdateBucket_TestRouting(t *testing.T) { testUpdateBucket(t, newTestRouting) }
|
||
|
func testUpdateBucket(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("a3", "3"), 5, 2, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
for _, prefix2 := range "18" {
|
||
|
for _, prefix1 := range "b4f25c896de03a71" {
|
||
|
require.NoError(t, table.ConnectionSuccess(
|
||
|
NodeFromPrefix(string([]rune{prefix1, prefix2}), "f")))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("c7139", "1"), 1)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("c1", "f"),
|
||
|
}, nodes)
|
||
|
|
||
|
require.NoError(t, table.ConnectionSuccess(
|
||
|
Node(PadID("c1", "f"), "new-address:3")))
|
||
|
|
||
|
nodes, err = table.FindNear(PadID("c7139", "1"), 1)
|
||
|
require.NoError(t, err)
|
||
|
require.Equal(t, 1, len(nodes))
|
||
|
require.Equal(t, PadID("c1", "f"), nodes[0].Id)
|
||
|
require.Equal(t, "new-address:3", nodes[0].Address.Address)
|
||
|
}
|
||
|
|
||
|
func TestUpdateCache_Routing(t *testing.T) { testUpdateCache(t, newRouting) }
|
||
|
func TestUpdateCache_TestRouting(t *testing.T) { testUpdateCache(t, newTestRouting) }
|
||
|
func testUpdateCache(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("a3", "3"), 1, 1, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("81", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("c1", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("41", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("01", "0")))
|
||
|
|
||
|
require.NoError(t, table.ConnectionSuccess(Node(PadID("01", "0"), "new-address:6")))
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("41", "0")))
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("01", "0"), 4)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
Node(PadID("01", "0"), "new-address:6"),
|
||
|
NodeFromPrefix("81", "0"),
|
||
|
NodeFromPrefix("c1", "0"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestFailureUnknownAddress_Routing(t *testing.T) { testFailureUnknownAddress(t, newRouting) }
|
||
|
func TestFailureUnknownAddress_TestRouting(t *testing.T) { testFailureUnknownAddress(t, newTestRouting) }
|
||
|
func testFailureUnknownAddress(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("a3", "3"), 1, 1, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("81", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("c1", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(Node(PadID("41", "0"), "address:2")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("01", "0")))
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("41", "0")))
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("01", "0"), 4)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
Node(PadID("41", "0"), "address:2"),
|
||
|
NodeFromPrefix("81", "0"),
|
||
|
NodeFromPrefix("c1", "0"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestShrink_Routing(t *testing.T) { testShrink(t, newRouting) }
|
||
|
func TestShrink_TestRouting(t *testing.T) { testShrink(t, newTestRouting) }
|
||
|
func testShrink(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("ff", "f"), 2, 2, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
// blow out the routing table
|
||
|
for _, prefix1 := range "0123456789abcdef" {
|
||
|
for _, prefix2 := range "18" {
|
||
|
require.NoError(t, table.ConnectionSuccess(
|
||
|
NodeFromPrefix(string([]rune{prefix1, prefix2}), "0")))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// delete some of the bad ones
|
||
|
for _, prefix1 := range "0123456789abcd" {
|
||
|
for _, prefix2 := range "18" {
|
||
|
require.NoError(t, table.ConnectionFailed(
|
||
|
NodeFromPrefix(string([]rune{prefix1, prefix2}), "0")))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add back some nodes more balanced
|
||
|
for _, prefix1 := range "3a50" {
|
||
|
for _, prefix2 := range "19" {
|
||
|
require.NoError(t, table.ConnectionSuccess(
|
||
|
NodeFromPrefix(string([]rune{prefix1, prefix2}), "0")))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// make sure table filled in alright
|
||
|
nodes, err := table.FindNear(PadID("ff", "f"), 13)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("f8", "0"),
|
||
|
NodeFromPrefix("f1", "0"),
|
||
|
NodeFromPrefix("e8", "0"),
|
||
|
NodeFromPrefix("e1", "0"),
|
||
|
NodeFromPrefix("a9", "0"),
|
||
|
NodeFromPrefix("a1", "0"),
|
||
|
NodeFromPrefix("59", "0"),
|
||
|
NodeFromPrefix("51", "0"),
|
||
|
NodeFromPrefix("39", "0"),
|
||
|
NodeFromPrefix("31", "0"),
|
||
|
NodeFromPrefix("09", "0"),
|
||
|
NodeFromPrefix("01", "0"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestReplacementCacheOrder_Routing(t *testing.T) { testReplacementCacheOrder(t, newRouting) }
|
||
|
func TestReplacementCacheOrder_TestRouting(t *testing.T) { testReplacementCacheOrder(t, newTestRouting) }
|
||
|
func testReplacementCacheOrder(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("a3", "3"), 1, 2, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("81", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("21", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("c1", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("41", "0")))
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix("01", "0")))
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("21", "0")))
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("55", "5"), 4)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("01", "0"),
|
||
|
NodeFromPrefix("c1", "0"),
|
||
|
NodeFromPrefix("81", "0"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestHealSplit_Routing(t *testing.T) { testHealSplit(t, newRouting) }
|
||
|
func TestHealSplit_TestRouting(t *testing.T) { testHealSplit(t, newTestRouting) }
|
||
|
func testHealSplit(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("55", "55"), 2, 2, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
for _, pad := range []string{"0", "1"} {
|
||
|
for _, prefix := range []string{"ff", "e1", "c1", "54", "56", "57"} {
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix(prefix, pad)))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("55", "55"), 9)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("54", "1"),
|
||
|
NodeFromPrefix("54", "0"),
|
||
|
NodeFromPrefix("57", "0"),
|
||
|
NodeFromPrefix("56", "0"),
|
||
|
NodeFromPrefix("c1", "1"),
|
||
|
NodeFromPrefix("c1", "0"),
|
||
|
NodeFromPrefix("ff", "0"),
|
||
|
NodeFromPrefix("e1", "0"),
|
||
|
}, nodes)
|
||
|
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("c1", "0")))
|
||
|
|
||
|
nodes, err = table.FindNear(PadID("55", "55"), 9)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("54", "1"),
|
||
|
NodeFromPrefix("54", "0"),
|
||
|
NodeFromPrefix("57", "0"),
|
||
|
NodeFromPrefix("56", "0"),
|
||
|
NodeFromPrefix("c1", "1"),
|
||
|
NodeFromPrefix("ff", "0"),
|
||
|
NodeFromPrefix("e1", "0"),
|
||
|
}, nodes)
|
||
|
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("ff", "0")))
|
||
|
nodes, err = table.FindNear(PadID("55", "55"), 9)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("54", "1"),
|
||
|
NodeFromPrefix("54", "0"),
|
||
|
NodeFromPrefix("57", "0"),
|
||
|
NodeFromPrefix("56", "0"),
|
||
|
NodeFromPrefix("c1", "1"),
|
||
|
NodeFromPrefix("e1", "1"),
|
||
|
NodeFromPrefix("e1", "0"),
|
||
|
}, nodes)
|
||
|
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("e1", "0")))
|
||
|
nodes, err = table.FindNear(PadID("55", "55"), 9)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("54", "1"),
|
||
|
NodeFromPrefix("54", "0"),
|
||
|
NodeFromPrefix("57", "0"),
|
||
|
NodeFromPrefix("56", "0"),
|
||
|
NodeFromPrefix("c1", "1"),
|
||
|
NodeFromPrefix("ff", "1"),
|
||
|
NodeFromPrefix("e1", "1"),
|
||
|
}, nodes)
|
||
|
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("e1", "1")))
|
||
|
nodes, err = table.FindNear(PadID("55", "55"), 9)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("54", "1"),
|
||
|
NodeFromPrefix("54", "0"),
|
||
|
NodeFromPrefix("57", "0"),
|
||
|
NodeFromPrefix("56", "0"),
|
||
|
NodeFromPrefix("c1", "1"),
|
||
|
NodeFromPrefix("ff", "1"),
|
||
|
}, nodes)
|
||
|
|
||
|
for _, prefix := range []string{"ff", "e1", "c1", "54", "56", "57"} {
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix(prefix, "2")))
|
||
|
}
|
||
|
|
||
|
nodes, err = table.FindNear(PadID("55", "55"), 9)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("54", "1"),
|
||
|
NodeFromPrefix("54", "0"),
|
||
|
NodeFromPrefix("57", "0"),
|
||
|
NodeFromPrefix("56", "0"),
|
||
|
NodeFromPrefix("c1", "1"),
|
||
|
NodeFromPrefix("c1", "2"),
|
||
|
NodeFromPrefix("ff", "1"),
|
||
|
NodeFromPrefix("ff", "2"),
|
||
|
}, nodes)
|
||
|
}
|
||
|
|
||
|
func TestFullDissimilarBucket_Routing(t *testing.T) { testFullDissimilarBucket(t, newRouting) }
|
||
|
func TestFullDissimilarBucket_TestRouting(t *testing.T) { testFullDissimilarBucket(t, newTestRouting) }
|
||
|
func testFullDissimilarBucket(t *testing.T, routingCtor routingCtor) {
|
||
|
ctx := testcontext.New(t)
|
||
|
defer ctx.Cleanup()
|
||
|
|
||
|
table := routingCtor(PadID("55", "55"), 2, 2, 0)
|
||
|
defer ctx.Check(table.Close)
|
||
|
|
||
|
for _, prefix := range []string{"d1", "c1", "f1", "e1"} {
|
||
|
require.NoError(t, table.ConnectionSuccess(NodeFromPrefix(prefix, "0")))
|
||
|
}
|
||
|
|
||
|
nodes, err := table.FindNear(PadID("55", "55"), 9)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("d1", "0"),
|
||
|
NodeFromPrefix("c1", "0"),
|
||
|
}, nodes)
|
||
|
|
||
|
require.NoError(t, table.ConnectionFailed(NodeFromPrefix("c1", "0")))
|
||
|
|
||
|
nodes, err = table.FindNear(PadID("55", "55"), 9)
|
||
|
require.NoError(t, err)
|
||
|
requireNodesEqual(t, []*pb.Node{
|
||
|
NodeFromPrefix("d1", "0"),
|
||
|
NodeFromPrefix("e1", "0"),
|
||
|
}, nodes)
|
||
|
}
|