github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/metric/metric_test.go (about)

     1  // Copyright 2015 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package metric
    12  
    13  import (
    14  	"bytes"
    15  	"encoding/json"
    16  	"reflect"
    17  	"sync"
    18  	"testing"
    19  	"time"
    20  
    21  	_ "github.com/cockroachdb/cockroach/pkg/util/log" // for flags
    22  	"github.com/kr/pretty"
    23  	prometheusgo "github.com/prometheus/client_model/go"
    24  )
    25  
    26  func testMarshal(t *testing.T, m json.Marshaler, exp string) {
    27  	if b, err := m.MarshalJSON(); err != nil || !bytes.Equal(b, []byte(exp)) {
    28  		t.Fatalf("unexpected: err=%v\nbytes=%s\nwanted=%s\nfor:\n%+v", err, b, exp, m)
    29  	}
    30  }
    31  
    32  var emptyMetadata = Metadata{Name: ""}
    33  
    34  func TestGauge(t *testing.T) {
    35  	g := NewGauge(emptyMetadata)
    36  	g.Update(10)
    37  	if v := g.Value(); v != 10 {
    38  		t.Fatalf("unexpected value: %d", v)
    39  	}
    40  	var wg sync.WaitGroup
    41  	for i := int64(0); i < 10; i++ {
    42  		wg.Add(2)
    43  		go func(i int64) { g.Inc(i); wg.Done() }(i)
    44  		go func(i int64) { g.Dec(i); wg.Done() }(i)
    45  	}
    46  	wg.Wait()
    47  	if v := g.Value(); v != 10 {
    48  		t.Fatalf("unexpected value: %d", v)
    49  	}
    50  	testMarshal(t, g, "10")
    51  }
    52  
    53  func TestFunctionalGauge(t *testing.T) {
    54  	valToReturn := int64(10)
    55  	g := NewFunctionalGauge(emptyMetadata, func() int64 { return valToReturn })
    56  	if v := g.Value(); v != 10 {
    57  		t.Fatalf("unexpected value: %d", v)
    58  	}
    59  	valToReturn = 15
    60  	if v := g.Value(); v != 15 {
    61  		t.Fatalf("unexpected value: %d", v)
    62  	}
    63  }
    64  
    65  func TestGaugeFloat64(t *testing.T) {
    66  	g := NewGaugeFloat64(emptyMetadata)
    67  	g.Update(10.4)
    68  	if v := g.Value(); v != 10.4 {
    69  		t.Fatalf("unexpected value: %f", v)
    70  	}
    71  	testMarshal(t, g, "10.4")
    72  }
    73  
    74  func TestRate(t *testing.T) {
    75  	r := NewRate(emptyMetadata, time.Minute)
    76  	r.Add(0)
    77  	if v := r.Value(); v != 0 {
    78  		t.Fatalf("unexpected value: %f", v)
    79  	}
    80  	testMarshal(t, r, "0")
    81  }
    82  
    83  func TestCounter(t *testing.T) {
    84  	c := NewCounter(emptyMetadata)
    85  	c.Inc(90)
    86  	if v := c.Count(); v != 90 {
    87  		t.Fatalf("unexpected value: %d", v)
    88  	}
    89  
    90  	testMarshal(t, c, "90")
    91  }
    92  
    93  func setNow(d time.Duration) {
    94  	now = func() time.Time {
    95  		return time.Time{}.Add(d)
    96  	}
    97  }
    98  
    99  func TestHistogramPrometheus(t *testing.T) {
   100  	u := func(v int) *uint64 {
   101  		n := uint64(v)
   102  		return &n
   103  	}
   104  
   105  	f := func(v int) *float64 {
   106  		n := float64(v)
   107  		return &n
   108  	}
   109  
   110  	h := NewHistogram(Metadata{}, time.Hour, 10, 1)
   111  	h.RecordValue(1)
   112  	h.RecordValue(5)
   113  	h.RecordValue(5)
   114  	h.RecordValue(10)
   115  	h.RecordValue(15000) // counts as 10
   116  	act := *h.ToPrometheusMetric().Histogram
   117  
   118  	expSum := float64(1*1 + 2*5 + 2*10)
   119  
   120  	exp := prometheusgo.Histogram{
   121  		SampleCount: u(5),
   122  		SampleSum:   &expSum,
   123  		Bucket: []*prometheusgo.Bucket{
   124  			{CumulativeCount: u(1), UpperBound: f(1)},
   125  			{CumulativeCount: u(3), UpperBound: f(5)},
   126  			{CumulativeCount: u(5), UpperBound: f(10)},
   127  		},
   128  	}
   129  
   130  	if !reflect.DeepEqual(act, exp) {
   131  		t.Fatalf("expected differs from actual: %s", pretty.Diff(exp, act))
   132  	}
   133  }
   134  
   135  func TestHistogramRotate(t *testing.T) {
   136  	defer TestingSetNow(nil)()
   137  	setNow(0)
   138  	duration := histWrapNum * time.Second
   139  	h := NewHistogram(emptyMetadata, duration, 1000+10*histWrapNum, 3)
   140  	var cur time.Duration
   141  	for i := 0; i < 3*histWrapNum; i++ {
   142  		v := int64(10 * i)
   143  		h.RecordValue(v)
   144  		cur += time.Second
   145  		setNow(cur)
   146  		cur, windowDuration := h.Windowed()
   147  		if windowDuration != duration {
   148  			t.Fatalf("window changed: is %s, should be %s", windowDuration, duration)
   149  		}
   150  
   151  		// When i == histWrapNum-1, we expect the entry from i==0 to move out
   152  		// of the window (since we rotated for the histWrapNum'th time).
   153  		expMin := int64((1 + i - (histWrapNum - 1)) * 10)
   154  		if expMin < 0 {
   155  			expMin = 0
   156  		}
   157  
   158  		if min := cur.Min(); min != expMin {
   159  			t.Fatalf("%d: unexpected minimum %d, expected %d", i, min, expMin)
   160  		}
   161  
   162  		if max, expMax := cur.Max(), v; max != expMax {
   163  			t.Fatalf("%d: unexpected maximum %d, expected %d", i, max, expMax)
   164  		}
   165  	}
   166  }
   167  
   168  func TestRateRotate(t *testing.T) {
   169  	defer TestingSetNow(nil)()
   170  	setNow(0)
   171  	const interval = 10 * time.Second
   172  	r := NewRate(emptyMetadata, interval)
   173  
   174  	// Skip the warmup phase of the wrapped EWMA for this test.
   175  	for i := 0; i < 100; i++ {
   176  		r.wrapped.Add(0)
   177  	}
   178  
   179  	// Put something nontrivial in.
   180  	r.Add(100)
   181  
   182  	for cur := time.Duration(0); cur < 5*interval; cur += time.Second / 2 {
   183  		prevVal := r.Value()
   184  		setNow(cur)
   185  		curVal := r.Value()
   186  		expChange := (cur % time.Second) != 0
   187  		hasChange := prevVal != curVal
   188  		if expChange != hasChange {
   189  			t.Fatalf("%s: expChange %t, hasChange %t (from %v to %v)",
   190  				cur, expChange, hasChange, prevVal, curVal)
   191  		}
   192  	}
   193  
   194  	v := r.Value()
   195  	if v > .1 {
   196  		t.Fatalf("final value implausible: %v", v)
   197  	}
   198  }