storj/pkg/kademlia/routing_helpers_test.go

721 lines
20 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information
package kademlia
import (
"io/ioutil"
"os"
"testing"
"time"
pb "github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
proto "storj.io/storj/protos/overlay"
"storj.io/storj/storage"
)
func tempfile(fileName string) string {
f, err := ioutil.TempFile("", fileName)
if err != nil {
panic(err)
}
err = f.Close()
if err != nil {
panic(err)
}
err = os.Remove(f.Name())
if err != nil {
panic(err)
}
return f.Name()
}
func createRT(localNodeID []byte) *RoutingTable {
if localNodeID == nil {
localNodeID = []byte("AA")
}
localNode := &proto.Node{Id: string(localNodeID)}
options := &RoutingOptions{
kpath: tempfile("Kadbucket"),
npath: tempfile("Nodebucket"),
idLength: 16,
bucketSize: 6,
rcBucketSize: 2,
}
rt, _ := NewRoutingTable(localNode, options)
return rt
}
func mockNode(id string) *proto.Node {
var node proto.Node
node.Id = id
return &node
}
func TestAddNode(t *testing.T) {
rt := createRT([]byte("OO")) //localNode [79, 79] or [01001111, 01001111]
bucket, err := rt.kadBucketDB.Get(storage.Key([]byte{255, 255}))
assert.NoError(t, err)
assert.NotNil(t, bucket)
var ok bool
//add node to unfilled kbucket
node1 := mockNode("PO") //[80, 79] or [01010000, 01001111]
ok, err = rt.addNode(node1)
assert.True(t, ok)
assert.NoError(t, err)
kadKeys, err := rt.kadBucketDB.List(nil, 0)
assert.NoError(t, err)
nodeKeys, err := rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
assert.Equal(t, 1, len(kadKeys))
assert.Equal(t, 2, len(nodeKeys))
//add node to full kbucket and split
node2 := mockNode("NO") //[78, 79] or [01001110, 01001111]
ok, err = rt.addNode(node2)
assert.True(t, ok)
assert.NoError(t, err)
node3 := mockNode("MO") //[77, 79] or [01001101, 01001111]
ok, err = rt.addNode(node3)
assert.True(t, ok)
assert.NoError(t, err)
node4 := mockNode("LO") //[76, 79] or [01001100, 01001111]
ok, err = rt.addNode(node4)
assert.True(t, ok)
assert.NoError(t, err)
node5 := mockNode("QO") //[81, 79] or [01010001, 01001111]
ok, err = rt.addNode(node5)
assert.True(t, ok)
assert.NoError(t, err)
kadKeys, err = rt.kadBucketDB.List(nil, 0)
assert.NoError(t, err)
nodeKeys, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
assert.Equal(t, 1, len(kadKeys))
assert.Equal(t, 6, len(nodeKeys))
//splitting here
node6 := mockNode("SO")
ok, err = rt.addNode(node6)
assert.True(t, ok)
assert.NoError(t, err)
kadKeys, err = rt.kadBucketDB.List(nil, 0)
assert.NoError(t, err)
nodeKeys, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
assert.Equal(t, 5, len(kadKeys))
assert.Equal(t, 7, len(nodeKeys))
// //check how many keys in each bucket
a, err := rt.getNodeIDsWithinKBucket(kadKeys[0])
assert.NoError(t, err)
assert.Equal(t, 0, len(a))
b, err := rt.getNodeIDsWithinKBucket(kadKeys[1])
assert.NoError(t, err)
assert.Equal(t, 4, len(b))
c, err := rt.getNodeIDsWithinKBucket(kadKeys[2])
assert.NoError(t, err)
assert.Equal(t, 3, len(c))
d, err := rt.getNodeIDsWithinKBucket(kadKeys[3])
assert.NoError(t, err)
assert.Equal(t, 0, len(d))
e, err := rt.getNodeIDsWithinKBucket(kadKeys[4])
assert.NoError(t, err)
assert.Equal(t, 0, len(e))
//add node to full kbucket and drop
node7 := mockNode("?O")
ok, err = rt.addNode(node7)
assert.True(t, ok)
assert.NoError(t, err)
node8 := mockNode(">O")
ok, err = rt.addNode(node8)
assert.True(t, ok)
assert.NoError(t, err)
node9 := mockNode("=O")
ok, err = rt.addNode(node9)
assert.True(t, ok)
assert.NoError(t, err)
node10 := mockNode(";O")
ok, err = rt.addNode(node10)
assert.True(t, ok)
assert.NoError(t, err)
node11 := mockNode(":O")
ok, err = rt.addNode(node11)
assert.True(t, ok)
assert.NoError(t, err)
node12 := mockNode("9O")
ok, err = rt.addNode(node12)
assert.True(t, ok)
assert.NoError(t, err)
kadKeys, err = rt.kadBucketDB.List(nil, 0)
assert.NoError(t, err)
nodeKeys, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
assert.Equal(t, 5, len(kadKeys))
assert.Equal(t, 13, len(nodeKeys))
a, err = rt.getNodeIDsWithinKBucket(kadKeys[0])
assert.NoError(t, err)
assert.Equal(t, 6, len(a))
//should drop
node13 := mockNode("8O")
ok, err = rt.addNode(node13)
assert.False(t, ok)
assert.NoError(t, err)
//check if node13 it into the replacement cache
ns := rt.replacementCache[string([]byte{63, 255})]
assert.Equal(t, node13.Id, ns[0].Id)
kadKeys, err = rt.kadBucketDB.List(nil, 0)
assert.NoError(t, err)
nodeKeys, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
assert.Equal(t, 5, len(kadKeys))
assert.Equal(t, 13, len(nodeKeys))
a, err = rt.getNodeIDsWithinKBucket(kadKeys[0])
assert.NoError(t, err)
assert.Equal(t, 6, len(a))
//add node to highly unbalanced tree
//adding to bucket 1
node14 := mockNode("KO") //75
ok, err = rt.addNode(node14)
assert.True(t, ok)
assert.NoError(t, err)
node15 := mockNode("JO") //74
ok, err = rt.addNode(node15)
assert.True(t, ok)
assert.NoError(t, err)
//adding to bucket 2
node16 := mockNode("]O") //93
ok, err = rt.addNode(node16)
assert.True(t, ok)
assert.NoError(t, err)
node17 := mockNode("^O") //94
ok, err = rt.addNode(node17)
assert.True(t, ok)
assert.NoError(t, err)
node18 := mockNode("_O") //95
ok, err = rt.addNode(node18)
assert.True(t, ok)
assert.NoError(t, err)
b, err = rt.getNodeIDsWithinKBucket(kadKeys[1])
assert.NoError(t, err)
assert.Equal(t, 6, len(b))
c, err = rt.getNodeIDsWithinKBucket(kadKeys[2])
assert.NoError(t, err)
assert.Equal(t, 6, len(c))
kadKeys, err = rt.kadBucketDB.List(nil, 0)
assert.NoError(t, err)
nodeKeys, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
assert.Equal(t, 5, len(kadKeys))
assert.Equal(t, 18, len(nodeKeys))
//split bucket 2
node19 := mockNode("@O")
ok, err = rt.addNode(node19)
assert.True(t, ok)
assert.NoError(t, err)
kadKeys, err = rt.kadBucketDB.List(nil, 0)
assert.NoError(t, err)
nodeKeys, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
assert.Equal(t, 6, len(kadKeys))
assert.Equal(t, 19, len(nodeKeys))
}
func TestUpdateNode(t *testing.T) {
rt := createRT([]byte("AA"))
node := mockNode("BB")
ok, err := rt.addNode(node)
assert.True(t, ok)
assert.NoError(t, err)
val, err := rt.nodeBucketDB.Get(storage.Key(node.Id))
assert.NoError(t, err)
unmarshaled, err := unmarshalNodes(storage.Keys{storage.Key(node.Id)}, []storage.Value{val})
assert.NoError(t, err)
x := unmarshaled[0].Address
assert.Nil(t, x)
node.Address = &proto.NodeAddress{Address: "BB"}
err = rt.updateNode(node)
assert.NoError(t, err)
val, err = rt.nodeBucketDB.Get(storage.Key(node.Id))
assert.NoError(t, err)
unmarshaled, err = unmarshalNodes(storage.Keys{storage.Key(node.Id)}, []storage.Value{val})
assert.NoError(t, err)
y := unmarshaled[0].Address.Address
assert.Equal(t, "BB", y)
}
func TestRemoveNode(t *testing.T) {
rt := createRT([]byte("AA"))
kadBucketID := []byte{255, 255}
node := mockNode("BB")
ok, err := rt.addNode(node)
assert.True(t, ok)
assert.NoError(t, err)
val, err := rt.nodeBucketDB.Get(storage.Key(node.Id))
assert.NoError(t, err)
assert.NotNil(t, val)
node2 := mockNode("CC")
rt.addToReplacementCache(kadBucketID, node2)
err = rt.removeNode(kadBucketID, storage.Key(node.Id))
assert.NoError(t, err)
val, err = rt.nodeBucketDB.Get(storage.Key(node.Id))
assert.Nil(t, val)
assert.Error(t, err)
val2, err := rt.nodeBucketDB.Get(storage.Key(node2.Id))
assert.NoError(t, err)
assert.NotNil(t, val2)
assert.Equal(t, 0, len(rt.replacementCache[string(kadBucketID)]))
//try to remove node not in rt
err = rt.removeNode(kadBucketID, storage.Key("DD"))
assert.NoError(t, err)
}
func TestCreateOrUpdateKBucket(t *testing.T) {
id := []byte{255, 255}
rt := createRT(nil)
err := rt.createOrUpdateKBucket(storage.Key(id), time.Now())
assert.NoError(t, err)
val, e := rt.kadBucketDB.Get(storage.Key(id))
assert.NotNil(t, val)
assert.NoError(t, e)
}
func TestGetKBucketID(t *testing.T) {
kadIDA := storage.Key([]byte{255, 255})
nodeIDA := []byte("AA")
rt := createRT(nodeIDA)
keyA, err := rt.getKBucketID(nodeIDA)
assert.NoError(t, err)
assert.Equal(t, kadIDA, keyA)
}
func TestXorTwoIds(t *testing.T) {
x := xorTwoIds([]byte{191}, []byte{159})
assert.Equal(t, []byte{32}, x) //00100000
}
func TestSortByXOR(t *testing.T) {
node1 := []byte{127, 255} //xor 0
rt := createRT(node1)
node2 := []byte{143, 255} //xor 240
assert.NoError(t, rt.nodeBucketDB.Put(node2, []byte("")))
node3 := []byte{255, 255} //xor 128
assert.NoError(t, rt.nodeBucketDB.Put(node3, []byte("")))
node4 := []byte{191, 255} //xor 192
assert.NoError(t, rt.nodeBucketDB.Put(node4, []byte("")))
node5 := []byte{133, 255} //xor 250
assert.NoError(t, rt.nodeBucketDB.Put(node5, []byte("")))
nodes, err := rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
expectedNodes := storage.Keys{node1, node5, node2, node4, node3}
assert.Equal(t, expectedNodes, nodes)
sortedNodes := sortByXOR(nodes, node1)
expectedSorted := storage.Keys{node1, node3, node4, node2, node5}
assert.Equal(t, expectedSorted, sortedNodes)
nodes, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
assert.Equal(t, expectedNodes, nodes)
}
func TestDetermineFurthestIDWithinK(t *testing.T) {
node1 := []byte{127, 255} //xor 0
rt := createRT(node1)
rt.self.Id = string(node1)
assert.NoError(t, rt.nodeBucketDB.Put(node1, []byte("")))
expectedFurthest := node1
nodes, err := rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
furthest, err := rt.determineFurthestIDWithinK(nodes)
assert.NoError(t, err)
assert.Equal(t, expectedFurthest, furthest)
node2 := []byte{143, 255} //xor 240
assert.NoError(t, rt.nodeBucketDB.Put(node2, []byte("")))
expectedFurthest = node2
nodes, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
furthest, err = rt.determineFurthestIDWithinK(nodes)
assert.NoError(t, err)
assert.Equal(t, expectedFurthest, furthest)
node3 := []byte{255, 255} //xor 128
assert.NoError(t, rt.nodeBucketDB.Put(node3, []byte("")))
expectedFurthest = node2
nodes, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
furthest, err = rt.determineFurthestIDWithinK(nodes)
assert.NoError(t, err)
assert.Equal(t, expectedFurthest, furthest)
node4 := []byte{191, 255} //xor 192
assert.NoError(t, rt.nodeBucketDB.Put(node4, []byte("")))
expectedFurthest = node2
nodes, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
furthest, err = rt.determineFurthestIDWithinK(nodes)
assert.NoError(t, err)
assert.Equal(t, expectedFurthest, furthest)
node5 := []byte{133, 255} //xor 250
assert.NoError(t, rt.nodeBucketDB.Put(node5, []byte("")))
expectedFurthest = node5
nodes, err = rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
furthest, err = rt.determineFurthestIDWithinK(nodes)
assert.NoError(t, err)
assert.Equal(t, expectedFurthest, furthest)
}
func TestNodeIsWithinNearestK(t *testing.T) {
selfNode := []byte{127, 255}
rt := createRT(selfNode)
rt.bucketSize = 2
expectTrue, err := rt.nodeIsWithinNearestK(selfNode)
assert.NoError(t, err)
assert.True(t, expectTrue)
furthestNode := []byte{143, 255}
expectTrue, err = rt.nodeIsWithinNearestK(furthestNode)
assert.NoError(t, err)
assert.True(t, expectTrue)
assert.NoError(t, rt.nodeBucketDB.Put(furthestNode, []byte("")))
node1 := []byte{255, 255}
expectTrue, err = rt.nodeIsWithinNearestK(node1)
assert.NoError(t, err)
assert.True(t, expectTrue)
assert.NoError(t, rt.nodeBucketDB.Put(node1, []byte("")))
node2 := []byte{191, 255}
expectTrue, err = rt.nodeIsWithinNearestK(node2)
assert.NoError(t, err)
assert.True(t, expectTrue)
assert.NoError(t, rt.nodeBucketDB.Put(node1, []byte("")))
node3 := []byte{133, 255}
expectFalse, err := rt.nodeIsWithinNearestK(node3)
assert.NoError(t, err)
assert.False(t, expectFalse)
}
func TestKadBucketContainsLocalNode(t *testing.T) {
nodeIDA := []byte{183, 255} //[10110111, 1111111]
rt := createRT(nodeIDA)
kadIDA := storage.Key([]byte{255, 255})
kadIDB := storage.Key([]byte{127, 255})
now := time.Now()
err := rt.createOrUpdateKBucket(kadIDB, now)
assert.NoError(t, err)
resultTrue, err := rt.kadBucketContainsLocalNode(kadIDA)
assert.NoError(t, err)
resultFalse, err := rt.kadBucketContainsLocalNode(kadIDB)
assert.NoError(t, err)
assert.True(t, resultTrue)
assert.False(t, resultFalse)
}
func TestKadBucketHasRoom(t *testing.T) {
node1 := []byte{255, 255}
kadIDA := storage.Key([]byte{255, 255})
rt := createRT(node1)
node2 := []byte{191, 255}
node3 := []byte{127, 255}
node4 := []byte{63, 255}
node5 := []byte{159, 255}
node6 := []byte{0, 127}
resultA, err := rt.kadBucketHasRoom(kadIDA)
assert.NoError(t, err)
assert.True(t, resultA)
assert.NoError(t, rt.nodeBucketDB.Put(node2, []byte("")))
assert.NoError(t, rt.nodeBucketDB.Put(node3, []byte("")))
assert.NoError(t, rt.nodeBucketDB.Put(node4, []byte("")))
assert.NoError(t, rt.nodeBucketDB.Put(node5, []byte("")))
assert.NoError(t, rt.nodeBucketDB.Put(node6, []byte("")))
resultB, err := rt.kadBucketHasRoom(kadIDA)
assert.NoError(t, err)
assert.False(t, resultB)
}
func TestGetNodeIDsWithinKBucket(t *testing.T) {
nodeIDA := []byte{183, 255} //[10110111, 1111111]
rt := createRT(nodeIDA)
kadIDA := storage.Key([]byte{255, 255})
kadIDB := storage.Key([]byte{127, 255})
now := time.Now()
assert.NoError(t, rt.createOrUpdateKBucket(kadIDB, now))
nodeIDB := []byte{111, 255} //[01101111, 1111111]
nodeIDC := []byte{47, 255} //[00101111, 1111111]
assert.NoError(t, rt.nodeBucketDB.Put(nodeIDB, []byte("")))
assert.NoError(t, rt.nodeBucketDB.Put(nodeIDC, []byte("")))
expectedA := storage.Keys{nodeIDA}
expectedB := storage.Keys{nodeIDC, nodeIDB}
A, err := rt.getNodeIDsWithinKBucket(kadIDA)
assert.NoError(t, err)
B, err := rt.getNodeIDsWithinKBucket(kadIDB)
assert.NoError(t, err)
assert.Equal(t, expectedA, A)
assert.Equal(t, expectedB, B)
}
func TestGetNodesFromIDs(t *testing.T) {
nodeA := mockNode("AA")
nodeB := mockNode("BB")
nodeC := mockNode("CC")
nodeIDA := []byte(nodeA.Id)
nodeIDB := []byte(nodeB.Id)
nodeIDC := []byte(nodeC.Id)
a, err := pb.Marshal(nodeA)
assert.NoError(t, err)
b, err := pb.Marshal(nodeB)
assert.NoError(t, err)
c, err := pb.Marshal(nodeC)
assert.NoError(t, err)
rt := createRT(nodeIDA)
assert.NoError(t, rt.nodeBucketDB.Put(nodeIDA, a))
assert.NoError(t, rt.nodeBucketDB.Put(nodeIDB, b))
assert.NoError(t, rt.nodeBucketDB.Put(nodeIDC, c))
expected := []storage.Value{a, b, c}
nodeIDs, err := rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
_, values, err := rt.getNodesFromIDs(nodeIDs)
assert.NoError(t, err)
assert.Equal(t, expected, values)
}
func TestUnmarshalNodes(t *testing.T) {
nodeA := mockNode("AA")
nodeB := mockNode("BB")
nodeC := mockNode("CC")
nodeIDA := []byte(nodeA.Id)
nodeIDB := []byte(nodeB.Id)
nodeIDC := []byte(nodeC.Id)
a, err := pb.Marshal(nodeA)
assert.NoError(t, err)
b, err := pb.Marshal(nodeB)
assert.NoError(t, err)
c, err := pb.Marshal(nodeC)
assert.NoError(t, err)
rt := createRT(nodeIDA)
assert.NoError(t, rt.nodeBucketDB.Put(nodeIDA, a))
assert.NoError(t, rt.nodeBucketDB.Put(nodeIDB, b))
assert.NoError(t, rt.nodeBucketDB.Put(nodeIDC, c))
nodeIDs, err := rt.nodeBucketDB.List(nil, 0)
assert.NoError(t, err)
ids, values, err := rt.getNodesFromIDs(nodeIDs)
assert.NoError(t, err)
nodes, err := unmarshalNodes(ids, values)
assert.NoError(t, err)
expected := []*proto.Node{nodeA, nodeB, nodeC}
for i, v := range expected {
assert.True(t, pb.Equal(v, nodes[i]))
}
}
func TestGetUnmarshaledNodesFromBucket(t *testing.T) {
bucketID := []byte{255, 255}
nodeA := mockNode("AA")
rt := createRT([]byte(nodeA.Id))
nodeB := mockNode("BB")
nodeC := mockNode("CC")
var err error
_, err = rt.addNode(nodeB)
assert.NoError(t, err)
_, err = rt.addNode(nodeC)
assert.NoError(t, err)
nodes, err := rt.getUnmarshaledNodesFromBucket(bucketID)
expected := []*proto.Node{nodeA, nodeB, nodeC}
assert.NoError(t, err)
for i, v := range expected {
assert.True(t, pb.Equal(v, nodes[i]))
}
}
func TestGetKBucketRange(t *testing.T) {
rt := createRT(nil)
idA := []byte{255, 255}
idB := []byte{127, 255}
idC := []byte{63, 255}
assert.NoError(t, rt.kadBucketDB.Put(idA, []byte("")))
assert.NoError(t, rt.kadBucketDB.Put(idB, []byte("")))
assert.NoError(t, rt.kadBucketDB.Put(idC, []byte("")))
expectedA := storage.Keys{idB, idA}
expectedB := storage.Keys{idC, idB}
expectedC := storage.Keys{rt.createZeroAsStorageKey(), idC}
endpointsA, err := rt.getKBucketRange(idA)
assert.NoError(t, err)
endpointsB, err := rt.getKBucketRange(idB)
assert.NoError(t, err)
endpointsC, err := rt.getKBucketRange(idC)
assert.NoError(t, err)
assert.Equal(t, expectedA, endpointsA)
assert.Equal(t, expectedB, endpointsB)
assert.Equal(t, expectedC, endpointsC)
}
func TestCreateFirstBucketID(t *testing.T) {
rt := createRT(nil)
x := rt.createFirstBucketID()
expected := []byte{255, 255}
assert.Equal(t, x, expected)
}
func TestCreateZeroAsStorageKey(t *testing.T) {
rt := createRT(nil)
zero := rt.createZeroAsStorageKey()
expected := []byte{0, 0}
assert.Equal(t, zero, storage.Key(expected))
}
func TestDetermineLeafDepth(t *testing.T) {
rt := createRT(nil)
idA := []byte{255, 255}
idB := []byte{127, 255}
idC := []byte{63, 255}
err := rt.kadBucketDB.Put(idA, []byte(""))
assert.NoError(t, err)
first, err := rt.determineLeafDepth(idA)
assert.NoError(t, err)
assert.Equal(t, 0, first)
err = rt.kadBucketDB.Put(idB, []byte(""))
assert.NoError(t, err)
second, err := rt.determineLeafDepth(idB)
assert.NoError(t, err)
assert.Equal(t, 1, second)
err = rt.kadBucketDB.Put(idC, []byte(""))
assert.NoError(t, err)
one, err := rt.determineLeafDepth(idA)
assert.NoError(t, err)
assert.Equal(t, 1, one)
two, err := rt.determineLeafDepth(idB)
assert.NoError(t, err)
assert.Equal(t, 2, two)
alsoTwo, err := rt.determineLeafDepth(idC)
assert.NoError(t, err)
assert.Equal(t, 2, alsoTwo)
}
func TestDetermineDifferingBitIndex(t *testing.T) {
rt := createRT(nil)
diff, err := rt.determineDifferingBitIndex([]byte{191, 255}, []byte{255, 255})
assert.NoError(t, err)
assert.Equal(t, 1, diff)
diff, err = rt.determineDifferingBitIndex([]byte{255, 255}, []byte{191, 255})
assert.NoError(t, err)
assert.Equal(t, 1, diff)
diff, err = rt.determineDifferingBitIndex([]byte{95, 255}, []byte{127, 255})
assert.NoError(t, err)
assert.Equal(t, 2, diff)
diff, err = rt.determineDifferingBitIndex([]byte{95, 255}, []byte{79, 255})
assert.NoError(t, err)
assert.Equal(t, 3, diff)
diff, err = rt.determineDifferingBitIndex([]byte{95, 255}, []byte{63, 255})
assert.NoError(t, err)
assert.Equal(t, 2, diff)
diff, err = rt.determineDifferingBitIndex([]byte{95, 255}, []byte{79, 255})
assert.NoError(t, err)
assert.Equal(t, 3, diff)
diff, err = rt.determineDifferingBitIndex([]byte{255, 255}, []byte{255, 255})
assert.Error(t, err)
assert.Equal(t, -2, diff)
diff, err = rt.determineDifferingBitIndex([]byte{255, 255}, []byte{0, 0})
assert.NoError(t, err)
assert.Equal(t, -1, diff)
diff, err = rt.determineDifferingBitIndex([]byte{127, 255}, []byte{0, 0})
assert.NoError(t, err)
assert.Equal(t, 0, diff)
diff, err = rt.determineDifferingBitIndex([]byte{63, 255}, []byte{0, 0})
assert.NoError(t, err)
assert.Equal(t, 1, diff)
diff, err = rt.determineDifferingBitIndex([]byte{31, 255}, []byte{0, 0})
assert.NoError(t, err)
assert.Equal(t, 2, diff)
diff, err = rt.determineDifferingBitIndex([]byte{95, 255}, []byte{63, 255})
assert.NoError(t, err)
assert.Equal(t, 2, diff)
}
func TestSplitBucket(t *testing.T) {
rt := createRT(nil)
id1 := []byte{255, 255}
id2 := []byte{191, 255}
id3 := []byte{127, 255}
id4 := []byte{63, 255}
id5 := []byte{159, 255}
id6 := []byte{0, 127}
id7 := []byte{0, 255}
id8 := []byte{95, 255}
id9 := []byte{87, 255}
newID1 := rt.splitBucket(id1, 1) //[11111111, 11111111] -> [10111111, 11111111]
assert.Equal(t, id2, newID1)
newID2 := rt.splitBucket(id2, 2) //[10111111, 11111111] -> [10011111, 11111111]
assert.Equal(t, id5, newID2)
newID3 := rt.splitBucket(id3, 1) //[01111111, 11111111] -> [00111111, 11111111]
assert.Equal(t, id4, newID3)
newID4 := rt.splitBucket(id7, 8) //[00000000, 11111111] -> [00000000, 01111111]
assert.Equal(t, id6, newID4)
newID5 := rt.splitBucket(id8, 4) //[01011111, 11111111] -> [01010111, 11111111]
assert.Equal(t, id9, newID5)
newID6 := rt.splitBucket(id8, 3)
assert.Equal(t, []byte{79, 255}, newID6)
}