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