github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/kad_table_test.go (about) 1 // This code is adapted from the libp2p project, specifically: 2 // https://github.com/libp2p/go-libp2p-kbucket/table_test.go 3 // we don't need to unify keyspaces between random strings and peer.IDs which ipfs requires. 4 5 package holochain 6 7 import ( 8 . "github.com/holochain/holochain-proto/hash" 9 peer "github.com/libp2p/go-libp2p-peer" 10 pstore "github.com/libp2p/go-libp2p-peerstore" 11 tu "github.com/libp2p/go-testutil" 12 "math/rand" 13 "testing" 14 "time" 15 ) 16 17 // Test basic features of the bucket struct 18 func TestBucket(t *testing.T) { 19 b := newBucket() 20 21 peers := make([]peer.ID, 100) 22 for i := 0; i < 100; i++ { 23 peers[i] = tu.RandPeerIDFatal(t) 24 b.PushFront(peers[i]) 25 } 26 27 localID := tu.RandPeerIDFatal(t) 28 29 i := rand.Intn(len(peers)) 30 if !b.Has(peers[i]) { 31 t.Errorf("Failed to find peer: %v", peers[i]) 32 } 33 34 spl := b.Split(0, localID) 35 llist := b.list 36 for e := llist.Front(); e != nil; e = e.Next() { 37 p := e.Value.(peer.ID) 38 cpl := commonPrefixLen(p, localID) 39 if cpl > 0 { 40 t.Fatalf("Split failed. found id with cpl > 0 in 0 bucket") 41 } 42 } 43 44 rlist := spl.list 45 for e := rlist.Front(); e != nil; e = e.Next() { 46 p := e.Value.(peer.ID) 47 cpl := commonPrefixLen(p, localID) 48 if cpl == 0 { 49 t.Fatalf("Split failed. found id with cpl == 0 in non 0 bucket") 50 } 51 } 52 } 53 54 func TestTableCallbacks(t *testing.T) { 55 local := tu.RandPeerIDFatal(t) 56 m := pstore.NewMetrics() 57 rt := NewRoutingTable(10, local, time.Hour, m) 58 59 peers := make([]peer.ID, 100) 60 for i := 0; i < 100; i++ { 61 peers[i] = tu.RandPeerIDFatal(t) 62 } 63 64 pset := make(map[peer.ID]struct{}) 65 rt.PeerAdded = func(p peer.ID) { 66 pset[p] = struct{}{} 67 } 68 rt.PeerRemoved = func(p peer.ID) { 69 delete(pset, p) 70 } 71 72 rt.Update(peers[0]) 73 if _, ok := pset[peers[0]]; !ok { 74 t.Fatal("should have this peer") 75 } 76 77 rt.Remove(peers[0]) 78 if _, ok := pset[peers[0]]; ok { 79 t.Fatal("should not have this peer") 80 } 81 82 for _, p := range peers { 83 rt.Update(p) 84 } 85 86 out := rt.ListPeers() 87 for _, outp := range out { 88 if _, ok := pset[outp]; !ok { 89 t.Fatal("should have peer in the peerset") 90 } 91 delete(pset, outp) 92 } 93 94 if len(pset) > 0 { 95 t.Fatal("have peers in peerset that were not in the table", len(pset)) 96 } 97 } 98 99 // Right now, this just makes sure that it doesnt hang or crash 100 func TestTableUpdate(t *testing.T) { 101 local := tu.RandPeerIDFatal(t) 102 m := pstore.NewMetrics() 103 rt := NewRoutingTable(10, local, time.Hour, m) 104 105 peers := make([]peer.ID, 100) 106 for i := 0; i < 100; i++ { 107 peers[i] = tu.RandPeerIDFatal(t) 108 } 109 110 // Testing Update 111 for i := 0; i < 10000; i++ { 112 rt.Update(peers[rand.Intn(len(peers))]) 113 } 114 115 for i := 0; i < 100; i++ { 116 id := tu.RandPeerIDFatal(t) 117 ret := rt.NearestPeers(HashFromPeerID(id), 5) 118 if len(ret) == 0 { 119 t.Fatal("Failed to find node near ID.") 120 } 121 } 122 } 123 124 func TestTableFind(t *testing.T) { 125 local := tu.RandPeerIDFatal(t) 126 m := pstore.NewMetrics() 127 rt := NewRoutingTable(10, local, time.Hour, m) 128 129 peers := make([]peer.ID, 100) 130 for i := 0; i < 5; i++ { 131 peers[i] = tu.RandPeerIDFatal(t) 132 rt.Update(peers[i]) 133 } 134 135 t.Logf("Searching for peer: '%s'", peers[2]) 136 found := rt.NearestPeer(HashFromPeerID(peers[2])) 137 if !(found == peers[2]) { 138 t.Fatalf("Failed to lookup known node...") 139 } 140 } 141 142 func TestTableFindMultiple(t *testing.T) { 143 local := tu.RandPeerIDFatal(t) 144 m := pstore.NewMetrics() 145 rt := NewRoutingTable(20, local, time.Hour, m) 146 147 peers := make([]peer.ID, 100) 148 for i := 0; i < 18; i++ { 149 peers[i] = tu.RandPeerIDFatal(t) 150 rt.Update(peers[i]) 151 } 152 153 t.Logf("Searching for peer: '%s'", peers[2]) 154 found := rt.NearestPeers(HashFromPeerID(peers[2]), 15) 155 if len(found) != 15 { 156 t.Fatalf("Got back different number of peers than we expected.") 157 } 158 } 159 160 // Looks for race conditions in table operations. For a more 'certain' 161 // test, increase the loop counter from 1000 to a much higher number 162 // and set GOMAXPROCS above 1 163 func TestTableMultithreaded(t *testing.T) { 164 local, _ := peer.IDB58Decode("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh2") 165 m := pstore.NewMetrics() 166 tab := NewRoutingTable(20, local, time.Hour, m) 167 var peers []peer.ID 168 for i := 0; i < 500; i++ { 169 peers = append(peers, tu.RandPeerIDFatal(t)) 170 } 171 172 count := 1000 173 done := make(chan struct{}) 174 go func() { 175 for i := 0; i < count; i++ { 176 n := rand.Intn(len(peers)) 177 tab.Update(peers[n]) 178 } 179 done <- struct{}{} 180 }() 181 182 go func() { 183 for i := 0; i < count; i++ { 184 n := rand.Intn(len(peers)) 185 tab.Update(peers[n]) 186 } 187 done <- struct{}{} 188 }() 189 190 go func() { 191 for i := 0; i < count; i++ { 192 n := rand.Intn(len(peers)) 193 tab.Find(peers[n]) 194 } 195 done <- struct{}{} 196 }() 197 <-done 198 <-done 199 <-done 200 } 201 202 /* 203 func BenchmarkUpdates(b *testing.B) { 204 b.StopTimer() 205 local := ConvertKey("localKey") 206 m := pstore.NewMetrics() 207 tab := NewRoutingTable(20, local, time.Hour, m) 208 209 var peers []peer.ID 210 for i := 0; i < b.N; i++ { 211 peers = append(peers, tu.RandPeerIDFatal(b)) 212 } 213 214 b.StartTimer() 215 for i := 0; i < b.N; i++ { 216 tab.Update(peers[i]) 217 } 218 } 219 220 func BenchmarkFinds(b *testing.B) { 221 b.StopTimer() 222 local := ConvertKey("localKey") 223 m := pstore.NewMetrics() 224 tab := NewRoutingTable(20, local, time.Hour, m) 225 226 var peers []peer.ID 227 for i := 0; i < b.N; i++ { 228 peers = append(peers, tu.RandPeerIDFatal(b)) 229 tab.Update(peers[i]) 230 } 231 232 b.StartTimer() 233 for i := 0; i < b.N; i++ { 234 tab.Find(peers[i]) 235 } 236 } 237 */