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 }