github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/storage/netstore_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:45</date> 10 //</624450121282621440> 11 12 13 package storage 14 15 import ( 16 "bytes" 17 "context" 18 "crypto/rand" 19 "errors" 20 "fmt" 21 "io/ioutil" 22 "sync" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/p2p/enode" 28 ch "github.com/ethereum/go-ethereum/swarm/chunk" 29 ) 30 31 var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") 32 33 type mockNetFetcher struct { 34 peers *sync.Map 35 sources []*enode.ID 36 peersPerRequest [][]Address 37 requestCalled bool 38 offerCalled bool 39 quit <-chan struct{} 40 ctx context.Context 41 hopCounts []uint8 42 mu sync.Mutex 43 } 44 45 func (m *mockNetFetcher) Offer(ctx context.Context, source *enode.ID) { 46 m.offerCalled = true 47 m.sources = append(m.sources, source) 48 } 49 50 func (m *mockNetFetcher) Request(ctx context.Context, hopCount uint8) { 51 m.mu.Lock() 52 defer m.mu.Unlock() 53 54 m.requestCalled = true 55 var peers []Address 56 m.peers.Range(func(key interface{}, _ interface{}) bool { 57 peers = append(peers, common.FromHex(key.(string))) 58 return true 59 }) 60 m.peersPerRequest = append(m.peersPerRequest, peers) 61 m.hopCounts = append(m.hopCounts, hopCount) 62 } 63 64 type mockNetFetchFuncFactory struct { 65 fetcher *mockNetFetcher 66 } 67 68 func (m *mockNetFetchFuncFactory) newMockNetFetcher(ctx context.Context, _ Address, peers *sync.Map) NetFetcher { 69 m.fetcher.peers = peers 70 m.fetcher.quit = ctx.Done() 71 m.fetcher.ctx = ctx 72 return m.fetcher 73 } 74 75 func mustNewNetStore(t *testing.T) *NetStore { 76 netStore, _ := mustNewNetStoreWithFetcher(t) 77 return netStore 78 } 79 80 func mustNewNetStoreWithFetcher(t *testing.T) (*NetStore, *mockNetFetcher) { 81 t.Helper() 82 83 datadir, err := ioutil.TempDir("", "netstore") 84 if err != nil { 85 t.Fatal(err) 86 } 87 naddr := make([]byte, 32) 88 params := NewDefaultLocalStoreParams() 89 params.Init(datadir) 90 params.BaseKey = naddr 91 localStore, err := NewTestLocalStoreForAddr(params) 92 if err != nil { 93 t.Fatal(err) 94 } 95 96 fetcher := &mockNetFetcher{} 97 mockNetFetchFuncFactory := &mockNetFetchFuncFactory{ 98 fetcher: fetcher, 99 } 100 netStore, err := NewNetStore(localStore, mockNetFetchFuncFactory.newMockNetFetcher) 101 if err != nil { 102 t.Fatal(err) 103 } 104 return netStore, fetcher 105 } 106 107 //调用netstore.get的testNetStoreGetAndPut测试将被阻止,直到放入同一块。 108 //放置之后,不应该有活动的获取器,为获取器创建的上下文应该 109 //被取消。 110 func TestNetStoreGetAndPut(t *testing.T) { 111 netStore, fetcher := mustNewNetStoreWithFetcher(t) 112 113 chunk := GenerateRandomChunk(ch.DefaultSize) 114 115 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 116 defer cancel() 117 118 c := make(chan struct{}) //此通道确保Put的Gouroutine不会在GeT之前运行。 119 putErrC := make(chan error) 120 go func() { 121 <-c //等待呼叫 122 time.Sleep(200 * time.Millisecond) //再多一点,这就是所谓的 123 124 //检查netstore是否在get调用中为不可用的块创建了一个获取程序 125 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 126 putErrC <- errors.New("Expected netStore to use a fetcher for the Get call") 127 return 128 } 129 130 err := netStore.Put(ctx, chunk) 131 if err != nil { 132 putErrC <- fmt.Errorf("Expected no err got %v", err) 133 return 134 } 135 136 putErrC <- nil 137 }() 138 139 close(c) 140 recChunk, err := netStore.Get(ctx, chunk.Address()) //在完成上述放置之前,此操作将被阻止。 141 if err != nil { 142 t.Fatalf("Expected no err got %v", err) 143 } 144 145 if err := <-putErrC; err != nil { 146 t.Fatal(err) 147 } 148 //检索到的块应该与我们放置的块相同 149 if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { 150 t.Fatalf("Different chunk received than what was put") 151 } 152 //块已经在本地可用,因此不应该有活动的获取程序等待它。 153 if netStore.fetchers.Len() != 0 { 154 t.Fatal("Expected netStore to remove the fetcher after delivery") 155 } 156 157 //调用get时创建了一个获取程序(而块不可用)。块 158 //是随Put调用一起发送的,因此应立即取消提取程序。 159 select { 160 case <-fetcher.ctx.Done(): 161 default: 162 t.Fatal("Expected fetcher context to be cancelled") 163 } 164 165 } 166 167 //测试netstore和测试调用netstore.put,然后调用netstore.get。 168 //在Put之后,块在本地可用,因此get可以从localstore中检索它, 169 //不需要创建回迁器。 170 func TestNetStoreGetAfterPut(t *testing.T) { 171 netStore, fetcher := mustNewNetStoreWithFetcher(t) 172 173 chunk := GenerateRandomChunk(ch.DefaultSize) 174 175 ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 176 defer cancel() 177 178 //首先我们放置块,这样块将在本地可用 179 err := netStore.Put(ctx, chunk) 180 if err != nil { 181 t.Fatalf("Expected no err got %v", err) 182 } 183 184 //get应该从localstore中检索块,而不创建gether 185 recChunk, err := netStore.Get(ctx, chunk.Address()) 186 if err != nil { 187 t.Fatalf("Expected no err got %v", err) 188 } 189 //检索到的块应该与我们放置的块相同 190 if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { 191 t.Fatalf("Different chunk received than what was put") 192 } 193 //不应为本地可用的块创建提取程序提供或请求 194 if fetcher.offerCalled || fetcher.requestCalled { 195 t.Fatal("NetFetcher.offerCalled or requestCalled not expected to be called") 196 } 197 //不应为本地可用块创建提取程序 198 if netStore.fetchers.Len() != 0 { 199 t.Fatal("Expected netStore to not have fetcher") 200 } 201 202 } 203 204 //testnetstoregettimeout测试对不可用块的get调用并等待超时 205 func TestNetStoreGetTimeout(t *testing.T) { 206 netStore, fetcher := mustNewNetStoreWithFetcher(t) 207 208 chunk := GenerateRandomChunk(ch.DefaultSize) 209 210 ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 211 defer cancel() 212 213 c := make(chan struct{}) //该通道确保Gouroutine不会在GET之前运行 214 fetcherErrC := make(chan error) 215 go func() { 216 <-c //等待呼叫 217 time.Sleep(200 * time.Millisecond) //再多一点,这就是所谓的 218 219 //检查netstore是否在get调用中为不可用的块创建了一个获取程序 220 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 221 fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") 222 return 223 } 224 225 fetcherErrC <- nil 226 }() 227 228 close(c) 229 //我们调用不在本地存储区中的get on这个块。我们一点也不放,所以会有 230 //超时 231 _, err := netStore.Get(ctx, chunk.Address()) 232 233 //检查是否发生超时 234 if err != context.DeadlineExceeded { 235 t.Fatalf("Expected context.DeadLineExceeded err got %v", err) 236 } 237 238 if err := <-fetcherErrC; err != nil { 239 t.Fatal(err) 240 } 241 242 //已创建提取程序,请检查是否已在超时后将其删除。 243 if netStore.fetchers.Len() != 0 { 244 t.Fatal("Expected netStore to remove the fetcher after timeout") 245 } 246 247 //检查超时后是否已取消获取器上下文 248 select { 249 case <-fetcher.ctx.Done(): 250 default: 251 t.Fatal("Expected fetcher context to be cancelled") 252 } 253 } 254 255 //testnetstoregetcancel测试get调用中的不可用块,然后取消上下文并检查 256 //错误 257 func TestNetStoreGetCancel(t *testing.T) { 258 netStore, fetcher := mustNewNetStoreWithFetcher(t) 259 260 chunk := GenerateRandomChunk(ch.DefaultSize) 261 262 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 263 264 c := make(chan struct{}) //此通道确保取消的Gouroutine运行时间不早于get 265 fetcherErrC := make(chan error, 1) 266 go func() { 267 <-c //等待呼叫 268 time.Sleep(200 * time.Millisecond) //再多一点,这就是所谓的 269 //检查netstore是否在get调用中为不可用的块创建了一个获取程序 270 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 271 fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") 272 return 273 } 274 275 fetcherErrC <- nil 276 cancel() 277 }() 278 279 close(c) 280 281 //我们使用一个不可用的块来调用get,因此它将创建一个获取器并等待传递 282 _, err := netStore.Get(ctx, chunk.Address()) 283 284 if err := <-fetcherErrC; err != nil { 285 t.Fatal(err) 286 } 287 288 //取消上下文后,上面的get应返回并返回一个错误 289 if err != context.Canceled { 290 t.Fatalf("Expected context.Canceled err got %v", err) 291 } 292 293 //已创建提取程序,请检查取消后是否已删除该提取程序。 294 if netStore.fetchers.Len() != 0 { 295 t.Fatal("Expected netStore to remove the fetcher after cancel") 296 } 297 298 //检查请求上下文取消后是否已取消提取程序上下文 299 select { 300 case <-fetcher.ctx.Done(): 301 default: 302 t.Fatal("Expected fetcher context to be cancelled") 303 } 304 } 305 306 //testnetstoremultipleegandput测试四个get调用相同的不可用块。块是 307 //我们必须确保所有的get调用都返回,并且它们使用一个gether 308 //用于区块检索 309 func TestNetStoreMultipleGetAndPut(t *testing.T) { 310 netStore, fetcher := mustNewNetStoreWithFetcher(t) 311 312 chunk := GenerateRandomChunk(ch.DefaultSize) 313 314 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 315 defer cancel() 316 317 putErrC := make(chan error) 318 go func() { 319 //睡一觉,以确保在所有的获取之后都调用Put。 320 time.Sleep(500 * time.Millisecond) 321 //检查netstore是否为所有get调用创建了一个提取程序 322 if netStore.fetchers.Len() != 1 { 323 putErrC <- errors.New("Expected netStore to use one fetcher for all Get calls") 324 return 325 } 326 err := netStore.Put(ctx, chunk) 327 if err != nil { 328 putErrC <- fmt.Errorf("Expected no err got %v", err) 329 return 330 } 331 putErrC <- nil 332 }() 333 334 count := 4 335 //对相同的不可用块调用get 4次。呼叫将被阻止,直到上面的Put。 336 errC := make(chan error) 337 for i := 0; i < count; i++ { 338 go func() { 339 recChunk, err := netStore.Get(ctx, chunk.Address()) 340 if err != nil { 341 errC <- fmt.Errorf("Expected no err got %v", err) 342 } 343 if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { 344 errC <- errors.New("Different chunk received than what was put") 345 } 346 errC <- nil 347 }() 348 } 349 350 if err := <-putErrC; err != nil { 351 t.Fatal(err) 352 } 353 354 timeout := time.After(1 * time.Second) 355 356 //get调用应该在put之后返回,因此不需要超时 357 for i := 0; i < count; i++ { 358 select { 359 case err := <-errC: 360 if err != nil { 361 t.Fatal(err) 362 } 363 case <-timeout: 364 t.Fatalf("Timeout waiting for Get calls to return") 365 } 366 } 367 368 //已创建提取程序,请检查取消后是否已删除该提取程序。 369 if netStore.fetchers.Len() != 0 { 370 t.Fatal("Expected netStore to remove the fetcher after delivery") 371 } 372 373 //已创建提取程序,请检查它是否在传递后被删除。 374 select { 375 case <-fetcher.ctx.Done(): 376 default: 377 t.Fatal("Expected fetcher context to be cancelled") 378 } 379 380 } 381 382 //testNetStoreFetchFunctionTimeout测试fetchfunc调用是否存在不可用的块并等待超时 383 func TestNetStoreFetchFuncTimeout(t *testing.T) { 384 netStore, fetcher := mustNewNetStoreWithFetcher(t) 385 386 chunk := GenerateRandomChunk(ch.DefaultSize) 387 388 ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) 389 defer cancel() 390 391 //对不可用的块调用了fetchfunc,因此返回的wait函数不应为nil。 392 wait := netStore.FetchFunc(ctx, chunk.Address()) 393 if wait == nil { 394 t.Fatal("Expected wait function to be not nil") 395 } 396 397 //在fetchfunc调用之后,应该有一个活动的块提取程序 398 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 399 t.Fatalf("Expected netStore to have one fetcher for the requested chunk") 400 } 401 402 //等待函数应该超时,因为我们不使用Put传递块 403 err := wait(ctx) 404 if err != context.DeadlineExceeded { 405 t.Fatalf("Expected context.DeadLineExceeded err got %v", err) 406 } 407 408 //回卷器应该在超时后移除 409 if netStore.fetchers.Len() != 0 { 410 t.Fatal("Expected netStore to remove the fetcher after timeout") 411 } 412 413 //超时后应取消获取器上下文 414 select { 415 case <-fetcher.ctx.Done(): 416 default: 417 t.Fatal("Expected fetcher context to be cancelled") 418 } 419 } 420 421 //testnetstorefetchfuncafterput测试fetchfunc应该为本地可用块返回nil 422 func TestNetStoreFetchFuncAfterPut(t *testing.T) { 423 netStore := mustNewNetStore(t) 424 425 chunk := GenerateRandomChunk(ch.DefaultSize) 426 427 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 428 defer cancel() 429 430 //我们用Put传递创建的块 431 err := netStore.Put(ctx, chunk) 432 if err != nil { 433 t.Fatalf("Expected no err got %v", err) 434 } 435 436 //fetchfunc应该返回nil,因为块在本地可用,所以不需要获取它。 437 wait := netStore.FetchFunc(ctx, chunk.Address()) 438 if wait != nil { 439 t.Fatal("Expected wait to be nil") 440 } 441 442 //根本不应该创建回迁器 443 if netStore.fetchers.Len() != 0 { 444 t.Fatal("Expected netStore to not have fetcher") 445 } 446 } 447 448 //如果在NetFetcher上为不可用的块创建了请求,则测试NetStoreGetCallsRequest测试 449 func TestNetStoreGetCallsRequest(t *testing.T) { 450 netStore, fetcher := mustNewNetStoreWithFetcher(t) 451 452 chunk := GenerateRandomChunk(ch.DefaultSize) 453 454 ctx := context.WithValue(context.Background(), "hopcount", uint8(5)) 455 ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) 456 defer cancel() 457 458 //我们调用get获取一个不可用的块,它将超时,因为该块未被传递 459 _, err := netStore.Get(ctx, chunk.Address()) 460 461 if err != context.DeadlineExceeded { 462 t.Fatalf("Expected context.DeadlineExceeded err got %v", err) 463 } 464 465 //netstore应该调用netfetcher.request并等待数据块 466 if !fetcher.requestCalled { 467 t.Fatal("Expected NetFetcher.Request to be called") 468 } 469 470 if fetcher.hopCounts[0] != 5 { 471 t.Fatalf("Expected NetFetcher.Request be called with hopCount 5, got %v", fetcher.hopCounts[0]) 472 } 473 } 474 475 //如果在NetFetcher上为不可用的块创建了一个请求,则测试netStoreGetCallsOffer测试 476 //在上下文中提供源对等的情况下。 477 func TestNetStoreGetCallsOffer(t *testing.T) { 478 netStore, fetcher := mustNewNetStoreWithFetcher(t) 479 480 chunk := GenerateRandomChunk(ch.DefaultSize) 481 482 //如果将源对等添加到上下文中,NetStore将把它作为一个提供来处理。 483 ctx := context.WithValue(context.Background(), "source", sourcePeerID.String()) 484 ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) 485 defer cancel() 486 487 //我们调用get获取一个不可用的块,它将超时,因为该块未被传递 488 _, err := netStore.Get(ctx, chunk.Address()) 489 490 if err != context.DeadlineExceeded { 491 t.Fatalf("Expect error %v got %v", context.DeadlineExceeded, err) 492 } 493 494 //NetStore应调用NetFetcher。与源对等端一起提供 495 if !fetcher.offerCalled { 496 t.Fatal("Expected NetFetcher.Request to be called") 497 } 498 499 if len(fetcher.sources) != 1 { 500 t.Fatalf("Expected fetcher sources length 1 got %v", len(fetcher.sources)) 501 } 502 503 if fetcher.sources[0].String() != sourcePeerID.String() { 504 t.Fatalf("Expected fetcher source %v got %v", sourcePeerID, fetcher.sources[0]) 505 } 506 507 } 508 509 //testNetStoreFetcherCountPeers测试多个netstore.get调用上下文中的Peer。 510 //没有Put调用,因此get调用超时 511 func TestNetStoreFetcherCountPeers(t *testing.T) { 512 513 netStore, fetcher := mustNewNetStoreWithFetcher(t) 514 515 addr := randomAddr() 516 peers := []string{randomAddr().Hex(), randomAddr().Hex(), randomAddr().Hex()} 517 518 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 519 defer cancel() 520 errC := make(chan error) 521 nrGets := 3 522 523 //使用上下文中的对等方调用get 3次 524 for i := 0; i < nrGets; i++ { 525 peer := peers[i] 526 go func() { 527 ctx := context.WithValue(ctx, "peer", peer) 528 _, err := netStore.Get(ctx, addr) 529 errC <- err 530 }() 531 } 532 533 //所有3个get调用都应超时 534 for i := 0; i < nrGets; i++ { 535 err := <-errC 536 if err != context.DeadlineExceeded { 537 t.Fatalf("Expected \"%v\" error got \"%v\"", context.DeadlineExceeded, err) 538 } 539 } 540 541 //回卷器应在超时后关闭 542 select { 543 case <-fetcher.quit: 544 case <-time.After(3 * time.Second): 545 t.Fatalf("mockNetFetcher not closed after timeout") 546 } 547 548 //在3个GET调用后,应将所有3个对等端都提供给NetFetcher。 549 if len(fetcher.peersPerRequest) != nrGets { 550 t.Fatalf("Expected 3 got %v", len(fetcher.peersPerRequest)) 551 } 552 553 for i, peers := range fetcher.peersPerRequest { 554 if len(peers) < i+1 { 555 t.Fatalf("Expected at least %v got %v", i+1, len(peers)) 556 } 557 } 558 } 559 560 //testnetstorefetchfuncalledmultipleTimes调用fetchfunc给出的等待函数三次, 561 //并且检查一个块是否仍然只有一个取件器。在传送数据块后,它会检查 562 //如果取纸器关闭。 563 func TestNetStoreFetchFuncCalledMultipleTimes(t *testing.T) { 564 netStore, fetcher := mustNewNetStoreWithFetcher(t) 565 566 chunk := GenerateRandomChunk(ch.DefaultSize) 567 568 ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 569 defer cancel() 570 571 //fetchfunc应返回非nil等待函数,因为块不可用 572 wait := netStore.FetchFunc(ctx, chunk.Address()) 573 if wait == nil { 574 t.Fatal("Expected wait function to be not nil") 575 } 576 577 //块应该只有一个取件器 578 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 579 t.Fatalf("Expected netStore to have one fetcher for the requested chunk") 580 } 581 582 //同时呼叫等待三次 583 count := 3 584 errC := make(chan error) 585 for i := 0; i < count; i++ { 586 go func() { 587 errC <- wait(ctx) 588 }() 589 } 590 591 //稍微睡一会儿,以便上面调用wait函数 592 time.Sleep(100 * time.Millisecond) 593 594 //应该仍然只有一个取数器,因为所有的等待调用都是针对同一块的。 595 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 596 t.Fatal("Expected netStore to have one fetcher for the requested chunk") 597 } 598 599 //用Put交付块 600 err := netStore.Put(ctx, chunk) 601 if err != nil { 602 t.Fatalf("Expected no err got %v", err) 603 } 604 605 //等待所有等待调用返回(因为块已传递) 606 for i := 0; i < count; i++ { 607 err := <-errC 608 if err != nil { 609 t.Fatal(err) 610 } 611 } 612 613 //对于已传递的块不应该有更多的获取程序 614 if netStore.fetchers.Len() != 0 { 615 t.Fatal("Expected netStore to remove the fetcher after delivery") 616 } 617 618 //回迁器的上下文应在传递后取消。 619 select { 620 case <-fetcher.ctx.Done(): 621 default: 622 t.Fatal("Expected fetcher context to be cancelled") 623 } 624 } 625 626 //testNetStoreFetcherLifecycleWithTimeout类似于testNetStoreFetchFunccalledMultipleTimes, 627 //唯一的区别是我们不解除块的划分,只需等待超时 628 func TestNetStoreFetcherLifeCycleWithTimeout(t *testing.T) { 629 netStore, fetcher := mustNewNetStoreWithFetcher(t) 630 631 chunk := GenerateRandomChunk(ch.DefaultSize) 632 633 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 634 defer cancel() 635 636 //fetchfunc应返回非nil等待函数,因为块不可用 637 wait := netStore.FetchFunc(ctx, chunk.Address()) 638 if wait == nil { 639 t.Fatal("Expected wait function to be not nil") 640 } 641 642 //块应该只有一个取件器 643 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 644 t.Fatalf("Expected netStore to have one fetcher for the requested chunk") 645 } 646 647 //同时呼叫等待三次 648 count := 3 649 errC := make(chan error) 650 for i := 0; i < count; i++ { 651 go func() { 652 rctx, rcancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 653 defer rcancel() 654 err := wait(rctx) 655 if err != context.DeadlineExceeded { 656 errC <- fmt.Errorf("Expected err %v got %v", context.DeadlineExceeded, err) 657 return 658 } 659 errC <- nil 660 }() 661 } 662 663 //等待直到所有等待调用超时 664 for i := 0; i < count; i++ { 665 err := <-errC 666 if err != nil { 667 t.Fatal(err) 668 } 669 } 670 671 //超时后不应该有更多的获取程序 672 if netStore.fetchers.Len() != 0 { 673 t.Fatal("Expected netStore to remove the fetcher after delivery") 674 } 675 676 //回迁器的上下文应在超时后取消。 677 select { 678 case <-fetcher.ctx.Done(): 679 default: 680 t.Fatal("Expected fetcher context to be cancelled") 681 } 682 } 683 684 func randomAddr() Address { 685 addr := make([]byte, 32) 686 rand.Read(addr) 687 return Address(addr) 688 } 689