github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/les/distributor_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:38</date>
    10  //</624450093415665664>
    11  
    12  
    13  //package light实现可按需检索的状态和链对象
    14  //对于以太坊Light客户端。
    15  package les
    16  
    17  import (
    18  	"math/rand"
    19  	"sync"
    20  	"testing"
    21  	"time"
    22  )
    23  
    24  type testDistReq struct {
    25  	cost, procTime, order uint64
    26  	canSendTo             map[*testDistPeer]struct{}
    27  }
    28  
    29  func (r *testDistReq) getCost(dp distPeer) uint64 {
    30  	return r.cost
    31  }
    32  
    33  func (r *testDistReq) canSend(dp distPeer) bool {
    34  	_, ok := r.canSendTo[dp.(*testDistPeer)]
    35  	return ok
    36  }
    37  
    38  func (r *testDistReq) request(dp distPeer) func() {
    39  	return func() { dp.(*testDistPeer).send(r) }
    40  }
    41  
    42  type testDistPeer struct {
    43  	sent    []*testDistReq
    44  	sumCost uint64
    45  	lock    sync.RWMutex
    46  }
    47  
    48  func (p *testDistPeer) send(r *testDistReq) {
    49  	p.lock.Lock()
    50  	defer p.lock.Unlock()
    51  
    52  	p.sent = append(p.sent, r)
    53  	p.sumCost += r.cost
    54  }
    55  
    56  func (p *testDistPeer) worker(t *testing.T, checkOrder bool, stop chan struct{}) {
    57  	var last uint64
    58  	for {
    59  		wait := time.Millisecond
    60  		p.lock.Lock()
    61  		if len(p.sent) > 0 {
    62  			rq := p.sent[0]
    63  			wait = time.Duration(rq.procTime)
    64  			p.sumCost -= rq.cost
    65  			if checkOrder {
    66  				if rq.order <= last {
    67  					t.Errorf("Requests processed in wrong order")
    68  				}
    69  				last = rq.order
    70  			}
    71  			p.sent = p.sent[1:]
    72  		}
    73  		p.lock.Unlock()
    74  		select {
    75  		case <-stop:
    76  			return
    77  		case <-time.After(wait):
    78  		}
    79  	}
    80  }
    81  
    82  const (
    83  	testDistBufLimit       = 10000000
    84  	testDistMaxCost        = 1000000
    85  	testDistPeerCount      = 5
    86  	testDistReqCount       = 5000
    87  	testDistMaxResendCount = 3
    88  )
    89  
    90  func (p *testDistPeer) waitBefore(cost uint64) (time.Duration, float64) {
    91  	p.lock.RLock()
    92  	sumCost := p.sumCost + cost
    93  	p.lock.RUnlock()
    94  	if sumCost < testDistBufLimit {
    95  		return 0, float64(testDistBufLimit-sumCost) / float64(testDistBufLimit)
    96  	}
    97  	return time.Duration(sumCost - testDistBufLimit), 0
    98  }
    99  
   100  func (p *testDistPeer) canQueue() bool {
   101  	return true
   102  }
   103  
   104  func (p *testDistPeer) queueSend(f func()) {
   105  	f()
   106  }
   107  
   108  func TestRequestDistributor(t *testing.T) {
   109  	testRequestDistributor(t, false)
   110  }
   111  
   112  func TestRequestDistributorResend(t *testing.T) {
   113  	testRequestDistributor(t, true)
   114  }
   115  
   116  func testRequestDistributor(t *testing.T, resend bool) {
   117  	stop := make(chan struct{})
   118  	defer close(stop)
   119  
   120  	dist := newRequestDistributor(nil, stop)
   121  	var peers [testDistPeerCount]*testDistPeer
   122  	for i := range peers {
   123  		peers[i] = &testDistPeer{}
   124  		go peers[i].worker(t, !resend, stop)
   125  		dist.registerTestPeer(peers[i])
   126  	}
   127  
   128  	var wg sync.WaitGroup
   129  
   130  	for i := 1; i <= testDistReqCount; i++ {
   131  		cost := uint64(rand.Int63n(testDistMaxCost))
   132  		procTime := uint64(rand.Int63n(int64(cost + 1)))
   133  		rq := &testDistReq{
   134  			cost:      cost,
   135  			procTime:  procTime,
   136  			order:     uint64(i),
   137  			canSendTo: make(map[*testDistPeer]struct{}),
   138  		}
   139  		for _, peer := range peers {
   140  			if rand.Intn(2) != 0 {
   141  				rq.canSendTo[peer] = struct{}{}
   142  			}
   143  		}
   144  
   145  		wg.Add(1)
   146  		req := &distReq{
   147  			getCost: rq.getCost,
   148  			canSend: rq.canSend,
   149  			request: rq.request,
   150  		}
   151  		chn := dist.queue(req)
   152  		go func() {
   153  			cnt := 1
   154  			if resend && len(rq.canSendTo) != 0 {
   155  				cnt = rand.Intn(testDistMaxResendCount) + 1
   156  			}
   157  			for i := 0; i < cnt; i++ {
   158  				if i != 0 {
   159  					chn = dist.queue(req)
   160  				}
   161  				p := <-chn
   162  				if p == nil {
   163  					if len(rq.canSendTo) != 0 {
   164  						t.Errorf("Request that could have been sent was dropped")
   165  					}
   166  				} else {
   167  					peer := p.(*testDistPeer)
   168  					if _, ok := rq.canSendTo[peer]; !ok {
   169  						t.Errorf("Request sent to wrong peer")
   170  					}
   171  				}
   172  			}
   173  			wg.Done()
   174  		}()
   175  		if rand.Intn(1000) == 0 {
   176  			time.Sleep(time.Duration(rand.Intn(5000000)))
   177  		}
   178  	}
   179  
   180  	wg.Wait()
   181  }
   182