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