github.com/alexdevranger/node-1.8.27@v0.0.0-20221128213301-aa5841e41d2d/swarm/storage/netstore_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-dubxcoin library. 3 // 4 // The go-dubxcoin 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-dubxcoin 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-dubxcoin library. If not, see <http://www.gnu.org/licenses/>. 16 17 package storage 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/rand" 23 "errors" 24 "fmt" 25 "io/ioutil" 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/alexdevranger/node-1.8.27/common" 31 "github.com/alexdevranger/node-1.8.27/p2p/enode" 32 ch "github.com/alexdevranger/node-1.8.27/swarm/chunk" 33 ) 34 35 var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") 36 37 type mockNetFetcher struct { 38 peers *sync.Map 39 sources []*enode.ID 40 peersPerRequest [][]Address 41 requestCalled bool 42 offerCalled bool 43 quit <-chan struct{} 44 ctx context.Context 45 hopCounts []uint8 46 mu sync.Mutex 47 } 48 49 func (m *mockNetFetcher) Offer(source *enode.ID) { 50 m.offerCalled = true 51 m.sources = append(m.sources, source) 52 } 53 54 func (m *mockNetFetcher) Request(hopCount uint8) { 55 m.mu.Lock() 56 defer m.mu.Unlock() 57 58 m.requestCalled = true 59 var peers []Address 60 m.peers.Range(func(key interface{}, _ interface{}) bool { 61 peers = append(peers, common.FromHex(key.(string))) 62 return true 63 }) 64 m.peersPerRequest = append(m.peersPerRequest, peers) 65 m.hopCounts = append(m.hopCounts, hopCount) 66 } 67 68 type mockNetFetchFuncFactory struct { 69 fetcher *mockNetFetcher 70 } 71 72 func (m *mockNetFetchFuncFactory) newMockNetFetcher(ctx context.Context, _ Address, peers *sync.Map) NetFetcher { 73 m.fetcher.peers = peers 74 m.fetcher.quit = ctx.Done() 75 m.fetcher.ctx = ctx 76 return m.fetcher 77 } 78 79 func mustNewNetStore(t *testing.T) *NetStore { 80 netStore, _ := mustNewNetStoreWithFetcher(t) 81 return netStore 82 } 83 84 func mustNewNetStoreWithFetcher(t *testing.T) (*NetStore, *mockNetFetcher) { 85 t.Helper() 86 87 datadir, err := ioutil.TempDir("", "netstore") 88 if err != nil { 89 t.Fatal(err) 90 } 91 naddr := make([]byte, 32) 92 params := NewDefaultLocalStoreParams() 93 params.Init(datadir) 94 params.BaseKey = naddr 95 localStore, err := NewTestLocalStoreForAddr(params) 96 if err != nil { 97 t.Fatal(err) 98 } 99 100 fetcher := &mockNetFetcher{} 101 mockNetFetchFuncFactory := &mockNetFetchFuncFactory{ 102 fetcher: fetcher, 103 } 104 netStore, err := NewNetStore(localStore, mockNetFetchFuncFactory.newMockNetFetcher) 105 if err != nil { 106 t.Fatal(err) 107 } 108 return netStore, fetcher 109 } 110 111 // TestNetStoreGetAndPut tests calling NetStore.Get which is blocked until the same chunk is Put. 112 // After the Put there should no active fetchers, and the context created for the fetcher should 113 // be cancelled. 114 func TestNetStoreGetAndPut(t *testing.T) { 115 netStore, fetcher := mustNewNetStoreWithFetcher(t) 116 117 chunk := GenerateRandomChunk(ch.DefaultSize) 118 119 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 120 defer cancel() 121 122 c := make(chan struct{}) // this channel ensures that the gouroutine with the Put does not run earlier than the Get 123 putErrC := make(chan error) 124 go func() { 125 <-c // wait for the Get to be called 126 time.Sleep(200 * time.Millisecond) // and a little more so it is surely called 127 128 // check if netStore created a fetcher in the Get call for the unavailable chunk 129 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 130 putErrC <- errors.New("Expected netStore to use a fetcher for the Get call") 131 return 132 } 133 134 err := netStore.Put(ctx, chunk) 135 if err != nil { 136 putErrC <- fmt.Errorf("Expected no err got %v", err) 137 return 138 } 139 140 putErrC <- nil 141 }() 142 143 close(c) 144 recChunk, err := netStore.Get(ctx, chunk.Address()) // this is blocked until the Put above is done 145 if err != nil { 146 t.Fatalf("Expected no err got %v", err) 147 } 148 149 if err := <-putErrC; err != nil { 150 t.Fatal(err) 151 } 152 // the retrieved chunk should be the same as what we Put 153 if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { 154 t.Fatalf("Different chunk received than what was put") 155 } 156 // the chunk is already available locally, so there should be no active fetchers waiting for it 157 if netStore.fetchers.Len() != 0 { 158 t.Fatal("Expected netStore to remove the fetcher after delivery") 159 } 160 161 // A fetcher was created when the Get was called (and the chunk was not available). The chunk 162 // was delivered with the Put call, so the fetcher should be cancelled now. 163 select { 164 case <-fetcher.ctx.Done(): 165 default: 166 t.Fatal("Expected fetcher context to be cancelled") 167 } 168 169 } 170 171 // TestNetStoreGetAndPut tests calling NetStore.Put and then NetStore.Get. 172 // After the Put the chunk is available locally, so the Get can just retrieve it from LocalStore, 173 // there is no need to create fetchers. 174 func TestNetStoreGetAfterPut(t *testing.T) { 175 netStore, fetcher := mustNewNetStoreWithFetcher(t) 176 177 chunk := GenerateRandomChunk(ch.DefaultSize) 178 179 ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 180 defer cancel() 181 182 // First we Put the chunk, so the chunk will be available locally 183 err := netStore.Put(ctx, chunk) 184 if err != nil { 185 t.Fatalf("Expected no err got %v", err) 186 } 187 188 // Get should retrieve the chunk from LocalStore, without creating fetcher 189 recChunk, err := netStore.Get(ctx, chunk.Address()) 190 if err != nil { 191 t.Fatalf("Expected no err got %v", err) 192 } 193 // the retrieved chunk should be the same as what we Put 194 if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { 195 t.Fatalf("Different chunk received than what was put") 196 } 197 // no fetcher offer or request should be created for a locally available chunk 198 if fetcher.offerCalled || fetcher.requestCalled { 199 t.Fatal("NetFetcher.offerCalled or requestCalled not expected to be called") 200 } 201 // no fetchers should be created for a locally available chunk 202 if netStore.fetchers.Len() != 0 { 203 t.Fatal("Expected netStore to not have fetcher") 204 } 205 206 } 207 208 // TestNetStoreGetTimeout tests a Get call for an unavailable chunk and waits for timeout 209 func TestNetStoreGetTimeout(t *testing.T) { 210 netStore, fetcher := mustNewNetStoreWithFetcher(t) 211 212 chunk := GenerateRandomChunk(ch.DefaultSize) 213 214 ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 215 defer cancel() 216 217 c := make(chan struct{}) // this channel ensures that the gouroutine does not run earlier than the Get 218 fetcherErrC := make(chan error) 219 go func() { 220 <-c // wait for the Get to be called 221 time.Sleep(200 * time.Millisecond) // and a little more so it is surely called 222 223 // check if netStore created a fetcher in the Get call for the unavailable chunk 224 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 225 fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") 226 return 227 } 228 229 fetcherErrC <- nil 230 }() 231 232 close(c) 233 // We call Get on this chunk, which is not in LocalStore. We don't Put it at all, so there will 234 // be a timeout 235 _, err := netStore.Get(ctx, chunk.Address()) 236 237 // Check if the timeout happened 238 if err != context.DeadlineExceeded { 239 t.Fatalf("Expected context.DeadLineExceeded err got %v", err) 240 } 241 242 if err := <-fetcherErrC; err != nil { 243 t.Fatal(err) 244 } 245 246 // A fetcher was created, check if it has been removed after timeout 247 if netStore.fetchers.Len() != 0 { 248 t.Fatal("Expected netStore to remove the fetcher after timeout") 249 } 250 251 // Check if the fetcher context has been cancelled after the timeout 252 select { 253 case <-fetcher.ctx.Done(): 254 default: 255 t.Fatal("Expected fetcher context to be cancelled") 256 } 257 } 258 259 // TestNetStoreGetCancel tests a Get call for an unavailable chunk, then cancels the context and checks 260 // the errors 261 func TestNetStoreGetCancel(t *testing.T) { 262 netStore, fetcher := mustNewNetStoreWithFetcher(t) 263 264 chunk := GenerateRandomChunk(ch.DefaultSize) 265 266 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 267 268 c := make(chan struct{}) // this channel ensures that the gouroutine with the cancel does not run earlier than the Get 269 fetcherErrC := make(chan error, 1) 270 go func() { 271 <-c // wait for the Get to be called 272 time.Sleep(200 * time.Millisecond) // and a little more so it is surely called 273 // check if netStore created a fetcher in the Get call for the unavailable chunk 274 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 275 fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") 276 return 277 } 278 279 fetcherErrC <- nil 280 cancel() 281 }() 282 283 close(c) 284 285 // We call Get with an unavailable chunk, so it will create a fetcher and wait for delivery 286 _, err := netStore.Get(ctx, chunk.Address()) 287 288 if err := <-fetcherErrC; err != nil { 289 t.Fatal(err) 290 } 291 292 // After the context is cancelled above Get should return with an error 293 if err != context.Canceled { 294 t.Fatalf("Expected context.Canceled err got %v", err) 295 } 296 297 // A fetcher was created, check if it has been removed after cancel 298 if netStore.fetchers.Len() != 0 { 299 t.Fatal("Expected netStore to remove the fetcher after cancel") 300 } 301 302 // Check if the fetcher context has been cancelled after the request context cancel 303 select { 304 case <-fetcher.ctx.Done(): 305 default: 306 t.Fatal("Expected fetcher context to be cancelled") 307 } 308 } 309 310 // TestNetStoreMultipleGetAndPut tests four Get calls for the same unavailable chunk. The chunk is 311 // delivered with a Put, we have to make sure all Get calls return, and they use a single fetcher 312 // for the chunk retrieval 313 func TestNetStoreMultipleGetAndPut(t *testing.T) { 314 netStore, fetcher := mustNewNetStoreWithFetcher(t) 315 316 chunk := GenerateRandomChunk(ch.DefaultSize) 317 318 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 319 defer cancel() 320 321 putErrC := make(chan error) 322 go func() { 323 // sleep to make sure Put is called after all the Get 324 time.Sleep(500 * time.Millisecond) 325 // check if netStore created exactly one fetcher for all Get calls 326 if netStore.fetchers.Len() != 1 { 327 putErrC <- errors.New("Expected netStore to use one fetcher for all Get calls") 328 return 329 } 330 err := netStore.Put(ctx, chunk) 331 if err != nil { 332 putErrC <- fmt.Errorf("Expected no err got %v", err) 333 return 334 } 335 putErrC <- nil 336 }() 337 338 count := 4 339 // call Get 4 times for the same unavailable chunk. The calls will be blocked until the Put above. 340 errC := make(chan error) 341 for i := 0; i < count; i++ { 342 go func() { 343 recChunk, err := netStore.Get(ctx, chunk.Address()) 344 if err != nil { 345 errC <- fmt.Errorf("Expected no err got %v", err) 346 } 347 if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { 348 errC <- errors.New("Different chunk received than what was put") 349 } 350 errC <- nil 351 }() 352 } 353 354 if err := <-putErrC; err != nil { 355 t.Fatal(err) 356 } 357 358 timeout := time.After(1 * time.Second) 359 360 // The Get calls should return after Put, so no timeout expected 361 for i := 0; i < count; i++ { 362 select { 363 case err := <-errC: 364 if err != nil { 365 t.Fatal(err) 366 } 367 case <-timeout: 368 t.Fatalf("Timeout waiting for Get calls to return") 369 } 370 } 371 372 // A fetcher was created, check if it has been removed after cancel 373 if netStore.fetchers.Len() != 0 { 374 t.Fatal("Expected netStore to remove the fetcher after delivery") 375 } 376 377 // A fetcher was created, check if it has been removed after delivery 378 select { 379 case <-fetcher.ctx.Done(): 380 default: 381 t.Fatal("Expected fetcher context to be cancelled") 382 } 383 384 } 385 386 // TestNetStoreFetchFuncTimeout tests a FetchFunc call for an unavailable chunk and waits for timeout 387 func TestNetStoreFetchFuncTimeout(t *testing.T) { 388 netStore, fetcher := mustNewNetStoreWithFetcher(t) 389 390 chunk := GenerateRandomChunk(ch.DefaultSize) 391 392 ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) 393 defer cancel() 394 395 // FetchFunc is called for an unavaible chunk, so the returned wait function should not be nil 396 wait := netStore.FetchFunc(ctx, chunk.Address()) 397 if wait == nil { 398 t.Fatal("Expected wait function to be not nil") 399 } 400 401 // There should an active fetcher for the chunk after the FetchFunc call 402 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 403 t.Fatalf("Expected netStore to have one fetcher for the requested chunk") 404 } 405 406 // wait function should timeout because we don't deliver the chunk with a Put 407 err := wait(ctx) 408 if err != context.DeadlineExceeded { 409 t.Fatalf("Expected context.DeadLineExceeded err got %v", err) 410 } 411 412 // the fetcher should be removed after timeout 413 if netStore.fetchers.Len() != 0 { 414 t.Fatal("Expected netStore to remove the fetcher after timeout") 415 } 416 417 // the fetcher context should be cancelled after timeout 418 select { 419 case <-fetcher.ctx.Done(): 420 default: 421 t.Fatal("Expected fetcher context to be cancelled") 422 } 423 } 424 425 // TestNetStoreFetchFuncAfterPut tests that the FetchFunc should return nil for a locally available chunk 426 func TestNetStoreFetchFuncAfterPut(t *testing.T) { 427 netStore := mustNewNetStore(t) 428 429 chunk := GenerateRandomChunk(ch.DefaultSize) 430 431 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 432 defer cancel() 433 434 // We deliver the created the chunk with a Put 435 err := netStore.Put(ctx, chunk) 436 if err != nil { 437 t.Fatalf("Expected no err got %v", err) 438 } 439 440 // FetchFunc should return nil, because the chunk is available locally, no need to fetch it 441 wait := netStore.FetchFunc(ctx, chunk.Address()) 442 if wait != nil { 443 t.Fatal("Expected wait to be nil") 444 } 445 446 // No fetchers should be created at all 447 if netStore.fetchers.Len() != 0 { 448 t.Fatal("Expected netStore to not have fetcher") 449 } 450 } 451 452 // TestNetStoreGetCallsRequest tests if Get created a request on the NetFetcher for an unavailable chunk 453 func TestNetStoreGetCallsRequest(t *testing.T) { 454 netStore, fetcher := mustNewNetStoreWithFetcher(t) 455 456 chunk := GenerateRandomChunk(ch.DefaultSize) 457 458 ctx := context.WithValue(context.Background(), "hopcount", uint8(5)) 459 ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) 460 defer cancel() 461 462 // We call get for a not available chunk, it will timeout because the chunk is not delivered 463 _, err := netStore.Get(ctx, chunk.Address()) 464 465 if err != context.DeadlineExceeded { 466 t.Fatalf("Expected context.DeadlineExceeded err got %v", err) 467 } 468 469 // NetStore should call NetFetcher.Request and wait for the chunk 470 if !fetcher.requestCalled { 471 t.Fatal("Expected NetFetcher.Request to be called") 472 } 473 474 if fetcher.hopCounts[0] != 5 { 475 t.Fatalf("Expected NetFetcher.Request be called with hopCount 5, got %v", fetcher.hopCounts[0]) 476 } 477 } 478 479 // TestNetStoreGetCallsOffer tests if Get created a request on the NetFetcher for an unavailable chunk 480 // in case of a source peer provided in the context. 481 func TestNetStoreGetCallsOffer(t *testing.T) { 482 netStore, fetcher := mustNewNetStoreWithFetcher(t) 483 484 chunk := GenerateRandomChunk(ch.DefaultSize) 485 486 // If a source peer is added to the context, NetStore will handle it as an offer 487 ctx := context.WithValue(context.Background(), "source", sourcePeerID.String()) 488 ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) 489 defer cancel() 490 491 // We call get for a not available chunk, it will timeout because the chunk is not delivered 492 _, err := netStore.Get(ctx, chunk.Address()) 493 494 if err != context.DeadlineExceeded { 495 t.Fatalf("Expect error %v got %v", context.DeadlineExceeded, err) 496 } 497 498 // NetStore should call NetFetcher.Offer with the source peer 499 if !fetcher.offerCalled { 500 t.Fatal("Expected NetFetcher.Request to be called") 501 } 502 503 if len(fetcher.sources) != 1 { 504 t.Fatalf("Expected fetcher sources length 1 got %v", len(fetcher.sources)) 505 } 506 507 if fetcher.sources[0].String() != sourcePeerID.String() { 508 t.Fatalf("Expected fetcher source %v got %v", sourcePeerID, fetcher.sources[0]) 509 } 510 511 } 512 513 // TestNetStoreFetcherCountPeers tests multiple NetStore.Get calls with peer in the context. 514 // There is no Put call, so the Get calls timeout 515 func TestNetStoreFetcherCountPeers(t *testing.T) { 516 517 netStore, fetcher := mustNewNetStoreWithFetcher(t) 518 519 addr := randomAddr() 520 peers := []string{randomAddr().Hex(), randomAddr().Hex(), randomAddr().Hex()} 521 522 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 523 defer cancel() 524 errC := make(chan error) 525 nrGets := 3 526 527 // Call Get 3 times with a peer in context 528 for i := 0; i < nrGets; i++ { 529 peer := peers[i] 530 go func() { 531 ctx := context.WithValue(ctx, "peer", peer) 532 _, err := netStore.Get(ctx, addr) 533 errC <- err 534 }() 535 } 536 537 // All 3 Get calls should timeout 538 for i := 0; i < nrGets; i++ { 539 err := <-errC 540 if err != context.DeadlineExceeded { 541 t.Fatalf("Expected \"%v\" error got \"%v\"", context.DeadlineExceeded, err) 542 } 543 } 544 545 // fetcher should be closed after timeout 546 select { 547 case <-fetcher.quit: 548 case <-time.After(3 * time.Second): 549 t.Fatalf("mockNetFetcher not closed after timeout") 550 } 551 552 // All 3 peers should be given to NetFetcher after the 3 Get calls 553 if len(fetcher.peersPerRequest) != nrGets { 554 t.Fatalf("Expected 3 got %v", len(fetcher.peersPerRequest)) 555 } 556 557 for i, peers := range fetcher.peersPerRequest { 558 if len(peers) < i+1 { 559 t.Fatalf("Expected at least %v got %v", i+1, len(peers)) 560 } 561 } 562 } 563 564 // TestNetStoreFetchFuncCalledMultipleTimes calls the wait function given by FetchFunc three times, 565 // and checks there is still exactly one fetcher for one chunk. Afthe chunk is delivered, it checks 566 // if the fetcher is closed. 567 func TestNetStoreFetchFuncCalledMultipleTimes(t *testing.T) { 568 netStore, fetcher := mustNewNetStoreWithFetcher(t) 569 570 chunk := GenerateRandomChunk(ch.DefaultSize) 571 572 ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 573 defer cancel() 574 575 // FetchFunc should return a non-nil wait function, because the chunk is not available 576 wait := netStore.FetchFunc(ctx, chunk.Address()) 577 if wait == nil { 578 t.Fatal("Expected wait function to be not nil") 579 } 580 581 // There should be exactly one fetcher for the chunk 582 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 583 t.Fatalf("Expected netStore to have one fetcher for the requested chunk") 584 } 585 586 // Call wait three times in parallel 587 count := 3 588 errC := make(chan error) 589 for i := 0; i < count; i++ { 590 go func() { 591 errC <- wait(ctx) 592 }() 593 } 594 595 // sleep a little so the wait functions are called above 596 time.Sleep(100 * time.Millisecond) 597 598 // there should be still only one fetcher, because all wait calls are for the same chunk 599 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 600 t.Fatal("Expected netStore to have one fetcher for the requested chunk") 601 } 602 603 // Deliver the chunk with a Put 604 err := netStore.Put(ctx, chunk) 605 if err != nil { 606 t.Fatalf("Expected no err got %v", err) 607 } 608 609 // wait until all wait calls return (because the chunk is delivered) 610 for i := 0; i < count; i++ { 611 err := <-errC 612 if err != nil { 613 t.Fatal(err) 614 } 615 } 616 617 // There should be no more fetchers for the delivered chunk 618 if netStore.fetchers.Len() != 0 { 619 t.Fatal("Expected netStore to remove the fetcher after delivery") 620 } 621 622 // The context for the fetcher should be cancelled after delivery 623 select { 624 case <-fetcher.ctx.Done(): 625 default: 626 t.Fatal("Expected fetcher context to be cancelled") 627 } 628 } 629 630 // TestNetStoreFetcherLifeCycleWithTimeout is similar to TestNetStoreFetchFuncCalledMultipleTimes, 631 // the only difference is that we don't deilver the chunk, just wait for timeout 632 func TestNetStoreFetcherLifeCycleWithTimeout(t *testing.T) { 633 netStore, fetcher := mustNewNetStoreWithFetcher(t) 634 635 chunk := GenerateRandomChunk(ch.DefaultSize) 636 637 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 638 defer cancel() 639 640 // FetchFunc should return a non-nil wait function, because the chunk is not available 641 wait := netStore.FetchFunc(ctx, chunk.Address()) 642 if wait == nil { 643 t.Fatal("Expected wait function to be not nil") 644 } 645 646 // There should be exactly one fetcher for the chunk 647 if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { 648 t.Fatalf("Expected netStore to have one fetcher for the requested chunk") 649 } 650 651 // Call wait three times in parallel 652 count := 3 653 errC := make(chan error) 654 for i := 0; i < count; i++ { 655 go func() { 656 rctx, rcancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 657 defer rcancel() 658 err := wait(rctx) 659 if err != context.DeadlineExceeded { 660 errC <- fmt.Errorf("Expected err %v got %v", context.DeadlineExceeded, err) 661 return 662 } 663 errC <- nil 664 }() 665 } 666 667 // wait until all wait calls timeout 668 for i := 0; i < count; i++ { 669 err := <-errC 670 if err != nil { 671 t.Fatal(err) 672 } 673 } 674 675 // There should be no more fetchers after timeout 676 if netStore.fetchers.Len() != 0 { 677 t.Fatal("Expected netStore to remove the fetcher after delivery") 678 } 679 680 // The context for the fetcher should be cancelled after timeout 681 select { 682 case <-fetcher.ctx.Done(): 683 default: 684 t.Fatal("Expected fetcher context to be cancelled") 685 } 686 } 687 688 func randomAddr() Address { 689 addr := make([]byte, 32) 690 rand.Read(addr) 691 return Address(addr) 692 }