github.com/MetalBlockchain/metalgo@v1.11.9/snow/networking/tracker/resource_tracker_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package tracker 5 6 import ( 7 "testing" 8 "time" 9 10 "github.com/prometheus/client_golang/prometheus" 11 "github.com/stretchr/testify/require" 12 "go.uber.org/mock/gomock" 13 14 "github.com/MetalBlockchain/metalgo/ids" 15 "github.com/MetalBlockchain/metalgo/utils/math/meter" 16 "github.com/MetalBlockchain/metalgo/utils/resource" 17 ) 18 19 func TestNewCPUTracker(t *testing.T) { 20 require := require.New(t) 21 22 reg := prometheus.NewRegistry() 23 halflife := 5 * time.Second 24 factory := &meter.ContinuousFactory{} 25 26 trackerIntf, err := NewResourceTracker(reg, resource.NoUsage, factory, halflife) 27 require.NoError(err) 28 require.IsType(&resourceTracker{}, trackerIntf) 29 tracker := trackerIntf.(*resourceTracker) 30 require.Equal(factory, tracker.factory) 31 require.NotNil(tracker.processingMeter) 32 require.Equal(halflife, tracker.halflife) 33 require.NotNil(tracker.meters) 34 require.NotNil(tracker.metrics) 35 } 36 37 func TestCPUTracker(t *testing.T) { 38 require := require.New(t) 39 40 halflife := 5 * time.Second 41 42 ctrl := gomock.NewController(t) 43 mockUser := resource.NewMockUser(ctrl) 44 mockUser.EXPECT().CPUUsage().Return(1.0).Times(3) 45 46 tracker, err := NewResourceTracker(prometheus.NewRegistry(), mockUser, meter.ContinuousFactory{}, time.Second) 47 require.NoError(err) 48 49 node1 := ids.BuildTestNodeID([]byte{1}) 50 node2 := ids.BuildTestNodeID([]byte{2}) 51 52 // Note that all the durations between start and end are [halflife]. 53 startTime1 := time.Now() 54 endTime1 := startTime1.Add(halflife) 55 // Note that all CPU usage is attributed to at-large allocation. 56 tracker.StartProcessing(node1, startTime1) 57 tracker.StopProcessing(node1, endTime1) 58 59 startTime2 := endTime1 60 endTime2 := startTime2.Add(halflife) 61 // Note that all CPU usage is attributed to at-large allocation. 62 tracker.StartProcessing(node2, startTime2) 63 tracker.StopProcessing(node2, endTime2) 64 65 cpuTracker := tracker.CPUTracker() 66 67 node1Utilization := cpuTracker.Usage(node1, endTime2) 68 node2Utilization := cpuTracker.Usage(node2, endTime2) 69 require.Greater(node2Utilization, node1Utilization) 70 71 cumulative := cpuTracker.TotalUsage() 72 sum := node1Utilization + node2Utilization 73 require.Equal(sum, cumulative) 74 75 mockUser.EXPECT().CPUUsage().Return(.5).Times(3) 76 77 startTime3 := endTime2 78 endTime3 := startTime3.Add(halflife) 79 newNode1Utilization := cpuTracker.Usage(node1, endTime3) 80 require.Greater(node1Utilization, newNode1Utilization) 81 newCumulative := cpuTracker.TotalUsage() 82 require.Greater(cumulative, newCumulative) 83 84 startTime4 := endTime3 85 endTime4 := startTime4.Add(halflife) 86 // Note that only half of CPU usage is attributed to at-large allocation. 87 tracker.StartProcessing(node1, startTime4) 88 tracker.StopProcessing(node1, endTime4) 89 90 cumulative = cpuTracker.TotalUsage() 91 sum = node1Utilization + node2Utilization 92 require.Greater(sum, cumulative) 93 } 94 95 func TestCPUTrackerTimeUntilCPUUtilization(t *testing.T) { 96 require := require.New(t) 97 98 halflife := 5 * time.Second 99 tracker, err := NewResourceTracker(prometheus.NewRegistry(), resource.NoUsage, meter.ContinuousFactory{}, halflife) 100 require.NoError(err) 101 now := time.Now() 102 nodeID := ids.GenerateTestNodeID() 103 // Start the meter 104 tracker.StartProcessing(nodeID, now) 105 // One halflife passes; stop the meter 106 now = now.Add(halflife) 107 tracker.StopProcessing(nodeID, now) 108 cpuTracker := tracker.CPUTracker() 109 // Read the current value 110 currentVal := cpuTracker.Usage(nodeID, now) 111 // Suppose we want to wait for the value to be 112 // a third of its current value 113 desiredVal := currentVal / 3 114 // See when that should happen 115 timeUntilDesiredVal := cpuTracker.TimeUntilUsage(nodeID, now, desiredVal) 116 // Get the actual value at that time 117 now = now.Add(timeUntilDesiredVal) 118 actualVal := cpuTracker.Usage(nodeID, now) 119 // Make sure the actual/expected are close 120 require.InDelta(desiredVal, actualVal, .00001) 121 // Make sure TimeUntilUsage returns the zero duration if 122 // the value provided >= the current value 123 require.Zero(cpuTracker.TimeUntilUsage(nodeID, now, actualVal)) 124 require.Zero(cpuTracker.TimeUntilUsage(nodeID, now, actualVal+.1)) 125 // Make sure it returns the zero duration if the node isn't known 126 require.Zero(cpuTracker.TimeUntilUsage(ids.GenerateTestNodeID(), now, 0.0001)) 127 }