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  }