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