go-ethereum/swarm/network/pbtree_test.go
zelig 7a6ff56333 p2p: network testing framework and protocol abstraction
subpackages:

* adapters:
  * msgpipes for simulated test connections
  * rlpx the RLPx adapter for normal non-test use
  * inproc simulated in-process network adapter
  * docker placeholder for docker cluster remote adapter
* protocols: easy-to-setup modular protocols
* simulations:
  * generic network model
  * journal, events, snapshots
  * cytoscape visualisation plugin
  * resourceful controller suite + REST API server
  * example: connectivity UX backend
* testing: test resource drivers
  * exchange: trigger/expect style driver for single node and its peers
  * sessions:   for unit testing protocols and protocol modules
  * (network: for network testing, benchmarking, stats, correctness, fault tolerance)
  * test peerpool

see more in the README-s in each subpackage

* p2p/server : conn/disconn hooks
* reporter remote client skeleton
2017-05-06 14:23:38 +01:00

511 lines
13 KiB
Go

package network
import (
"errors"
"fmt"
"math/rand"
"runtime"
"sync"
"testing"
"time"
"github.com/ethereum/go-ethereum/logger/glog"
)
func init() {
glog.SetV(4)
glog.SetToStderr(true)
}
type testAddr struct {
*BinAddr
i int
}
func NewTestAddr(s string, i int) *testAddr {
return &testAddr{NewBinAddr(s), i}
}
func str(v PbVal) string {
if v == nil {
return ""
}
return v.(*testAddr).String()
}
func indexes(t *PbTree) (i []int, pos []int) {
t.Each(func(v PbVal, po int) bool {
a := v.(*testAddr)
i = append(i, a.i)
pos = append(pos, po)
return true
})
return i, pos
}
func add(t *PbTree, n int, values ...string) {
for i, val := range values {
t.Add(NewTestAddr(val, i+n))
}
}
func (self *testAddr) Prefix(val PbVal, pos int) (po int, eq bool) {
return self.BinAddr.Prefix(val.(*testAddr).BinAddr, pos)
}
// func RandomBinAddr()
func TestPbTreeAdd(t *testing.T) {
n := NewPbTree(NewTestAddr("001111", 0), 0)
// Pin set correctly
exp := "001111"
got := str(n.Pin())
if got != exp {
t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got)
}
// check size
goti := n.Size()
expi := 1
if goti != expi {
t.Fatalf("incorrect number of elements in PbTree. Expected %v, got %v", expi, goti)
}
add(n, 1, "011111", "001111", "011111", "000111")
// check size
goti = n.Size()
expi = 3
if goti != expi {
t.Fatalf("incorrect number of elements in PbTree. Expected %v, got %v", expi, goti)
}
inds, pos := indexes(n)
got = fmt.Sprintf("%v", inds)
exp = "[3 4 2]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over PbTree. Expected %v, got %v", exp, got)
}
got = fmt.Sprintf("%v", pos)
exp = "[1 2 0]"
if got != exp {
t.Fatalf("incorrect po-s in iteration over PbTree. Expected %v, got %v", exp, got)
}
}
// func RandomBinAddr()
func TestPbTreeRemove(t *testing.T) {
n := NewPbTree(NewTestAddr("001111", 0), 0)
n.Remove(NewTestAddr("001111", 0))
exp := ""
got := str(n.Pin())
if got != exp {
t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got)
}
add(n, 1, "000000", "011111", "001111", "000111")
n.Remove(NewTestAddr("001111", 0))
goti := n.Size()
expi := 3
if goti != expi {
t.Fatalf("incorrect number of elements in PbTree. Expected %v, got %v", expi, goti)
}
inds, pos := indexes(n)
got = fmt.Sprintf("%v", inds)
exp = "[2 4 1]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over PbTree. Expected %v, got %v", exp, got)
}
got = fmt.Sprintf("%v", pos)
exp = "[1 3 0]"
if got != exp {
t.Fatalf("incorrect po-s in iteration over PbTree. Expected %v, got %v", exp, got)
}
// remove again
n.Remove(NewTestAddr("001111", 0))
inds, pos = indexes(n)
got = fmt.Sprintf("%v", inds)
exp = "[2 4 1]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over PbTree. Expected %v, got %v", exp, got)
}
}
func checkPo(val PbVal) func(PbVal, int) error {
return func(v PbVal, po int) error {
// check the po
exp, _ := val.Prefix(v, 0)
if po != exp {
return fmt.Errorf("incorrect prox order for item %v in neighbour iteration for %v. Expected %v, got %v", v, val, exp, po)
}
return nil
}
}
func checkOrder(val PbVal) func(PbVal, int) error {
var pos int = keylen
return func(v PbVal, po int) error {
if pos < po {
return fmt.Errorf("incorrect order for item %v in neighbour iteration for %v. PO %v > %v (previous max)", v, val, po, pos)
}
pos = po
return nil
}
}
func checkValues(m map[string]bool, val PbVal) func(PbVal, int) error {
return func(v PbVal, po int) error {
duplicate, ok := m[v.String()]
if !ok {
return fmt.Errorf("alien value %v", v)
}
if duplicate {
return fmt.Errorf("duplicate value returned: %v", v)
}
m[v.String()] = true
return nil
}
}
var errNoCount = errors.New("not count")
func testPbTreeEachNeighbour(n *PbTree, val PbVal, expCount int, fs ...func(PbVal, int) error) error {
var err error
var count int
n.EachNeighbour(val, func(v PbVal, po int) bool {
for _, f := range fs {
err = f(v, po)
if err != nil {
return err.Error() == errNoCount.Error()
}
}
count++
if count == expCount {
return false
}
return true
})
if err == nil && count < expCount {
return fmt.Errorf("not enough neighbours returned, expected %v, got %v", expCount, count)
}
return err
}
const (
maxEachNeighbourTests = 500
maxEachNeighbour = 4
keylen = 4
)
func randomTestAddr(n int, i int) *testAddr {
v := RandomAddress().Bin()[:n]
return NewTestAddr(v, i)
}
func TestPbTreeMerge(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ {
max0 := rand.Intn(maxEachNeighbour) + 1
max1 := rand.Intn(maxEachNeighbour) + 1
n0 := NewPbTree(nil, 0)
n1 := NewPbTree(nil, 0)
m := make(map[string]bool)
for j := 0; j < max0; {
v := randomTestAddr(keylen, j)
_, found := n0.Add(v)
if !found {
glog.V(4).Infof("%v: add %v", j, v)
m[v.String()] = false
j++
}
}
expAdded := 0
for j := 0; j < max1; {
v := randomTestAddr(keylen, j)
_, found := n1.Add(v)
glog.V(4).Infof("%v: add %v", j, v)
if !found {
j++
}
_, found = m[v.String()]
if !found {
expAdded++
glog.V(4).Infof("%v: newly added %v", j-1, v)
m[v.String()] = false
}
}
expSize := len(m)
glog.V(4).Infof("%v-0: pin: %v, size: %v", i, n0.Pin(), max0)
glog.V(4).Infof("%v-1: pin: %v, size: %v", i, n1.Pin(), max1)
glog.V(4).Infof("%v: %v", i, expSize)
added := n0.Merge(n1)
size := n0.Size()
if expSize != size {
t.Fatalf("incorrect number of elements in merged pbTree, expected %v, got %v\n%v", expSize, size, n0)
}
if expAdded != added {
t.Fatalf("incorrect number of added elements in merged pbTree, expected %v, got %v", expAdded, added)
}
for k, _ := range m {
_, found := n0.Add(NewTestAddr(k, 0))
if !found {
t.Fatalf("merged pbTree missing element %v", k)
}
}
}
}
func TestPbTreeEachNeighbourSync(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ {
max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2
pin := randomTestAddr(keylen, 0)
n := NewPbTree(pin, 0)
m := make(map[string]bool)
m[pin.String()] = false
for j := 1; j <= max; j++ {
v := randomTestAddr(keylen, j)
n.Add(v)
m[v.String()] = false
}
size := n.Size()
if size < 2 {
continue
}
count := rand.Intn(size/2) + size/2
val := randomTestAddr(keylen, max+1)
glog.V(4).Infof("%v: pin: %v, size: %v, val: %v, count: %v", i, n.Pin(), size, val, count)
err := testPbTreeEachNeighbour(n, val, count, checkPo(val), checkOrder(val), checkValues(m, val))
if err != nil {
t.Fatal(err)
}
minPoFound := keylen
maxPoNotFound := 0
for k, found := range m {
po, _ := val.Prefix(NewTestAddr(k, 0), 0)
if found {
if po < minPoFound {
minPoFound = po
}
} else {
if po > maxPoNotFound {
maxPoNotFound = po
}
}
}
if minPoFound < maxPoNotFound {
t.Fatalf("incorrect neighbours returned: found one with PO %v < there was one not found with PO %v", minPoFound, maxPoNotFound)
}
}
}
func TestPbTreeEachNeighbourAsync(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ {
max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2
n := NewPbTree(randomTestAddr(keylen, 0), 0)
var size int = 1
for j := 1; j <= max; j++ {
v := randomTestAddr(keylen, j)
_, found := n.Add(v)
if !found {
size++
}
}
if size != n.Size() {
t.Fatal(n)
}
if size < 2 {
continue
}
count := rand.Intn(size/2) + size/2
val := randomTestAddr(keylen, max+1)
mu := sync.Mutex{}
m := make(map[string]bool)
maxPos := rand.Intn(keylen)
glog.V(5).Infof("%v: pin: %v, size: %v, val: %v, count: %v, maxPos: %v", i, n.Pin(), size, val, count, maxPos)
msize := 0
remember := func(v PbVal, po int) error {
// mu.Lock()
// defer mu.Unlock()
if po > maxPos {
// glog.V(4).Infof("NOT ADD %v", v)
return errNoCount
}
// glog.V(4).Infof("ADD %v, %v", v, msize)
m[v.String()] = true
msize++
return nil
}
if i == 0 {
continue
}
err := testPbTreeEachNeighbour(n, val, count, remember)
if err != nil {
glog.V(6).Info(err)
}
d := 0
forget := func(v PbVal, po int) {
mu.Lock()
defer mu.Unlock()
d++
// glog.V(4).Infof("DEL %v", v)
delete(m, v.String())
}
n.EachNeighbourAsync(val, count, maxPos, forget, true)
if d != msize {
t.Fatalf("incorrect number of neighbour calls in async iterator. expected %v, got %v", msize, d)
}
if len(m) != 0 {
t.Fatalf("incorrect neighbour calls in async iterator. %v items missed:\n%v", len(m), n)
}
}
}
func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) {
t.ReportAllocs()
pin := randomTestAddr(keylen, 0)
n := NewPbTree(pin, 0)
for j := 1; j <= max; {
v := randomTestAddr(keylen, j)
_, found := n.Add(v)
if !found {
j++
}
}
t.ResetTimer()
for i := 0; i < t.N; i++ {
val := randomTestAddr(keylen, max+1)
m := 0
n.EachNeighbour(val, func(v PbVal, po int) bool {
time.Sleep(d)
m++
if m == count {
return false
}
return true
})
}
t.StopTimer()
stats := new(runtime.MemStats)
runtime.ReadMemStats(stats)
// fmt.Println(stats.Sys)
}
func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration) {
t.ReportAllocs()
pin := randomTestAddr(keylen, 0)
n := NewPbTree(pin, 0)
for j := 1; j <= max; {
v := randomTestAddr(keylen, j)
_, found := n.Add(v)
if !found {
j++
}
}
t.ResetTimer()
for i := 0; i < t.N; i++ {
val := randomTestAddr(keylen, max+1)
n.EachNeighbourAsync(val, count, keylen, func(v PbVal, po int) {
time.Sleep(d)
}, true)
}
t.StopTimer()
stats := new(runtime.MemStats)
runtime.ReadMemStats(stats)
// fmt.Println(stats.Sys)
}
func BenchmarkEachNeighbourSync_3_1_0(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 1*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_0(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 1*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_0(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 1*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_0(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 1*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_0(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 1*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_0(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 1*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_1_1(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 2*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_1(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 2*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_1(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 2*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_1(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 2*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_1(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 2*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_1(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 2*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_1_2(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 4*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_2(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 4*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_2(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 4*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_2(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 4*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_2(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 4*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_2(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 4*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_1_3(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 8*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_3(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 8*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_3(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 8*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_3(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 8*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_3(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 8*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_3(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 8*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_1_4(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 16*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_4(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 16*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_4(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 16*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_4(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 16*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_4(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 16*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_4(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 16*time.Microsecond)
}