github.com/theQRL/go-zond@v0.1.1/les/flowcontrol/manager_test.go (about) 1 // Copyright 2019 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 flowcontrol 18 19 import ( 20 "math" 21 "math/rand" 22 "testing" 23 "time" 24 25 "github.com/theQRL/go-zond/common/mclock" 26 ) 27 28 type testNode struct { 29 node *ClientNode 30 bufLimit, capacity uint64 31 waitUntil mclock.AbsTime 32 index, totalCost uint64 33 } 34 35 const ( 36 testMaxCost = 1000000 37 testLength = 100000 38 ) 39 40 // testConstantTotalCapacity simulates multiple request sender nodes and verifies 41 // whether the total amount of served requests matches the expected value based on 42 // the total capacity and the duration of the test. 43 // Some nodes are sending requests occasionally so that their buffer should regularly 44 // reach the maximum while other nodes (the "max capacity nodes") are sending at the 45 // maximum permitted rate. The max capacity nodes are changed multiple times during 46 // a single test. 47 func TestConstantTotalCapacity(t *testing.T) { 48 testConstantTotalCapacity(t, 10, 1, 0, false) 49 testConstantTotalCapacity(t, 10, 1, 1, false) 50 testConstantTotalCapacity(t, 30, 1, 0, false) 51 testConstantTotalCapacity(t, 30, 2, 3, false) 52 testConstantTotalCapacity(t, 100, 1, 0, false) 53 testConstantTotalCapacity(t, 100, 3, 5, false) 54 testConstantTotalCapacity(t, 100, 5, 10, false) 55 testConstantTotalCapacity(t, 100, 3, 5, true) 56 } 57 58 func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, randomSend int, priorityOverflow bool) { 59 clock := &mclock.Simulated{} 60 nodes := make([]*testNode, nodeCount) 61 var totalCapacity uint64 62 for i := range nodes { 63 nodes[i] = &testNode{capacity: uint64(50000 + rand.Intn(100000))} 64 totalCapacity += nodes[i].capacity 65 } 66 m := NewClientManager(PieceWiseLinear{{0, totalCapacity}}, clock) 67 if priorityOverflow { 68 // provoke a situation where rcLastUpdate overflow needs to be handled 69 m.rcLastIntValue = math.MaxInt64 - 10000000000 70 } 71 for _, n := range nodes { 72 n.bufLimit = n.capacity * 6000 73 n.node = NewClientNode(m, ServerParams{BufLimit: n.bufLimit, MinRecharge: n.capacity}) 74 } 75 maxNodes := make([]int, maxCapacityNodes) 76 for i := range maxNodes { 77 // we don't care if some indexes are selected multiple times 78 // in that case we have fewer max nodes 79 maxNodes[i] = rand.Intn(nodeCount) 80 } 81 82 var sendCount int 83 for i := 0; i < testLength; i++ { 84 now := clock.Now() 85 for _, idx := range maxNodes { 86 for nodes[idx].send(t, now) { 87 } 88 } 89 if rand.Intn(testLength) < maxCapacityNodes*3 { 90 maxNodes[rand.Intn(maxCapacityNodes)] = rand.Intn(nodeCount) 91 } 92 93 sendCount += randomSend 94 failCount := randomSend * 10 95 for sendCount > 0 && failCount > 0 { 96 if nodes[rand.Intn(nodeCount)].send(t, now) { 97 sendCount-- 98 } else { 99 failCount-- 100 } 101 } 102 clock.Run(time.Millisecond) 103 } 104 105 var totalCost uint64 106 for _, n := range nodes { 107 totalCost += n.totalCost 108 } 109 ratio := float64(totalCost) / float64(totalCapacity) / testLength 110 if ratio < 0.98 || ratio > 1.02 { 111 t.Errorf("totalCost/totalCapacity/testLength ratio incorrect (expected: 1, got: %f)", ratio) 112 } 113 } 114 115 func (n *testNode) send(t *testing.T, now mclock.AbsTime) bool { 116 if now < n.waitUntil { 117 return false 118 } 119 n.index++ 120 if ok, _, _ := n.node.AcceptRequest(0, n.index, testMaxCost); !ok { 121 t.Fatalf("Rejected request after expected waiting time has passed") 122 } 123 rcost := uint64(rand.Int63n(testMaxCost)) 124 bv := n.node.RequestProcessed(0, n.index, testMaxCost, rcost) 125 if bv < testMaxCost { 126 n.waitUntil = now + mclock.AbsTime((testMaxCost-bv)*1001000/n.capacity) 127 } 128 n.totalCost += rcost 129 return true 130 }