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  }