github.com/maynardminer/ethereumprogpow@v1.8.23/swarm/storage/netstore_test.go (about) 1 // Copyright 2018 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 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/ethereumprogpow/ethereumprogpow/common" 31 "github.com/ethereumprogpow/ethereumprogpow/p2p/enode" 32 ch "github.com/ethereumprogpow/ethereumprogpow/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 } 47 48 func (m *mockNetFetcher) Offer(ctx context.Context, source *enode.ID) { 49 m.offerCalled = true 50 m.sources = append(m.sources, source) 51 } 52 53 func (m *mockNetFetcher) Request(ctx context.Context, hopCount uint8) { 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 // TestNetStoreGetAndPut tests calling NetStore.Get which is blocked until the same chunk is Put. 108 // After the Put there should no active fetchers, and the context created for the fetcher should 109 // be cancelled. 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{}) // this channel ensures that the gouroutine with the Put does not run earlier than the Get 119 putErrC := make(chan error) 120 go func() { 121 <-c // wait for the Get to be called 122 time.Sleep(200 * time.Millisecond) // and a little more so it is surely called 123 124 // check if netStore created a fetcher in the Get call for the unavailable chunk 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()) // this is blocked until the Put above is done 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 // the retrieved chunk should be the same as what we Put 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 // the chunk is already available locally, so there should be no active fetchers waiting for it 153 if netStore.fetchers.Len() != 0 { 154 t.Fatal("Expected netStore to remove the fetcher after delivery") 155 } 156 157 // A fetcher was created when the Get was called (and the chunk was not available). The chunk 158 // was delivered with the Put call, so the fetcher should be cancelled now. 159 select { 160 case <-fetcher.ctx.Done(): 161 default: 162 t.Fatal("Expected fetcher context to be cancelled") 163 } 164 165 } 166 167 // TestNetStoreGetAndPut tests calling NetStore.Put and then NetStore.Get. 168 // After the Put the chunk is available locally, so the Get can just retrieve it from LocalStore, 169 // there is no need to create fetchers. 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 // First we Put the chunk, so the chunk will be available locally 179 err := netStore.Put(ctx, chunk) 180 if err != nil { 181 t.Fatalf("Expected no err got %v", err) 182 } 183 184 // Get should retrieve the chunk from LocalStore, without creating fetcher 185 recChunk, err := netStore.Get(ctx, chunk.Address()) 186 if err != nil { 187 t.Fatalf("Expected no err got %v", err) 188 } 189 // the retrieved chunk should be the same as what we Put 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 // no fetcher offer or request should be created for a locally available chunk 194 if fetcher.offerCalled || fetcher.requestCalled { 195 t.Fatal("NetFetcher.offerCalled or requestCalled not expected to be called") 196 } 197 // no fetchers should be created for a locally available chunk 198 if netStore.fetchers.Len() != 0 { 199 t.Fatal("Expected netStore to not have fetcher") 200 } 201 202 } 203 204 // TestNetStoreGetTimeout tests a Get call for an unavailable chunk and waits for timeout 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{}) // this channel ensures that the gouroutine does not run earlier than the Get 214 fetcherErrC := make(chan error) 215 go func() { 216 <-c // wait for the Get to be called 217 time.Sleep(200 * time.Millisecond) // and a little more so it is surely called 218 219 // check if netStore created a fetcher in the Get call for the unavailable chunk 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 // We call Get on this chunk, which is not in LocalStore. We don't Put it at all, so there will 230 // be a timeout 231 _, err := netStore.Get(ctx, chunk.Address()) 232 233 // Check if the timeout happened 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 // A fetcher was created, check if it has been removed after timeout 243 if netStore.fetchers.Len() != 0 { 244 t.Fatal("Expected netStore to remove the fetcher after timeout") 245 } 246 247 // Check if the fetcher context has been cancelled after the timeout 248 select { 249 case <-fetcher.ctx.Done(): 250 default: 251 t.Fatal("Expected fetcher context to be cancelled") 252 } 253 } 254 255 // TestNetStoreGetCancel tests a Get call for an unavailable chunk, then cancels the context and checks 256 // the errors 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{}) // this channel ensures that the gouroutine with the cancel does not run earlier than the Get 265 fetcherErrC := make(chan error, 1) 266 go func() { 267 <-c // wait for the Get to be called 268 time.Sleep(200 * time.Millisecond) // and a little more so it is surely called 269 // check if netStore created a fetcher in the Get call for the unavailable chunk 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 // We call Get with an unavailable chunk, so it will create a fetcher and wait for delivery 282 _, err := netStore.Get(ctx, chunk.Address()) 283 284 if err := <-fetcherErrC; err != nil { 285 t.Fatal(err) 286 } 287 288 // After the context is cancelled above Get should return with an error 289 if err != context.Canceled { 290 t.Fatalf("Expected context.Canceled err got %v", err) 291 } 292 293 // A fetcher was created, check if it has been removed after cancel 294 if netStore.fetchers.Len() != 0 { 295 t.Fatal("Expected netStore to remove the fetcher after cancel") 296 } 297 298 // Check if the fetcher context has been cancelled after the request context cancel 299 select { 300 case <-fetcher.ctx.Done(): 301 default: 302 t.Fatal("Expected fetcher context to be cancelled") 303 } 304 } 305 306 // TestNetStoreMultipleGetAndPut tests four Get calls for the same unavailable chunk. The chunk is 307 // delivered with a Put, we have to make sure all Get calls return, and they use a single fetcher 308 // for the chunk retrieval 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 // sleep to make sure Put is called after all the Get 320 time.Sleep(500 * time.Millisecond) 321 // check if netStore created exactly one fetcher for all Get calls 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 // call Get 4 times for the same unavailable chunk. The calls will be blocked until the Put above. 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 // The Get calls should return after Put, so no timeout expected 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 // A fetcher was created, check if it has been removed after cancel 369 if netStore.fetchers.Len() != 0 { 370 t.Fatal("Expected netStore to remove the fetcher after delivery") 371 } 372 373 // A fetcher was created, check if it has been removed after delivery 374 select { 375 case <-fetcher.ctx.Done(): 376 default: 377 t.Fatal("Expected fetcher context to be cancelled") 378 } 379 380 } 381 382 // TestNetStoreFetchFuncTimeout tests a FetchFunc call for an unavailable chunk and waits for timeout 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 is called for an unavaible chunk, so the returned wait function should not be 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 // There should an active fetcher for the chunk after the FetchFunc call 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 // wait function should timeout because we don't deliver the chunk with a Put 403 err := wait(ctx) 404 if err != context.DeadlineExceeded { 405 t.Fatalf("Expected context.DeadLineExceeded err got %v", err) 406 } 407 408 // the fetcher should be removed after timeout 409 if netStore.fetchers.Len() != 0 { 410 t.Fatal("Expected netStore to remove the fetcher after timeout") 411 } 412 413 // the fetcher context should be cancelled after timeout 414 select { 415 case <-fetcher.ctx.Done(): 416 default: 417 t.Fatal("Expected fetcher context to be cancelled") 418 } 419 } 420 421 // TestNetStoreFetchFuncAfterPut tests that the FetchFunc should return nil for a locally available chunk 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 // We deliver the created the chunk with a Put 431 err := netStore.Put(ctx, chunk) 432 if err != nil { 433 t.Fatalf("Expected no err got %v", err) 434 } 435 436 // FetchFunc should return nil, because the chunk is available locally, no need to fetch it 437 wait := netStore.FetchFunc(ctx, chunk.Address()) 438 if wait != nil { 439 t.Fatal("Expected wait to be nil") 440 } 441 442 // No fetchers should be created at all 443 if netStore.fetchers.Len() != 0 { 444 t.Fatal("Expected netStore to not have fetcher") 445 } 446 } 447 448 // TestNetStoreGetCallsRequest tests if Get created a request on the NetFetcher for an unavailable chunk 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 // We call get for a not available chunk, it will timeout because the chunk is not delivered 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 should call NetFetcher.Request and wait for the chunk 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 // TestNetStoreGetCallsOffer tests if Get created a request on the NetFetcher for an unavailable chunk 476 // in case of a source peer provided in the context. 477 func TestNetStoreGetCallsOffer(t *testing.T) { 478 netStore, fetcher := mustNewNetStoreWithFetcher(t) 479 480 chunk := GenerateRandomChunk(ch.DefaultSize) 481 482 // If a source peer is added to the context, NetStore will handle it as an offer 483 ctx := context.WithValue(context.Background(), "source", sourcePeerID.String()) 484 ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) 485 defer cancel() 486 487 // We call get for a not available chunk, it will timeout because the chunk is not delivered 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 should call NetFetcher.Offer with the source peer 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 tests multiple NetStore.Get calls with peer in the context. 510 // There is no Put call, so the Get calls timeout 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 // Call Get 3 times with a peer in context 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 // All 3 Get calls should timeout 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 // fetcher should be closed after timeout 542 select { 543 case <-fetcher.quit: 544 case <-time.After(3 * time.Second): 545 t.Fatalf("mockNetFetcher not closed after timeout") 546 } 547 548 // All 3 peers should be given to NetFetcher after the 3 Get calls 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 // TestNetStoreFetchFuncCalledMultipleTimes calls the wait function given by FetchFunc three times, 561 // and checks there is still exactly one fetcher for one chunk. Afthe chunk is delivered, it checks 562 // if the fetcher is closed. 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 should return a non-nil wait function, because the chunk is not available 572 wait := netStore.FetchFunc(ctx, chunk.Address()) 573 if wait == nil { 574 t.Fatal("Expected wait function to be not nil") 575 } 576 577 // There should be exactly one fetcher for the chunk 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 // Call wait three times in parallel 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 // sleep a little so the wait functions are called above 592 time.Sleep(100 * time.Millisecond) 593 594 // there should be still only one fetcher, because all wait calls are for the same chunk 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 // Deliver the chunk with a Put 600 err := netStore.Put(ctx, chunk) 601 if err != nil { 602 t.Fatalf("Expected no err got %v", err) 603 } 604 605 // wait until all wait calls return (because the chunk is delivered) 606 for i := 0; i < count; i++ { 607 err := <-errC 608 if err != nil { 609 t.Fatal(err) 610 } 611 } 612 613 // There should be no more fetchers for the delivered chunk 614 if netStore.fetchers.Len() != 0 { 615 t.Fatal("Expected netStore to remove the fetcher after delivery") 616 } 617 618 // The context for the fetcher should be cancelled after delivery 619 select { 620 case <-fetcher.ctx.Done(): 621 default: 622 t.Fatal("Expected fetcher context to be cancelled") 623 } 624 } 625 626 // TestNetStoreFetcherLifeCycleWithTimeout is similar to TestNetStoreFetchFuncCalledMultipleTimes, 627 // the only difference is that we don't deilver the chunk, just wait for timeout 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 should return a non-nil wait function, because the chunk is not available 637 wait := netStore.FetchFunc(ctx, chunk.Address()) 638 if wait == nil { 639 t.Fatal("Expected wait function to be not nil") 640 } 641 642 // There should be exactly one fetcher for the chunk 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 // Call wait three times in parallel 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 // wait until all wait calls timeout 664 for i := 0; i < count; i++ { 665 err := <-errC 666 if err != nil { 667 t.Fatal(err) 668 } 669 } 670 671 // There should be no more fetchers after timeout 672 if netStore.fetchers.Len() != 0 { 673 t.Fatal("Expected netStore to remove the fetcher after delivery") 674 } 675 676 // The context for the fetcher should be cancelled after timeout 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 }