2018-03-07 02:15:44 +01:00
|
|
|
package dht
|
|
|
|
|
2018-03-09 01:50:18 +01:00
|
|
|
import (
|
2018-05-19 19:05:30 +02:00
|
|
|
"encoding/json"
|
2018-03-09 01:50:18 +01:00
|
|
|
"net"
|
2018-05-19 19:05:30 +02:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2018-03-09 01:50:18 +01:00
|
|
|
"testing"
|
2018-05-19 19:05:30 +02:00
|
|
|
|
2018-06-14 17:48:02 +02:00
|
|
|
"github.com/lbryio/reflector.go/dht/bits"
|
2018-05-19 19:05:30 +02:00
|
|
|
"github.com/sebdah/goldie"
|
2018-03-09 01:50:18 +01:00
|
|
|
)
|
2018-03-07 02:15:44 +01:00
|
|
|
|
2018-03-29 03:05:27 +02:00
|
|
|
func TestRoutingTable_bucketFor(t *testing.T) {
|
2018-06-14 17:48:02 +02:00
|
|
|
rt := newRoutingTable(bits.FromHexP("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))
|
2018-03-29 03:05:27 +02:00
|
|
|
var tests = []struct {
|
2018-06-14 17:48:02 +02:00
|
|
|
id bits.Bitmap
|
2018-03-29 03:05:27 +02:00
|
|
|
expected int
|
|
|
|
}{
|
2018-06-14 17:48:02 +02:00
|
|
|
{bits.FromHexP("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"), 0},
|
|
|
|
{bits.FromHexP("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"), 1},
|
|
|
|
{bits.FromHexP("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"), 1},
|
|
|
|
{bits.FromHexP("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004"), 2},
|
|
|
|
{bits.FromHexP("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005"), 2},
|
|
|
|
{bits.FromHexP("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f"), 3},
|
|
|
|
{bits.FromHexP("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010"), 4},
|
|
|
|
{bits.FromHexP("F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), 383},
|
|
|
|
{bits.FromHexP("F0000000000000000000000000000000F0000000000000000000000000F0000000000000000000000000000000000000"), 383},
|
2018-03-29 03:05:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
2018-05-13 22:02:46 +02:00
|
|
|
bucket := rt.bucketNumFor(tt.id)
|
2018-03-29 03:05:27 +02:00
|
|
|
if bucket != tt.expected {
|
2018-05-13 22:02:46 +02:00
|
|
|
t.Errorf("bucketFor(%s, %s) => %d, want %d", tt.id.Hex(), rt.id.Hex(), bucket, tt.expected)
|
2018-03-29 03:05:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-26 19:42:36 +02:00
|
|
|
func TestRoutingTableFillBuckets(t *testing.T) {
|
|
|
|
n1 := bits.FromHexP("FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n2 := bits.FromHexP("FFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n3 := bits.FromHexP("111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n4 := bits.FromHexP("111111120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n5 := bits.FromHexP("111111130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n6 := bits.FromHexP("111111140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n7 := bits.FromHexP("111111150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n8 := bits.FromHexP("111111160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n9 := bits.FromHexP("111111070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
|
|
|
|
rt := newRoutingTable(n1)
|
|
|
|
rt.Update(Contact{n2, net.ParseIP("127.0.0.1"), 8001})
|
|
|
|
rt.Update(Contact{n3, net.ParseIP("127.0.0.1"), 8002})
|
|
|
|
rt.Update(Contact{n4, net.ParseIP("127.0.0.1"), 8003})
|
|
|
|
rt.Update(Contact{n5, net.ParseIP("127.0.0.1"), 8004})
|
|
|
|
rt.Update(Contact{n6, net.ParseIP("127.0.0.1"), 8005})
|
|
|
|
rt.Update(Contact{n7, net.ParseIP("127.0.0.1"), 8006})
|
|
|
|
rt.Update(Contact{n7, net.ParseIP("127.0.0.1"), 8007})
|
|
|
|
rt.Update(Contact{n8, net.ParseIP("127.0.0.1"), 8008})
|
|
|
|
rt.Update(Contact{n9, net.ParseIP("127.0.0.1"), 8009})
|
|
|
|
|
|
|
|
log.Printf(rt.BucketInfo())
|
|
|
|
}
|
|
|
|
|
2018-05-19 19:05:30 +02:00
|
|
|
func TestRoutingTable_GetClosest(t *testing.T) {
|
2018-06-14 17:48:02 +02:00
|
|
|
n1 := bits.FromHexP("FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n2 := bits.FromHexP("FFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
|
|
n3 := bits.FromHexP("111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
2018-04-28 02:16:12 +02:00
|
|
|
rt := newRoutingTable(n1)
|
|
|
|
rt.Update(Contact{n2, net.ParseIP("127.0.0.1"), 8001})
|
|
|
|
rt.Update(Contact{n3, net.ParseIP("127.0.0.1"), 8002})
|
2018-03-07 02:15:44 +01:00
|
|
|
|
2018-06-14 17:48:02 +02:00
|
|
|
contacts := rt.GetClosest(bits.FromHexP("222222220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), 1)
|
2018-03-07 02:15:44 +01:00
|
|
|
if len(contacts) != 1 {
|
|
|
|
t.Fail()
|
|
|
|
return
|
|
|
|
}
|
2018-05-19 19:05:30 +02:00
|
|
|
if !contacts[0].ID.Equals(n3) {
|
2018-03-07 02:15:44 +01:00
|
|
|
t.Error(contacts[0])
|
|
|
|
}
|
|
|
|
|
2018-03-29 03:05:27 +02:00
|
|
|
contacts = rt.GetClosest(n2, 10)
|
2018-03-07 02:15:44 +01:00
|
|
|
if len(contacts) != 2 {
|
|
|
|
t.Error(len(contacts))
|
|
|
|
return
|
|
|
|
}
|
2018-05-19 19:05:30 +02:00
|
|
|
if !contacts[0].ID.Equals(n2) {
|
2018-03-07 02:15:44 +01:00
|
|
|
t.Error(contacts[0])
|
|
|
|
}
|
2018-05-19 19:05:30 +02:00
|
|
|
if !contacts[1].ID.Equals(n3) {
|
2018-03-07 02:15:44 +01:00
|
|
|
t.Error(contacts[1])
|
|
|
|
}
|
|
|
|
}
|
2018-03-09 01:50:18 +01:00
|
|
|
|
2018-05-19 19:05:30 +02:00
|
|
|
func TestRoutingTable_Refresh(t *testing.T) {
|
2018-05-13 22:02:46 +02:00
|
|
|
t.Skip("TODO: test routing table refreshing")
|
|
|
|
}
|
2018-05-19 19:05:30 +02:00
|
|
|
|
|
|
|
func TestRoutingTable_MoveToBack(t *testing.T) {
|
|
|
|
tt := map[string]struct {
|
|
|
|
data []peer
|
|
|
|
index int
|
|
|
|
expected []peer
|
|
|
|
}{
|
|
|
|
"simpleMove": {
|
|
|
|
data: []peer{{NumFailures: 0}, {NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}},
|
|
|
|
index: 1,
|
|
|
|
expected: []peer{{NumFailures: 0}, {NumFailures: 2}, {NumFailures: 3}, {NumFailures: 1}},
|
|
|
|
},
|
|
|
|
"moveFirst": {
|
|
|
|
data: []peer{{NumFailures: 0}, {NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}},
|
|
|
|
index: 0,
|
|
|
|
expected: []peer{{NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}, {NumFailures: 0}},
|
|
|
|
},
|
|
|
|
"moveLast": {
|
|
|
|
data: []peer{{NumFailures: 0}, {NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}},
|
|
|
|
index: 3,
|
|
|
|
expected: []peer{{NumFailures: 0}, {NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}},
|
|
|
|
},
|
|
|
|
"largeIndex": {
|
|
|
|
data: []peer{{NumFailures: 0}, {NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}},
|
|
|
|
index: 27,
|
|
|
|
expected: []peer{{NumFailures: 0}, {NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}},
|
|
|
|
},
|
|
|
|
"negativeIndex": {
|
|
|
|
data: []peer{{NumFailures: 0}, {NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}},
|
|
|
|
index: -12,
|
|
|
|
expected: []peer{{NumFailures: 0}, {NumFailures: 1}, {NumFailures: 2}, {NumFailures: 3}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, test := range tt {
|
|
|
|
moveToBack(test.data, test.index)
|
|
|
|
expected := make([]string, len(test.expected))
|
|
|
|
actual := make([]string, len(test.data))
|
|
|
|
for i := range actual {
|
|
|
|
actual[i] = strconv.Itoa(test.data[i].NumFailures)
|
|
|
|
expected[i] = strconv.Itoa(test.expected[i].NumFailures)
|
|
|
|
}
|
|
|
|
|
|
|
|
expJoin := strings.Join(expected, ",")
|
|
|
|
actJoin := strings.Join(actual, ",")
|
|
|
|
|
|
|
|
if actJoin != expJoin {
|
|
|
|
t.Errorf("%s failed: got %s; expected %s", name, actJoin, expJoin)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-26 19:42:36 +02:00
|
|
|
func TestRoutingTable_InitialBucketRange(t *testing.T) {
|
2018-06-14 17:48:02 +02:00
|
|
|
id := bits.FromHexP("1c8aff71b99462464d9eeac639595ab99664be3482cb91a29d87467515c7d9158fe72aa1f1582dab07d8f8b5db277f41")
|
2018-05-19 19:05:30 +02:00
|
|
|
ranges := newRoutingTable(id).BucketRanges()
|
2018-06-26 19:42:36 +02:00
|
|
|
bucketRange := ranges[0]
|
|
|
|
if len(ranges) != 1 {
|
|
|
|
t.Error("there should only be one bucket")
|
|
|
|
}
|
|
|
|
if !ranges[0].Start.Equals(bits.FromHexP("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")) {
|
|
|
|
t.Error("bucket does not cover the lower keyspace")
|
2018-05-19 19:05:30 +02:00
|
|
|
}
|
2018-06-26 19:42:36 +02:00
|
|
|
if !ranges[0].End.Equals(bits.FromHexP("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) {
|
|
|
|
t.Error("bucket does not cover the upper keyspace")
|
|
|
|
}
|
|
|
|
found := 0
|
2018-05-19 19:05:30 +02:00
|
|
|
for i := 0; i < 1000; i++ {
|
2018-06-14 17:48:02 +02:00
|
|
|
randID := bits.Rand()
|
2018-06-26 19:42:36 +02:00
|
|
|
if bucketRange.Start.Cmp(randID) <= 0 && bucketRange.End.Cmp(randID) >= 0 {
|
|
|
|
found += 1
|
2018-05-19 19:05:30 +02:00
|
|
|
}
|
|
|
|
}
|
2018-06-26 19:42:36 +02:00
|
|
|
if found != 1000 {
|
|
|
|
t.Errorf("%d did not appear in any bucket", found)
|
|
|
|
}
|
2018-05-19 19:05:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestRoutingTable_Save(t *testing.T) {
|
2018-06-14 17:48:02 +02:00
|
|
|
id := bits.FromHexP("1c8aff71b99462464d9eeac639595ab99664be3482cb91a29d87467515c7d9158fe72aa1f1582dab07d8f8b5db277f41")
|
2018-05-19 19:05:30 +02:00
|
|
|
rt := newRoutingTable(id)
|
|
|
|
|
|
|
|
ranges := rt.BucketRanges()
|
|
|
|
|
|
|
|
for i, r := range ranges {
|
|
|
|
for j := 0; j < bucketSize; j++ {
|
2018-06-19 19:47:13 +02:00
|
|
|
toAdd := r.Start.Add(bits.FromShortHexP(strconv.Itoa(j)))
|
2018-06-25 21:48:57 +02:00
|
|
|
if toAdd.Cmp(r.End) <= 0 {
|
2018-05-19 19:05:30 +02:00
|
|
|
rt.Update(Contact{
|
2018-06-19 19:47:13 +02:00
|
|
|
ID: r.Start.Add(bits.FromShortHexP(strconv.Itoa(j))),
|
2018-05-19 19:05:30 +02:00
|
|
|
IP: net.ParseIP("1.2.3." + strconv.Itoa(j)),
|
|
|
|
Port: 1 + i*bucketSize + j,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := json.MarshalIndent(rt, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
goldie.Assert(t, t.Name(), data)
|
|
|
|
}
|
|
|
|
|
2018-06-19 20:06:35 +02:00
|
|
|
func TestRoutingTable_Load_ID(t *testing.T) {
|
|
|
|
id := "1c8aff71b99462464d9eeac639595ab99664be3482cb91a29d87467515c7d9158fe72aa1f1582dab07d8f8b5db277f41"
|
|
|
|
data := []byte(`{"id": "` + id + `","contacts": []}`)
|
|
|
|
|
|
|
|
rt := routingTable{}
|
|
|
|
err := json.Unmarshal(data, &rt)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
if rt.id.Hex() != id {
|
|
|
|
t.Error("id mismatch")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRoutingTable_Load_Contacts(t *testing.T) {
|
2018-05-19 19:05:30 +02:00
|
|
|
t.Skip("TODO")
|
|
|
|
}
|