github.com/XiaoMi/Gaea@v1.2.5/stats/rates_test.go (about) 1 /* 2 Copyright 2017 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package stats 18 19 import ( 20 "expvar" 21 "testing" 22 "time" 23 ) 24 25 // For tests, we want to control exactly the time used by Rates. 26 // The way Rates works is: 27 // - at creation, do a snapshot. 28 // - every interval, do a snapshot. 29 // So in these tests, we make sure to always call snapshot() every interval. 30 // We do other actions after epsilon, but then wait for intervalMinusEpsilon 31 // and call snapshot(). 32 const ( 33 interval = 1 * time.Second 34 epsilon = 50 * time.Millisecond 35 intervalMinusEpsilon = interval - epsilon 36 ) 37 38 func TestRates(t *testing.T) { 39 now := time.Now() 40 timeNow = func() time.Time { 41 return now 42 } 43 44 clear() 45 c := NewCountersWithSingleLabel("rcounter1", "rcounter help", "label") 46 r := NewRates("rates1", c, 3, -1*time.Second) 47 r.snapshot() 48 now = now.Add(epsilon) 49 c.Add("tag1", 0) 50 c.Add("tag2", 0) 51 now = now.Add(intervalMinusEpsilon) 52 r.snapshot() 53 now = now.Add(epsilon) 54 checkRates(t, r, "after 1s", 0.0, `{"tag1":[0],"tag2":[0]}`) 55 56 c.Add("tag1", 10) 57 c.Add("tag2", 20) 58 now = now.Add(intervalMinusEpsilon) 59 r.snapshot() 60 now = now.Add(epsilon) 61 checkRates(t, r, "after 2s", 30.0, `{"tag1":[0,10],"tag2":[0,20]}`) 62 63 now = now.Add(intervalMinusEpsilon) 64 r.snapshot() 65 now = now.Add(epsilon) 66 checkRates(t, r, "after 3s", 0.0, `{"tag1":[0,10,0],"tag2":[0,20,0]}`) 67 68 now = now.Add(intervalMinusEpsilon) 69 r.snapshot() 70 now = now.Add(epsilon) 71 checkRates(t, r, "after 4s", 0.0, `{"tag1":[10,0,0],"tag2":[20,0,0]}`) 72 } 73 74 func checkRates(t *testing.T, r *Rates, desc string, wantRate float64, wantRateMap string) { 75 if got := r.String(); got != wantRateMap { 76 t.Errorf("%v: want %s, got %s", desc, wantRateMap, got) 77 } 78 if got := r.TotalRate(); got != wantRate { 79 t.Errorf("%v: want rate %v, got rate %v", desc, wantRate, got) 80 } 81 } 82 83 func TestRatesConsistency(t *testing.T) { 84 now := time.Now() 85 timeNow = func() time.Time { 86 return now 87 } 88 89 // This tests the following invariant: in the time window 90 // covered by rates, the sum of the rates reported must be 91 // equal to the count reported by the counter. 92 clear() 93 c := NewCountersWithSingleLabel("rcounter4", "rcounter4 help", "label") 94 r := NewRates("rates4", c, 100, -1*time.Second) 95 r.snapshot() 96 97 now = now.Add(epsilon) 98 c.Add("a", 1000) 99 now = now.Add(intervalMinusEpsilon) 100 r.snapshot() 101 now = now.Add(epsilon) 102 c.Add("a", 1) 103 now = now.Add(intervalMinusEpsilon) 104 r.snapshot() 105 now = now.Add(epsilon) 106 107 result := r.Get() 108 counts := c.Counts() 109 t.Logf("r.Get(): %v", result) 110 t.Logf("c.Counts(): %v", counts) 111 112 rate, count := result["a"], counts["a"] 113 114 var sum float64 115 for _, v := range rate { 116 sum += v 117 } 118 if sum != float64(counts["a"]) { 119 t.Errorf("rate inconsistent with count: sum of %v != %v", rate, count) 120 } 121 122 } 123 124 func TestRatesHook(t *testing.T) { 125 clear() 126 c := NewCountersWithSingleLabel("rcounter2", "rcounter2 help", "label") 127 var gotname string 128 var gotv *Rates 129 clear() 130 Register(func(name string, v expvar.Var) { 131 gotname = name 132 gotv = v.(*Rates) 133 }) 134 135 v := NewRates("rates2", c, 2, 10*time.Second) 136 if gotname != "rates2" { 137 t.Errorf("want rates2, got %s", gotname) 138 } 139 if gotv != v { 140 t.Errorf("want %#v, got %#v", v, gotv) 141 } 142 }