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