github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/aggregator/aggregation/gauge_test.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package aggregation 22 23 import ( 24 "math" 25 "testing" 26 "time" 27 28 "github.com/m3db/m3/src/metrics/aggregation" 29 "github.com/m3db/m3/src/x/instrument" 30 31 "github.com/stretchr/testify/require" 32 "github.com/uber-go/tally" 33 ) 34 35 func TestGaugeDefaultAggregationType(t *testing.T) { 36 g := NewGauge(NewOptions(instrument.NewOptions())) 37 require.False(t, g.HasExpensiveAggregations) 38 for i := 1.0; i <= 100.0; i++ { 39 g.Update(time.Now(), i, nil) 40 } 41 require.Equal(t, 100.0, g.Last()) 42 require.Equal(t, 100.0, g.ValueOf(aggregation.Last)) 43 require.Equal(t, 100.0, g.ValueOf(aggregation.Count)) 44 require.Equal(t, 50.5, g.ValueOf(aggregation.Mean)) 45 require.Equal(t, 0.0, g.ValueOf(aggregation.SumSq)) 46 require.Equal(t, 100.0, g.ValueOf(aggregation.Max)) 47 require.Equal(t, 1.0, g.ValueOf(aggregation.Min)) 48 49 g = NewGauge(NewOptions(instrument.NewOptions())) 50 require.Equal(t, 0.0, g.Last()) 51 require.Equal(t, 0.0, g.ValueOf(aggregation.Last)) 52 require.Equal(t, 0.0, g.ValueOf(aggregation.Count)) 53 require.Equal(t, 0.0, g.ValueOf(aggregation.Mean)) 54 require.Equal(t, 0.0, g.ValueOf(aggregation.SumSq)) 55 require.True(t, math.IsNaN(g.ValueOf(aggregation.Max))) 56 require.True(t, math.IsNaN(g.ValueOf(aggregation.Min))) 57 } 58 59 func TestGauge_UpdatePrevious(t *testing.T) { 60 opts := NewOptions(instrument.NewOptions()) 61 opts.HasExpensiveAggregations = true 62 g := NewGauge(opts) 63 64 g.Update(time.Now(), 1.0, nil) 65 g.Update(time.Now(), 2.0, nil) 66 g.Update(time.Now(), 3.0, nil) 67 68 require.Equal(t, 3.0, g.Last()) 69 require.Equal(t, 3.0, g.ValueOf(aggregation.Last)) 70 require.Equal(t, 3.0, g.ValueOf(aggregation.Count)) 71 require.Equal(t, 2.0, g.ValueOf(aggregation.Mean)) 72 require.Equal(t, 14.0, g.ValueOf(aggregation.SumSq)) 73 require.Equal(t, 3.0, g.ValueOf(aggregation.Max)) 74 require.Equal(t, 1.0, g.ValueOf(aggregation.Min)) 75 76 g.UpdatePrevious(time.Now(), 4.0, 2.0) 77 78 require.Equal(t, 4.0, g.Last()) 79 require.Equal(t, 4.0, g.ValueOf(aggregation.Last)) 80 require.Equal(t, 3.0, g.ValueOf(aggregation.Count)) 81 require.Equal(t, 2.6666666666666665, g.ValueOf(aggregation.Mean)) 82 require.Equal(t, 26.0, g.ValueOf(aggregation.SumSq)) 83 // max updated. 84 require.Equal(t, 4.0, g.ValueOf(aggregation.Max)) 85 // min does not change. 86 require.Equal(t, 1.0, g.ValueOf(aggregation.Min)) 87 88 g.UpdatePrevious(time.Now(), 0.0, 3.0) 89 require.Equal(t, 0.0, g.Last()) 90 require.Equal(t, 0.0, g.ValueOf(aggregation.Last)) 91 require.Equal(t, 3.0, g.ValueOf(aggregation.Count)) 92 require.Equal(t, 5.0/3.0, g.ValueOf(aggregation.Mean)) 93 require.Equal(t, 17.0, g.ValueOf(aggregation.SumSq)) 94 require.Equal(t, 4.0, g.ValueOf(aggregation.Max)) 95 // min updated. 96 require.Equal(t, 0.0, g.ValueOf(aggregation.Min)) 97 } 98 99 func TestGaugeReturnsLastNonEmptyAnnotation(t *testing.T) { 100 g := NewGauge(NewOptions(instrument.NewOptions())) 101 g.Update(time.Now(), 1.1, []byte("first")) 102 g.Update(time.Now(), 2.1, []byte("second")) 103 g.Update(time.Now(), 3.1, nil) 104 105 require.Equal(t, []byte("second"), g.Annotation()) 106 } 107 108 func TestGaugeCustomAggregationType(t *testing.T) { 109 opts := NewOptions(instrument.NewOptions()) 110 opts.HasExpensiveAggregations = true 111 112 g := NewGauge(opts) 113 require.True(t, g.HasExpensiveAggregations) 114 115 for i := 1; i <= 100; i++ { 116 g.Update(time.Now(), float64(i), nil) 117 } 118 119 require.Equal(t, 100.0, g.Last()) 120 for aggType := range aggregation.ValidTypes { 121 v := g.ValueOf(aggType) 122 switch aggType { 123 case aggregation.Last: 124 require.Equal(t, float64(100), v) 125 case aggregation.Min: 126 require.Equal(t, float64(1), v) 127 case aggregation.Max: 128 require.Equal(t, float64(100), v) 129 case aggregation.Mean: 130 require.Equal(t, float64(50.5), v) 131 case aggregation.Count: 132 require.Equal(t, float64(100), v) 133 case aggregation.Sum: 134 require.Equal(t, float64(5050), v) 135 case aggregation.SumSq: 136 require.Equal(t, float64(338350), v) 137 case aggregation.Stdev: 138 require.InDelta(t, 29.01149, v, 0.001) 139 default: 140 require.Equal(t, float64(0), v) 141 require.False(t, aggType.IsValidForGauge()) 142 } 143 } 144 145 g = NewGauge(opts) 146 require.Equal(t, 0.0, g.Last()) 147 for aggType := range aggregation.ValidTypes { 148 v := g.ValueOf(aggType) 149 switch aggType { 150 case aggregation.Last: 151 require.Equal(t, 0.0, v) 152 case aggregation.Min: 153 require.True(t, math.IsNaN(v)) 154 case aggregation.Max: 155 require.True(t, math.IsNaN(v)) 156 case aggregation.Mean: 157 require.Equal(t, 0.0, v) 158 case aggregation.Count: 159 require.Equal(t, 0.0, v) 160 case aggregation.Sum: 161 require.Equal(t, 0.0, v) 162 case aggregation.SumSq: 163 require.Equal(t, 0.0, v) 164 case aggregation.Stdev: 165 require.InDelta(t, 0.0, v, 0.0) 166 default: 167 require.Equal(t, 0.0, v) 168 require.False(t, aggType.IsValidForGauge()) 169 } 170 } 171 } 172 173 func TestGaugeLastOutOfOrderValues(t *testing.T) { 174 scope := tally.NewTestScope("", nil) 175 g := NewGauge(NewOptions(instrument.NewOptions().SetMetricsScope(scope))) 176 177 timeMid := time.Now().Add(time.Minute) 178 timePre := timeMid.Add(-1 * time.Second) 179 timePrePre := timeMid.Add(-1 * time.Second) 180 timeAfter := timeMid.Add(time.Second) 181 182 g.Update(timeMid, 42, nil) 183 g.Update(timePre, 41, nil) 184 g.Update(timeAfter, 43, nil) 185 g.Update(timePrePre, 40, nil) 186 187 require.Equal(t, 43.0, g.Last()) 188 snap := scope.Snapshot() 189 counters := snap.Counters() 190 counter, ok := counters["aggregation.gauges.values-out-of-order+"] 191 require.True(t, ok) 192 require.Equal(t, int64(2), counter.Value()) 193 }