github.com/MetalBlockchain/metalgo@v1.11.9/utils/math/meter/meter_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 meter
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  var (
    15  	halflife = time.Second
    16  	meters   = []struct {
    17  		name    string
    18  		factory Factory
    19  	}{
    20  		{
    21  			name:    "continuous",
    22  			factory: ContinuousFactory{},
    23  		},
    24  	}
    25  
    26  	meterTests = []struct {
    27  		name string
    28  		test func(*testing.T, Factory)
    29  	}{
    30  		{
    31  			name: "new",
    32  			test: NewTest,
    33  		},
    34  		{
    35  			name: "standard usage",
    36  			test: StandardUsageTest,
    37  		},
    38  		{
    39  			name: "time travel",
    40  			test: TimeTravelTest,
    41  		},
    42  	}
    43  )
    44  
    45  func TestMeters(t *testing.T) {
    46  	for _, s := range meters {
    47  		for _, test := range meterTests {
    48  			t.Run(fmt.Sprintf("meter %s test %s", s.name, test.name), func(t *testing.T) {
    49  				test.test(t, s.factory)
    50  			})
    51  		}
    52  	}
    53  }
    54  
    55  func NewTest(t *testing.T, factory Factory) {
    56  	require.NotNil(t, factory.New(halflife))
    57  }
    58  
    59  func TimeTravelTest(t *testing.T, factory Factory) {
    60  	require := require.New(t)
    61  
    62  	m := factory.New(halflife)
    63  
    64  	now := time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC)
    65  	m.Inc(now, 1)
    66  
    67  	now = now.Add(halflife - 1)
    68  	delta := 0.0001
    69  	require.InDelta(.5, m.Read(now), delta)
    70  
    71  	m.Dec(now, 1)
    72  
    73  	now = now.Add(-halflife)
    74  	require.InDelta(.5, m.Read(now), delta)
    75  
    76  	m.Inc(now, 1)
    77  
    78  	now = now.Add(halflife / 2)
    79  	require.InDelta(.5, m.Read(now), delta)
    80  }
    81  
    82  func StandardUsageTest(t *testing.T, factory Factory) {
    83  	require := require.New(t)
    84  
    85  	m := factory.New(halflife)
    86  
    87  	now := time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC)
    88  	m.Inc(now, 1)
    89  
    90  	now = now.Add(halflife - 1)
    91  	delta := 0.0001
    92  	require.InDelta(.5, m.Read(now), delta)
    93  
    94  	m.Inc(now, 1)
    95  	require.InDelta(.5, m.Read(now), delta)
    96  
    97  	m.Dec(now, 1)
    98  	require.InDelta(.5, m.Read(now), delta)
    99  
   100  	m.Dec(now, 1)
   101  
   102  	require.InDelta(.5, m.Read(now), delta)
   103  
   104  	now = now.Add(halflife)
   105  	require.InDelta(.25, m.Read(now), delta)
   106  
   107  	m.Inc(now, 1)
   108  
   109  	now = now.Add(halflife)
   110  	require.InDelta(.625, m.Read(now), delta)
   111  
   112  	now = now.Add(34 * halflife)
   113  	require.InDelta(1, m.Read(now), delta)
   114  
   115  	m.Dec(now, 1)
   116  
   117  	now = now.Add(34 * halflife)
   118  	require.InDelta(0, m.Read(now), delta)
   119  
   120  	m.Inc(now, 1)
   121  
   122  	now = now.Add(2 * halflife)
   123  	require.InDelta(.75, m.Read(now), delta)
   124  
   125  	// Second start
   126  	m.Inc(now, 1)
   127  
   128  	now = now.Add(34 * halflife)
   129  	require.InDelta(2, m.Read(now), delta)
   130  
   131  	// Stop the second CPU
   132  	m.Dec(now, 1)
   133  
   134  	now = now.Add(34 * halflife)
   135  	require.InDelta(1, m.Read(now), delta)
   136  }
   137  
   138  func TestTimeUntil(t *testing.T) {
   139  	require := require.New(t)
   140  
   141  	halflife := 5 * time.Second
   142  	f := ContinuousFactory{}
   143  	m := f.New(halflife)
   144  	now := time.Now()
   145  	// Start the meter
   146  	m.Inc(now, 1)
   147  	// One halflife passes; stop the meter
   148  	now = now.Add(halflife)
   149  	m.Dec(now, 1)
   150  	// Read the current value
   151  	currentVal := m.Read(now)
   152  	// Suppose we want to wait for the value to be
   153  	// a third of its current value
   154  	desiredVal := currentVal / 3
   155  	// See when that should happen
   156  	timeUntilDesiredVal := m.TimeUntil(now, desiredVal)
   157  	// Get the actual value at that time
   158  	now = now.Add(timeUntilDesiredVal)
   159  	actualVal := m.Read(now)
   160  	// Make sure the actual/expected are close
   161  	require.InDelta(desiredVal, actualVal, .00001)
   162  	// Make sure TimeUntil returns the zero duration if
   163  	// the value provided >= the current value
   164  	require.Zero(m.TimeUntil(now, actualVal))
   165  	require.Zero(m.TimeUntil(now, actualVal+.1))
   166  }