github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/fetcher_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:43</date>
    10  //</624450113661571072>
    11  
    12  
    13  package network
    14  
    15  import (
    16  	"context"
    17  	"sync"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/ethereum/go-ethereum/p2p/enode"
    22  )
    23  
    24  var requestedPeerID = enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8")
    25  var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9")
    26  
    27  //mockrequester在调用其dorequest函数时将每个请求推送到requestc通道
    28  type mockRequester struct {
    29  //请求[]请求
    30  requestC  chan *Request   //当一个请求到来时,它被推送到请求C
    31  waitTimes []time.Duration //使用waittimes[i]可以定义在第i个请求上等待的时间(可选)
    32  count     int             //统计请求数
    33  	quitC     chan struct{}
    34  }
    35  
    36  func newMockRequester(waitTimes ...time.Duration) *mockRequester {
    37  	return &mockRequester{
    38  		requestC:  make(chan *Request),
    39  		waitTimes: waitTimes,
    40  		quitC:     make(chan struct{}),
    41  	}
    42  }
    43  
    44  func (m *mockRequester) doRequest(ctx context.Context, request *Request) (*enode.ID, chan struct{}, error) {
    45  	waitTime := time.Duration(0)
    46  	if m.count < len(m.waitTimes) {
    47  		waitTime = m.waitTimes[m.count]
    48  		m.count++
    49  	}
    50  	time.Sleep(waitTime)
    51  	m.requestC <- request
    52  
    53  //如果请求中存在源,请使用该源,如果不使用全局requestedpeerid
    54  	source := request.Source
    55  	if source == nil {
    56  		source = &requestedPeerID
    57  	}
    58  	return source, m.quitC, nil
    59  }
    60  
    61  //testwithersinglerequest使用mockrequester创建一个取数器,并使用一组要跳过的对等方来运行它。
    62  //mockrequester每次调用请求函数时都在通道上推送请求。使用
    63  //这个通道我们测试调用fetcher.request是否调用request函数,以及它是否使用
    64  //我们为fetcher.run函数提供的要跳过的正确对等点。
    65  func TestFetcherSingleRequest(t *testing.T) {
    66  	requester := newMockRequester()
    67  	addr := make([]byte, 32)
    68  	fetcher := NewFetcher(addr, requester.doRequest, true)
    69  
    70  	peers := []string{"a", "b", "c", "d"}
    71  	peersToSkip := &sync.Map{}
    72  	for _, p := range peers {
    73  		peersToSkip.Store(p, time.Now())
    74  	}
    75  
    76  	ctx, cancel := context.WithCancel(context.Background())
    77  	defer cancel()
    78  
    79  	go fetcher.run(ctx, peersToSkip)
    80  
    81  	rctx := context.Background()
    82  	fetcher.Request(rctx, 0)
    83  
    84  	select {
    85  	case request := <-requester.requestC:
    86  //请求应包含从PeersToSkip提供给获取程序的所有对等方
    87  		for _, p := range peers {
    88  			if _, ok := request.peersToSkip.Load(p); !ok {
    89  				t.Fatalf("request.peersToSkip misses peer")
    90  			}
    91  		}
    92  
    93  //源对等端最终也应添加到对等端跳过
    94  		time.Sleep(100 * time.Millisecond)
    95  		if _, ok := request.peersToSkip.Load(requestedPeerID.String()); !ok {
    96  			t.Fatalf("request.peersToSkip does not contain peer returned by the request function")
    97  		}
    98  
    99  //转发请求中的跃点计数应递增
   100  		if request.HopCount != 1 {
   101  			t.Fatalf("Expected request.HopCount 1 got %v", request.HopCount)
   102  		}
   103  
   104  //fetch应该触发一个请求,如果它没有及时发生,测试应该失败。
   105  	case <-time.After(200 * time.Millisecond):
   106  		t.Fatalf("fetch timeout")
   107  	}
   108  }
   109  
   110  //testCancelStopsFetcher测试已取消的获取程序即使调用了其获取函数,也不会启动进一步的请求。
   111  func TestFetcherCancelStopsFetcher(t *testing.T) {
   112  	requester := newMockRequester()
   113  	addr := make([]byte, 32)
   114  	fetcher := NewFetcher(addr, requester.doRequest, true)
   115  
   116  	peersToSkip := &sync.Map{}
   117  
   118  	ctx, cancel := context.WithCancel(context.Background())
   119  
   120  //我们启动提取程序,然后立即取消上下文
   121  	go fetcher.run(ctx, peersToSkip)
   122  	cancel()
   123  
   124  	rctx, rcancel := context.WithTimeout(ctx, 100*time.Millisecond)
   125  	defer rcancel()
   126  //我们使用活动上下文调用请求
   127  	fetcher.Request(rctx, 0)
   128  
   129  //回取器不应该启动请求,我们只能通过等待一点并确保没有发生请求来进行检查。
   130  	select {
   131  	case <-requester.requestC:
   132  		t.Fatalf("cancelled fetcher initiated request")
   133  	case <-time.After(200 * time.Millisecond):
   134  	}
   135  }
   136  
   137  //TestFetchCancelStopsRequest测试使用已取消的上下文调用请求函数不会启动请求
   138  func TestFetcherCancelStopsRequest(t *testing.T) {
   139  	requester := newMockRequester(100 * time.Millisecond)
   140  	addr := make([]byte, 32)
   141  	fetcher := NewFetcher(addr, requester.doRequest, true)
   142  
   143  	peersToSkip := &sync.Map{}
   144  
   145  	ctx, cancel := context.WithCancel(context.Background())
   146  	defer cancel()
   147  
   148  //我们使用活动上下文启动提取程序
   149  	go fetcher.run(ctx, peersToSkip)
   150  
   151  	rctx, rcancel := context.WithCancel(context.Background())
   152  	rcancel()
   153  
   154  //我们用取消的上下文调用请求
   155  	fetcher.Request(rctx, 0)
   156  
   157  //回取器不应该启动请求,我们只能通过等待一点并确保没有发生请求来进行检查。
   158  	select {
   159  	case <-requester.requestC:
   160  		t.Fatalf("cancelled fetch function initiated request")
   161  	case <-time.After(200 * time.Millisecond):
   162  	}
   163  
   164  //如果有另一个具有活动上下文的请求,则应该有一个请求,因为提取程序本身没有被取消。
   165  	rctx = context.Background()
   166  	fetcher.Request(rctx, 0)
   167  
   168  	select {
   169  	case <-requester.requestC:
   170  	case <-time.After(200 * time.Millisecond):
   171  		t.Fatalf("expected request")
   172  	}
   173  }
   174  
   175  //TestOfferUsesSource测试获取器提供行为。
   176  //在这种情况下,应该有1个(并且只有一个)来自源对等端的请求,并且
   177  //源节点ID应出现在PeerStoskip映射中。
   178  func TestFetcherOfferUsesSource(t *testing.T) {
   179  	requester := newMockRequester(100 * time.Millisecond)
   180  	addr := make([]byte, 32)
   181  	fetcher := NewFetcher(addr, requester.doRequest, true)
   182  
   183  	peersToSkip := &sync.Map{}
   184  
   185  	ctx, cancel := context.WithCancel(context.Background())
   186  	defer cancel()
   187  
   188  //启动取纸器
   189  	go fetcher.run(ctx, peersToSkip)
   190  
   191  	rctx := context.Background()
   192  //使用源对等调用offer函数
   193  	fetcher.Offer(rctx, &sourcePeerID)
   194  
   195  //提取程序不应启动请求
   196  	select {
   197  	case <-requester.requestC:
   198  		t.Fatalf("fetcher initiated request")
   199  	case <-time.After(200 * time.Millisecond):
   200  	}
   201  
   202  //报价后的呼叫请求
   203  	rctx = context.Background()
   204  	fetcher.Request(rctx, 0)
   205  
   206  //从取数器中应该正好有一个请求
   207  	var request *Request
   208  	select {
   209  	case request = <-requester.requestC:
   210  		if *request.Source != sourcePeerID {
   211  			t.Fatalf("Expected source id %v got %v", sourcePeerID, request.Source)
   212  		}
   213  	case <-time.After(200 * time.Millisecond):
   214  		t.Fatalf("fetcher did not initiate request")
   215  	}
   216  
   217  	select {
   218  	case <-requester.requestC:
   219  		t.Fatalf("Fetcher number of requests expected 1 got 2")
   220  	case <-time.After(200 * time.Millisecond):
   221  	}
   222  
   223  //源对等端最终应添加到对等端跳过
   224  	time.Sleep(100 * time.Millisecond)
   225  	if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok {
   226  		t.Fatalf("SourcePeerId not added to peersToSkip")
   227  	}
   228  }
   229  
   230  func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) {
   231  	requester := newMockRequester(100 * time.Millisecond)
   232  	addr := make([]byte, 32)
   233  	fetcher := NewFetcher(addr, requester.doRequest, true)
   234  
   235  	peersToSkip := &sync.Map{}
   236  
   237  	ctx, cancel := context.WithCancel(context.Background())
   238  	defer cancel()
   239  
   240  //启动取纸器
   241  	go fetcher.run(ctx, peersToSkip)
   242  
   243  //先呼叫请求
   244  	rctx := context.Background()
   245  	fetcher.Request(rctx, 0)
   246  
   247  //应该有一个来自回迁者的请求
   248  	var request *Request
   249  	select {
   250  	case request = <-requester.requestC:
   251  		if request.Source != nil {
   252  			t.Fatalf("Incorrect source peer id, expected nil got %v", request.Source)
   253  		}
   254  	case <-time.After(200 * time.Millisecond):
   255  		t.Fatalf("fetcher did not initiate request")
   256  	}
   257  
   258  //请求后呼叫提供
   259  	fetcher.Offer(context.Background(), &sourcePeerID)
   260  
   261  //应该有一个来自回迁者的请求
   262  	select {
   263  	case request = <-requester.requestC:
   264  		if *request.Source != sourcePeerID {
   265  			t.Fatalf("Incorrect source peer id, expected %v got %v", sourcePeerID, request.Source)
   266  		}
   267  	case <-time.After(200 * time.Millisecond):
   268  		t.Fatalf("fetcher did not initiate request")
   269  	}
   270  
   271  //源对等端最终应添加到对等端跳过
   272  	time.Sleep(100 * time.Millisecond)
   273  	if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok {
   274  		t.Fatalf("SourcePeerId not added to peersToSkip")
   275  	}
   276  }
   277  
   278  //TestFetcherRetryOnTimeout测试在SearchTimeout通过后获取重试
   279  func TestFetcherRetryOnTimeout(t *testing.T) {
   280  	requester := newMockRequester()
   281  	addr := make([]byte, 32)
   282  	fetcher := NewFetcher(addr, requester.doRequest, true)
   283  //将SearchTimeout设置为低值,以便测试更快
   284  	fetcher.searchTimeout = 250 * time.Millisecond
   285  
   286  	peersToSkip := &sync.Map{}
   287  
   288  	ctx, cancel := context.WithCancel(context.Background())
   289  	defer cancel()
   290  
   291  //启动取纸器
   292  	go fetcher.run(ctx, peersToSkip)
   293  
   294  //使用活动上下文调用fetch函数
   295  	rctx := context.Background()
   296  	fetcher.Request(rctx, 0)
   297  
   298  //100毫秒后,应启动第一个请求
   299  	time.Sleep(100 * time.Millisecond)
   300  
   301  	select {
   302  	case <-requester.requestC:
   303  	default:
   304  		t.Fatalf("fetch did not initiate request")
   305  	}
   306  
   307  //再过100毫秒后,不应启动新的请求,因为搜索超时为250毫秒。
   308  	time.Sleep(100 * time.Millisecond)
   309  
   310  	select {
   311  	case <-requester.requestC:
   312  		t.Fatalf("unexpected request from fetcher")
   313  	default:
   314  	}
   315  
   316  //在另一个300ms搜索超时结束后,应该有一个新的请求
   317  	time.Sleep(300 * time.Millisecond)
   318  
   319  	select {
   320  	case <-requester.requestC:
   321  	default:
   322  		t.Fatalf("fetch did not retry request")
   323  	}
   324  }
   325  
   326  //TestFetcherFactory创建一个FetcherFactory并检查工厂是否真正创建并启动
   327  //回迁函数时的回迁函数。我们只需检查
   328  //调用FETCH函数时启动请求
   329  func TestFetcherFactory(t *testing.T) {
   330  	requester := newMockRequester(100 * time.Millisecond)
   331  	addr := make([]byte, 32)
   332  	fetcherFactory := NewFetcherFactory(requester.doRequest, false)
   333  
   334  	peersToSkip := &sync.Map{}
   335  
   336  	fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip)
   337  
   338  	fetcher.Request(context.Background(), 0)
   339  
   340  //检查创建的fetchFunction是否真的启动了一个fetcher并启动了一个请求
   341  	select {
   342  	case <-requester.requestC:
   343  	case <-time.After(200 * time.Millisecond):
   344  		t.Fatalf("fetch timeout")
   345  	}
   346  
   347  }
   348  
   349  func TestFetcherRequestQuitRetriesRequest(t *testing.T) {
   350  	requester := newMockRequester()
   351  	addr := make([]byte, 32)
   352  	fetcher := NewFetcher(addr, requester.doRequest, true)
   353  
   354  //确保SearchTimeout很长,以确保请求不是
   355  //由于超时而重试
   356  	fetcher.searchTimeout = 10 * time.Second
   357  
   358  	peersToSkip := &sync.Map{}
   359  
   360  	ctx, cancel := context.WithCancel(context.Background())
   361  	defer cancel()
   362  
   363  	go fetcher.run(ctx, peersToSkip)
   364  
   365  	rctx := context.Background()
   366  	fetcher.Request(rctx, 0)
   367  
   368  	select {
   369  	case <-requester.requestC:
   370  	case <-time.After(200 * time.Millisecond):
   371  		t.Fatalf("request is not initiated")
   372  	}
   373  
   374  	close(requester.quitC)
   375  
   376  	select {
   377  	case <-requester.requestC:
   378  	case <-time.After(200 * time.Millisecond):
   379  		t.Fatalf("request is not initiated after failed request")
   380  	}
   381  }
   382  
   383  //testRequestSkipper检查peerSkip函数是否将跳过提供的peer
   384  //不要跳过未知的。
   385  func TestRequestSkipPeer(t *testing.T) {
   386  	addr := make([]byte, 32)
   387  	peers := []enode.ID{
   388  		enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8"),
   389  		enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9"),
   390  	}
   391  
   392  	peersToSkip := new(sync.Map)
   393  	peersToSkip.Store(peers[0].String(), time.Now())
   394  	r := NewRequest(addr, false, peersToSkip)
   395  
   396  	if !r.SkipPeer(peers[0].String()) {
   397  		t.Errorf("peer not skipped")
   398  	}
   399  
   400  	if r.SkipPeer(peers[1].String()) {
   401  		t.Errorf("peer skipped")
   402  	}
   403  }
   404  
   405  //testRequestSkipperExpired检查是否未跳过要跳过的对等机
   406  //请求超时之后。
   407  func TestRequestSkipPeerExpired(t *testing.T) {
   408  	addr := make([]byte, 32)
   409  	peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8")
   410  
   411  //将requestTimeout设置为低值,并在测试后重置它
   412  	defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout)
   413  	RequestTimeout = 250 * time.Millisecond
   414  
   415  	peersToSkip := new(sync.Map)
   416  	peersToSkip.Store(peer.String(), time.Now())
   417  	r := NewRequest(addr, false, peersToSkip)
   418  
   419  	if !r.SkipPeer(peer.String()) {
   420  		t.Errorf("peer not skipped")
   421  	}
   422  
   423  	time.Sleep(500 * time.Millisecond)
   424  
   425  	if r.SkipPeer(peer.String()) {
   426  		t.Errorf("peer skipped")
   427  	}
   428  }
   429  
   430  //testRequestSkipperPermanent检查是否跳过要跳过的对等机
   431  //如果设置为永久跳过,则不会跳过请求超时之后
   432  //按值到PeersToSkip映射不是Time.Duration。
   433  func TestRequestSkipPeerPermanent(t *testing.T) {
   434  	addr := make([]byte, 32)
   435  	peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8")
   436  
   437  //将requestTimeout设置为低值,并在测试后重置它
   438  	defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout)
   439  	RequestTimeout = 250 * time.Millisecond
   440  
   441  	peersToSkip := new(sync.Map)
   442  	peersToSkip.Store(peer.String(), true)
   443  	r := NewRequest(addr, false, peersToSkip)
   444  
   445  	if !r.SkipPeer(peer.String()) {
   446  		t.Errorf("peer not skipped")
   447  	}
   448  
   449  	time.Sleep(500 * time.Millisecond)
   450  
   451  	if !r.SkipPeer(peer.String()) {
   452  		t.Errorf("peer not skipped")
   453  	}
   454  }
   455  
   456  func TestFetcherMaxHopCount(t *testing.T) {
   457  	requester := newMockRequester()
   458  	addr := make([]byte, 32)
   459  	fetcher := NewFetcher(addr, requester.doRequest, true)
   460  
   461  	ctx, cancel := context.WithCancel(context.Background())
   462  	defer cancel()
   463  
   464  	peersToSkip := &sync.Map{}
   465  
   466  	go fetcher.run(ctx, peersToSkip)
   467  
   468  	rctx := context.Background()
   469  	fetcher.Request(rctx, maxHopCount)
   470  
   471  //如果HopCount已达到最大值,则不应启动任何请求。
   472  	select {
   473  	case <-requester.requestC:
   474  		t.Fatalf("cancelled fetcher initiated request")
   475  	case <-time.After(200 * time.Millisecond):
   476  	}
   477  }
   478