github.com/core-coin/go-core/v2@v2.1.9/les/distributor_test.go (about) 1 // Copyright 2017 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core 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/core-coin/go-core/v2/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()) bool { 109 f() 110 return true 111 } 112 113 func TestRequestDistributor(t *testing.T) { 114 testRequestDistributor(t, false) 115 } 116 117 func TestRequestDistributorResend(t *testing.T) { 118 testRequestDistributor(t, true) 119 } 120 121 func testRequestDistributor(t *testing.T, resend bool) { 122 stop := make(chan struct{}) 123 defer close(stop) 124 125 dist := newRequestDistributor(nil, &mclock.System{}) 126 var peers [testDistPeerCount]*testDistPeer 127 for i := range peers { 128 peers[i] = &testDistPeer{} 129 go peers[i].worker(t, !resend, stop) 130 dist.registerTestPeer(peers[i]) 131 } 132 // Disable the mechanism that we will wait a few time for request 133 // even there is no suitable peer to send right now. 134 waitForPeers = 0 135 136 var wg sync.WaitGroup 137 138 for i := 1; i <= testDistReqCount; i++ { 139 cost := uint64(rand.Int63n(testDistMaxCost)) 140 procTime := uint64(rand.Int63n(int64(cost + 1))) 141 rq := &testDistReq{ 142 cost: cost, 143 procTime: procTime, 144 order: uint64(i), 145 canSendTo: make(map[*testDistPeer]struct{}), 146 } 147 for _, peer := range peers { 148 if rand.Intn(2) != 0 { 149 rq.canSendTo[peer] = struct{}{} 150 } 151 } 152 153 wg.Add(1) 154 req := &distReq{ 155 getCost: rq.getCost, 156 canSend: rq.canSend, 157 request: rq.request, 158 } 159 chn := dist.queue(req) 160 go func() { 161 cnt := 1 162 if resend && len(rq.canSendTo) != 0 { 163 cnt = rand.Intn(testDistMaxResendCount) + 1 164 } 165 for i := 0; i < cnt; i++ { 166 if i != 0 { 167 chn = dist.queue(req) 168 } 169 p := <-chn 170 if p == nil { 171 if len(rq.canSendTo) != 0 { 172 t.Errorf("Request that could have been sent was dropped") 173 } 174 } else { 175 peer := p.(*testDistPeer) 176 if _, ok := rq.canSendTo[peer]; !ok { 177 t.Errorf("Request sent to wrong peer") 178 } 179 } 180 } 181 wg.Done() 182 }() 183 if rand.Intn(1000) == 0 { 184 time.Sleep(time.Duration(rand.Intn(5000000))) 185 } 186 } 187 188 wg.Wait() 189 }