github.com/hashicorp/go-metrics@v0.5.3/inmem_test.go (about) 1 package metrics 2 3 import ( 4 "math" 5 "net/url" 6 "strings" 7 "testing" 8 "time" 9 ) 10 11 func TestInmemSink(t *testing.T) { 12 inm := NewInmemSink(10*time.Millisecond, 50*time.Millisecond) 13 14 data := inm.Data() 15 if len(data) != 1 { 16 t.Fatalf("bad: %v", data) 17 } 18 19 // Add data points 20 inm.SetGauge([]string{"foo", "bar"}, 42) 21 inm.SetGaugeWithLabels([]string{"foo", "bar"}, 23, []Label{{"a", "b"}}) 22 inm.EmitKey([]string{"foo", "bar"}, 42) 23 inm.IncrCounter([]string{"foo", "bar"}, 20) 24 inm.IncrCounter([]string{"foo", "bar"}, 22) 25 inm.IncrCounterWithLabels([]string{"foo", "bar"}, 20, []Label{{"a", "b"}}) 26 inm.IncrCounterWithLabels([]string{"foo", "bar"}, 22, []Label{{"a", "b"}}) 27 inm.AddSample([]string{"foo", "bar"}, 20) 28 inm.AddSample([]string{"foo", "bar"}, 22) 29 inm.AddSampleWithLabels([]string{"foo", "bar"}, 23, []Label{{"a", "b"}}) 30 31 data = inm.Data() 32 if len(data) != 1 { 33 t.Fatalf("bad: %v", data) 34 } 35 36 intvM := data[0] 37 intvM.RLock() 38 39 if time.Now().Sub(intvM.Interval) > 10*time.Millisecond { 40 t.Fatalf("interval too old") 41 } 42 if intvM.Gauges["foo.bar"].Value != 42 { 43 t.Fatalf("bad val: %v", intvM.Gauges) 44 } 45 if intvM.Gauges["foo.bar;a=b"].Value != 23 { 46 t.Fatalf("bad val: %v", intvM.Gauges) 47 } 48 if intvM.Points["foo.bar"][0] != 42 { 49 t.Fatalf("bad val: %v", intvM.Points) 50 } 51 52 for _, agg := range []SampledValue{intvM.Counters["foo.bar"], intvM.Counters["foo.bar;a=b"]} { 53 if agg.Count != 2 { 54 t.Fatalf("bad val: %v", agg) 55 } 56 if agg.Rate != 4200 { 57 t.Fatalf("bad val: %v", agg.Rate) 58 } 59 if agg.Sum != 42 { 60 t.Fatalf("bad val: %v", agg) 61 } 62 if agg.SumSq != 884 { 63 t.Fatalf("bad val: %v", agg) 64 } 65 if agg.Min != 20 { 66 t.Fatalf("bad val: %v", agg) 67 } 68 if agg.Max != 22 { 69 t.Fatalf("bad val: %v", agg) 70 } 71 if agg.AggregateSample.Mean() != 21 { 72 t.Fatalf("bad val: %v", agg) 73 } 74 if agg.AggregateSample.Stddev() != math.Sqrt(2) { 75 t.Fatalf("bad val: %v", agg) 76 } 77 78 if agg.LastUpdated.IsZero() { 79 t.Fatalf("agg.LastUpdated is not set: %v", agg) 80 } 81 82 diff := time.Now().Sub(agg.LastUpdated).Seconds() 83 if diff > 1 { 84 t.Fatalf("time diff too great: %f", diff) 85 } 86 } 87 88 if _, ok := intvM.Samples["foo.bar"]; !ok { 89 t.Fatalf("missing sample") 90 } 91 92 if _, ok := intvM.Samples["foo.bar;a=b"]; !ok { 93 t.Fatalf("missing sample") 94 } 95 96 intvM.RUnlock() 97 98 for i := 1; i < 10; i++ { 99 time.Sleep(10 * time.Millisecond) 100 inm.SetGauge([]string{"foo", "bar"}, 42) 101 data = inm.Data() 102 if len(data) != min(i+1, 5) { 103 t.Fatalf("bad: %v", data) 104 } 105 } 106 107 // Should not exceed 5 intervals! 108 time.Sleep(10 * time.Millisecond) 109 inm.SetGauge([]string{"foo", "bar"}, 42) 110 data = inm.Data() 111 if len(data) != 5 { 112 t.Fatalf("bad: %v", data) 113 } 114 } 115 116 func TestNewInmemSinkFromURL(t *testing.T) { 117 for _, tc := range []struct { 118 desc string 119 input string 120 expectErr string 121 expectInterval time.Duration 122 expectRetain time.Duration 123 }{ 124 { 125 desc: "interval and duration are set via query params", 126 input: "inmem://?interval=11s&retain=22s", 127 expectInterval: duration(t, "11s"), 128 expectRetain: duration(t, "22s"), 129 }, 130 { 131 desc: "interval is required", 132 input: "inmem://?retain=22s", 133 expectErr: "Bad 'interval' param", 134 }, 135 { 136 desc: "interval must be a duration", 137 input: "inmem://?retain=30s&interval=HIYA", 138 expectErr: "Bad 'interval' param", 139 }, 140 { 141 desc: "retain is required", 142 input: "inmem://?interval=30s", 143 expectErr: "Bad 'retain' param", 144 }, 145 { 146 desc: "retain must be a valid duration", 147 input: "inmem://?interval=30s&retain=HELLO", 148 expectErr: "Bad 'retain' param", 149 }, 150 } { 151 t.Run(tc.desc, func(t *testing.T) { 152 u, err := url.Parse(tc.input) 153 if err != nil { 154 t.Fatalf("error parsing URL: %s", err) 155 } 156 ms, err := NewInmemSinkFromURL(u) 157 if tc.expectErr != "" { 158 if !strings.Contains(err.Error(), tc.expectErr) { 159 t.Fatalf("expected err: %q, to contain: %q", err, tc.expectErr) 160 } 161 } else { 162 if err != nil { 163 t.Fatalf("unexpected err: %s", err) 164 } 165 is := ms.(*InmemSink) 166 if is.interval != tc.expectInterval { 167 t.Fatalf("expected interval %s, got: %s", tc.expectInterval, is.interval) 168 } 169 if is.retain != tc.expectRetain { 170 t.Fatalf("expected retain %s, got: %s", tc.expectRetain, is.retain) 171 } 172 } 173 }) 174 } 175 } 176 177 func min(a, b int) int { 178 if a < b { 179 return a 180 } 181 return b 182 } 183 184 func duration(t *testing.T, s string) time.Duration { 185 dur, err := time.ParseDuration(s) 186 if err != nil { 187 t.Fatalf("error parsing duration: %s", err) 188 } 189 return dur 190 }