github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/p2p/dial_test.go (about) 1 package p2p 2 3 import ( 4 "encoding/binary" 5 "net" 6 "reflect" 7 "testing" 8 "time" 9 10 "github.com/davecgh/go-spew/spew" 11 "github.com/quickchainproject/quickchain/p2p/discover" 12 "github.com/quickchainproject/quickchain/p2p/netutil" 13 ) 14 15 func init() { 16 spew.Config.Indent = "\t" 17 } 18 19 type dialtest struct { 20 init *dialstate // state before and after the test. 21 rounds []round 22 } 23 24 type round struct { 25 peers []*Peer // current peer set 26 done []task // tasks that got done this round 27 new []task // the result must match this one 28 } 29 30 func runDialTest(t *testing.T, test dialtest) { 31 var ( 32 vtime time.Time 33 running int 34 ) 35 pm := func(ps []*Peer) map[discover.NodeID]*Peer { 36 m := make(map[discover.NodeID]*Peer) 37 for _, p := range ps { 38 m[p.rw.id] = p 39 } 40 return m 41 } 42 for i, round := range test.rounds { 43 for _, task := range round.done { 44 running-- 45 if running < 0 { 46 panic("running task counter underflow") 47 } 48 test.init.taskDone(task, vtime) 49 } 50 51 new := test.init.newTasks(running, pm(round.peers), vtime) 52 if !sametasks(new, round.new) { 53 t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n", 54 i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running)) 55 } 56 57 // Time advances by 16 seconds on every round. 58 vtime = vtime.Add(16 * time.Second) 59 running += len(new) 60 } 61 } 62 63 type fakeTable []*discover.Node 64 65 func (t fakeTable) Self() *discover.Node { return new(discover.Node) } 66 func (t fakeTable) Close() {} 67 func (t fakeTable) Lookup(discover.NodeID) []*discover.Node { return nil } 68 func (t fakeTable) Resolve(discover.NodeID) *discover.Node { return nil } 69 func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) } 70 71 // This test checks that dynamic dials are launched from discovery results. 72 func TestDialStateDynDial(t *testing.T) { 73 runDialTest(t, dialtest{ 74 init: newDialState(nil, nil, fakeTable{}, 5, nil), 75 rounds: []round{ 76 // A discovery query is launched. 77 { 78 peers: []*Peer{ 79 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 80 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 81 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 82 }, 83 new: []task{&discoverTask{}}, 84 }, 85 // Dynamic dials are launched when it completes. 86 { 87 peers: []*Peer{ 88 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 89 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 90 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 91 }, 92 done: []task{ 93 &discoverTask{results: []*discover.Node{ 94 {ID: uintID(2)}, // this one is already connected and not dialed. 95 {ID: uintID(3)}, 96 {ID: uintID(4)}, 97 {ID: uintID(5)}, 98 {ID: uintID(6)}, // these are not tried because max dyn dials is 5 99 {ID: uintID(7)}, // ... 100 }}, 101 }, 102 new: []task{ 103 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 104 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 105 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 106 }, 107 }, 108 // Some of the dials complete but no new ones are launched yet because 109 // the sum of active dial count and dynamic peer count is == maxDynDials. 110 { 111 peers: []*Peer{ 112 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 113 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 114 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 115 {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, 116 {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, 117 }, 118 done: []task{ 119 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 120 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 121 }, 122 }, 123 // No new dial tasks are launched in the this round because 124 // maxDynDials has been reached. 125 { 126 peers: []*Peer{ 127 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 128 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 129 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 130 {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, 131 {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, 132 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 133 }, 134 done: []task{ 135 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 136 }, 137 new: []task{ 138 &waitExpireTask{Duration: 14 * time.Second}, 139 }, 140 }, 141 // In this round, the peer with id 2 drops off. The query 142 // results from last discovery lookup are reused. 143 { 144 peers: []*Peer{ 145 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 146 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 147 {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, 148 {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, 149 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 150 }, 151 new: []task{ 152 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}}, 153 }, 154 }, 155 // More peers (3,4) drop off and dial for ID 6 completes. 156 // The last query result from the discovery lookup is reused 157 // and a new one is spawned because more candidates are needed. 158 { 159 peers: []*Peer{ 160 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 161 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 162 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 163 }, 164 done: []task{ 165 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}}, 166 }, 167 new: []task{ 168 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}}, 169 &discoverTask{}, 170 }, 171 }, 172 // Peer 7 is connected, but there still aren't enough dynamic peers 173 // (4 out of 5). However, a discovery is already running, so ensure 174 // no new is started. 175 { 176 peers: []*Peer{ 177 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 178 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 179 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 180 {rw: &conn{flags: dynDialedConn, id: uintID(7)}}, 181 }, 182 done: []task{ 183 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}}, 184 }, 185 }, 186 // Finish the running node discovery with an empty set. A new lookup 187 // should be immediately requested. 188 { 189 peers: []*Peer{ 190 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 191 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 192 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 193 {rw: &conn{flags: dynDialedConn, id: uintID(7)}}, 194 }, 195 done: []task{ 196 &discoverTask{}, 197 }, 198 new: []task{ 199 &discoverTask{}, 200 }, 201 }, 202 }, 203 }) 204 } 205 206 // Tests that bootnodes are dialed if no peers are connectd, but not otherwise. 207 func TestDialStateDynDialBootnode(t *testing.T) { 208 bootnodes := []*discover.Node{ 209 {ID: uintID(1)}, 210 {ID: uintID(2)}, 211 {ID: uintID(3)}, 212 } 213 table := fakeTable{ 214 {ID: uintID(4)}, 215 {ID: uintID(5)}, 216 {ID: uintID(6)}, 217 {ID: uintID(7)}, 218 {ID: uintID(8)}, 219 } 220 runDialTest(t, dialtest{ 221 init: newDialState(nil, bootnodes, table, 5, nil), 222 rounds: []round{ 223 // 2 dynamic dials attempted, bootnodes pending fallback interval 224 { 225 new: []task{ 226 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 227 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 228 &discoverTask{}, 229 }, 230 }, 231 // No dials succeed, bootnodes still pending fallback interval 232 { 233 done: []task{ 234 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 235 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 236 }, 237 }, 238 // No dials succeed, bootnodes still pending fallback interval 239 {}, 240 // No dials succeed, 2 dynamic dials attempted and 1 bootnode too as fallback interval was reached 241 { 242 new: []task{ 243 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, 244 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 245 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 246 }, 247 }, 248 // No dials succeed, 2nd bootnode is attempted 249 { 250 done: []task{ 251 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, 252 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 253 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 254 }, 255 new: []task{ 256 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, 257 }, 258 }, 259 // No dials succeed, 3rd bootnode is attempted 260 { 261 done: []task{ 262 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, 263 }, 264 new: []task{ 265 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 266 }, 267 }, 268 // No dials succeed, 1st bootnode is attempted again, expired random nodes retried 269 { 270 done: []task{ 271 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 272 }, 273 new: []task{ 274 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, 275 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 276 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 277 }, 278 }, 279 // Random dial succeeds, no more bootnodes are attempted 280 { 281 peers: []*Peer{ 282 {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, 283 }, 284 done: []task{ 285 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, 286 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 287 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 288 }, 289 }, 290 }, 291 }) 292 } 293 294 func TestDialStateDynDialFromTable(t *testing.T) { 295 // This table always returns the same random nodes 296 // in the order given below. 297 table := fakeTable{ 298 {ID: uintID(1)}, 299 {ID: uintID(2)}, 300 {ID: uintID(3)}, 301 {ID: uintID(4)}, 302 {ID: uintID(5)}, 303 {ID: uintID(6)}, 304 {ID: uintID(7)}, 305 {ID: uintID(8)}, 306 } 307 308 runDialTest(t, dialtest{ 309 init: newDialState(nil, nil, table, 10, nil), 310 rounds: []round{ 311 // 5 out of 8 of the nodes returned by ReadRandomNodes are dialed. 312 { 313 new: []task{ 314 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, 315 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, 316 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 317 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 318 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 319 &discoverTask{}, 320 }, 321 }, 322 // Dialing nodes 1,2 succeeds. Dials from the lookup are launched. 323 { 324 peers: []*Peer{ 325 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 326 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 327 }, 328 done: []task{ 329 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, 330 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, 331 &discoverTask{results: []*discover.Node{ 332 {ID: uintID(10)}, 333 {ID: uintID(11)}, 334 {ID: uintID(12)}, 335 }}, 336 }, 337 new: []task{ 338 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}}, 339 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}}, 340 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}}, 341 &discoverTask{}, 342 }, 343 }, 344 // Dialing nodes 3,4,5 fails. The dials from the lookup succeed. 345 { 346 peers: []*Peer{ 347 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 348 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 349 {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, 350 {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, 351 {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, 352 }, 353 done: []task{ 354 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 355 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 356 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 357 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}}, 358 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}}, 359 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}}, 360 }, 361 }, 362 // Waiting for expiry. No waitExpireTask is launched because the 363 // discovery query is still running. 364 { 365 peers: []*Peer{ 366 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 367 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 368 {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, 369 {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, 370 {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, 371 }, 372 }, 373 // Nodes 3,4 are not tried again because only the first two 374 // returned random nodes (nodes 1,2) are tried and they're 375 // already connected. 376 { 377 peers: []*Peer{ 378 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 379 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 380 {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, 381 {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, 382 {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, 383 }, 384 }, 385 }, 386 }) 387 } 388 389 // This test checks that candidates that do not match the netrestrict list are not dialed. 390 func TestDialStateNetRestrict(t *testing.T) { 391 // This table always returns the same random nodes 392 // in the order given below. 393 table := fakeTable{ 394 {ID: uintID(1), IP: net.ParseIP("127.0.0.1")}, 395 {ID: uintID(2), IP: net.ParseIP("127.0.0.2")}, 396 {ID: uintID(3), IP: net.ParseIP("127.0.0.3")}, 397 {ID: uintID(4), IP: net.ParseIP("127.0.0.4")}, 398 {ID: uintID(5), IP: net.ParseIP("127.0.2.5")}, 399 {ID: uintID(6), IP: net.ParseIP("127.0.2.6")}, 400 {ID: uintID(7), IP: net.ParseIP("127.0.2.7")}, 401 {ID: uintID(8), IP: net.ParseIP("127.0.2.8")}, 402 } 403 restrict := new(netutil.Netlist) 404 restrict.Add("127.0.2.0/24") 405 406 runDialTest(t, dialtest{ 407 init: newDialState(nil, nil, table, 10, restrict), 408 rounds: []round{ 409 { 410 new: []task{ 411 &dialTask{flags: dynDialedConn, dest: table[4]}, 412 &discoverTask{}, 413 }, 414 }, 415 }, 416 }) 417 } 418 419 // This test checks that static dials are launched. 420 func TestDialStateStaticDial(t *testing.T) { 421 wantStatic := []*discover.Node{ 422 {ID: uintID(1)}, 423 {ID: uintID(2)}, 424 {ID: uintID(3)}, 425 {ID: uintID(4)}, 426 {ID: uintID(5)}, 427 } 428 429 runDialTest(t, dialtest{ 430 init: newDialState(wantStatic, nil, fakeTable{}, 0, nil), 431 rounds: []round{ 432 // Static dials are launched for the nodes that 433 // aren't yet connected. 434 { 435 peers: []*Peer{ 436 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 437 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 438 }, 439 new: []task{ 440 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 441 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, 442 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}}, 443 }, 444 }, 445 // No new tasks are launched in this round because all static 446 // nodes are either connected or still being dialed. 447 { 448 peers: []*Peer{ 449 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 450 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 451 {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, 452 }, 453 done: []task{ 454 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 455 }, 456 }, 457 // No new dial tasks are launched because all static 458 // nodes are now connected. 459 { 460 peers: []*Peer{ 461 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 462 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 463 {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, 464 {rw: &conn{flags: staticDialedConn, id: uintID(4)}}, 465 {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, 466 }, 467 done: []task{ 468 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, 469 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}}, 470 }, 471 new: []task{ 472 &waitExpireTask{Duration: 14 * time.Second}, 473 }, 474 }, 475 // Wait a round for dial history to expire, no new tasks should spawn. 476 { 477 peers: []*Peer{ 478 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 479 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 480 {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, 481 {rw: &conn{flags: staticDialedConn, id: uintID(4)}}, 482 {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, 483 }, 484 }, 485 // If a static node is dropped, it should be immediately redialed, 486 // irrespective whether it was originally static or dynamic. 487 { 488 peers: []*Peer{ 489 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 490 {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, 491 {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, 492 }, 493 new: []task{ 494 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, 495 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, 496 }, 497 }, 498 }, 499 }) 500 } 501 502 // This test checks that static peers will be redialed immediately if they were re-added to a static list. 503 func TestDialStaticAfterReset(t *testing.T) { 504 wantStatic := []*discover.Node{ 505 {ID: uintID(1)}, 506 {ID: uintID(2)}, 507 } 508 509 rounds := []round{ 510 // Static dials are launched for the nodes that aren't yet connected. 511 { 512 peers: nil, 513 new: []task{ 514 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}}, 515 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, 516 }, 517 }, 518 // No new dial tasks, all peers are connected. 519 { 520 peers: []*Peer{ 521 {rw: &conn{flags: staticDialedConn, id: uintID(1)}}, 522 {rw: &conn{flags: staticDialedConn, id: uintID(2)}}, 523 }, 524 done: []task{ 525 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}}, 526 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, 527 }, 528 new: []task{ 529 &waitExpireTask{Duration: 30 * time.Second}, 530 }, 531 }, 532 } 533 dTest := dialtest{ 534 init: newDialState(wantStatic, nil, fakeTable{}, 0, nil), 535 rounds: rounds, 536 } 537 runDialTest(t, dTest) 538 for _, n := range wantStatic { 539 dTest.init.removeStatic(n) 540 dTest.init.addStatic(n) 541 } 542 // without removing peers they will be considered recently dialed 543 runDialTest(t, dTest) 544 } 545 546 // This test checks that past dials are not retried for some time. 547 func TestDialStateCache(t *testing.T) { 548 wantStatic := []*discover.Node{ 549 {ID: uintID(1)}, 550 {ID: uintID(2)}, 551 {ID: uintID(3)}, 552 } 553 554 runDialTest(t, dialtest{ 555 init: newDialState(wantStatic, nil, fakeTable{}, 0, nil), 556 rounds: []round{ 557 // Static dials are launched for the nodes that 558 // aren't yet connected. 559 { 560 peers: nil, 561 new: []task{ 562 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}}, 563 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, 564 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 565 }, 566 }, 567 // No new tasks are launched in this round because all static 568 // nodes are either connected or still being dialed. 569 { 570 peers: []*Peer{ 571 {rw: &conn{flags: staticDialedConn, id: uintID(1)}}, 572 {rw: &conn{flags: staticDialedConn, id: uintID(2)}}, 573 }, 574 done: []task{ 575 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}}, 576 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, 577 }, 578 }, 579 // A salvage task is launched to wait for node 3's history 580 // entry to expire. 581 { 582 peers: []*Peer{ 583 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 584 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 585 }, 586 done: []task{ 587 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 588 }, 589 new: []task{ 590 &waitExpireTask{Duration: 14 * time.Second}, 591 }, 592 }, 593 // Still waiting for node 3's entry to expire in the cache. 594 { 595 peers: []*Peer{ 596 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 597 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 598 }, 599 }, 600 // The cache entry for node 3 has expired and is retried. 601 { 602 peers: []*Peer{ 603 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 604 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 605 }, 606 new: []task{ 607 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 608 }, 609 }, 610 }, 611 }) 612 } 613 614 func TestDialResolve(t *testing.T) { 615 resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444) 616 table := &resolveMock{answer: resolved} 617 state := newDialState(nil, nil, table, 0, nil) 618 619 // Check that the task is generated with an incomplete ID. 620 dest := discover.NewNode(uintID(1), nil, 0, 0) 621 state.addStatic(dest) 622 tasks := state.newTasks(0, nil, time.Time{}) 623 if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) { 624 t.Fatalf("expected dial task, got %#v", tasks) 625 } 626 627 // Now run the task, it should resolve the ID once. 628 config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}} 629 srv := &Server{ntab: table, Config: config} 630 tasks[0].Do(srv) 631 if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) { 632 t.Fatalf("wrong resolve calls, got %v", table.resolveCalls) 633 } 634 635 // Report it as done to the dialer, which should update the static node record. 636 state.taskDone(tasks[0], time.Now()) 637 if state.static[uintID(1)].dest != resolved { 638 t.Fatalf("state.dest not updated") 639 } 640 } 641 642 // compares task lists but doesn't care about the order. 643 func sametasks(a, b []task) bool { 644 if len(a) != len(b) { 645 return false 646 } 647 next: 648 for _, ta := range a { 649 for _, tb := range b { 650 if reflect.DeepEqual(ta, tb) { 651 continue next 652 } 653 } 654 return false 655 } 656 return true 657 } 658 659 func uintID(i uint32) discover.NodeID { 660 var id discover.NodeID 661 binary.BigEndian.PutUint32(id[:], i) 662 return id 663 } 664 665 // implements discoverTable for TestDialResolve 666 type resolveMock struct { 667 resolveCalls []discover.NodeID 668 answer *discover.Node 669 } 670 671 func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node { 672 t.resolveCalls = append(t.resolveCalls, id) 673 return t.answer 674 } 675 676 func (t *resolveMock) Self() *discover.Node { return new(discover.Node) } 677 func (t *resolveMock) Close() {} 678 func (t *resolveMock) Bootstrap([]*discover.Node) {} 679 func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node { return nil } 680 func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 }