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