github.com/hashicorp/go-metrics@v0.5.3/start_test.go (about) 1 package metrics 2 3 import ( 4 "io/ioutil" 5 "log" 6 "reflect" 7 "sync/atomic" 8 "testing" 9 "time" 10 ) 11 12 func TestDefaultConfig(t *testing.T) { 13 conf := DefaultConfig("service") 14 if conf.ServiceName != "service" { 15 t.Fatalf("Bad name") 16 } 17 if conf.HostName == "" { 18 t.Fatalf("missing hostname") 19 } 20 if !conf.EnableHostname || !conf.EnableRuntimeMetrics { 21 t.Fatalf("expect true") 22 } 23 if conf.EnableTypePrefix { 24 t.Fatalf("expect false") 25 } 26 if conf.TimerGranularity != time.Millisecond { 27 t.Fatalf("bad granularity") 28 } 29 if conf.ProfileInterval != time.Second { 30 t.Fatalf("bad interval") 31 } 32 } 33 34 func Test_GlobalMetrics(t *testing.T) { 35 var tests = []struct { 36 desc string 37 key []string 38 val float32 39 fn func([]string, float32) 40 }{ 41 {"SetGauge", []string{"test"}, 42, SetGauge}, 42 {"EmitKey", []string{"test"}, 42, EmitKey}, 43 {"IncrCounter", []string{"test"}, 42, IncrCounter}, 44 {"AddSample", []string{"test"}, 42, AddSample}, 45 } 46 47 for _, tt := range tests { 48 t.Run(tt.desc, func(t *testing.T) { 49 s := &MockSink{} 50 globalMetrics.Store(&Metrics{Config: Config{FilterDefault: true}, sink: s}) 51 tt.fn(tt.key, tt.val) 52 if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) { 53 t.Fatalf("got key %s want %s", got, want) 54 } 55 if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) { 56 t.Fatalf("got val %v want %v", got, want) 57 } 58 }) 59 } 60 } 61 62 func Test_GlobalMetrics_Labels(t *testing.T) { 63 labels := []Label{{"a", "b"}} 64 var tests = []struct { 65 desc string 66 key []string 67 val float32 68 fn func([]string, float32, []Label) 69 labels []Label 70 }{ 71 {"SetGaugeWithLabels", []string{"test"}, 42, SetGaugeWithLabels, labels}, 72 {"IncrCounterWithLabels", []string{"test"}, 42, IncrCounterWithLabels, labels}, 73 {"AddSampleWithLabels", []string{"test"}, 42, AddSampleWithLabels, labels}, 74 } 75 76 for _, tt := range tests { 77 t.Run(tt.desc, func(t *testing.T) { 78 s := &MockSink{} 79 globalMetrics.Store(&Metrics{Config: Config{FilterDefault: true}, sink: s}) 80 tt.fn(tt.key, tt.val, tt.labels) 81 if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) { 82 t.Fatalf("got key %s want %s", got, want) 83 } 84 if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) { 85 t.Fatalf("got val %v want %v", got, want) 86 } 87 if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) { 88 t.Fatalf("got val %s want %s", got, want) 89 } 90 }) 91 } 92 } 93 94 func Test_GlobalPrecisionMetrics_Labels(t *testing.T) { 95 labels := []Label{{"a", "b"}} 96 var tests = []struct { 97 desc string 98 key []string 99 val float64 100 fn func([]string, float64, []Label) 101 labels []Label 102 }{ 103 {"SetPrecisionGaugeWithLabels", []string{"test"}, 42, SetPrecisionGaugeWithLabels, labels}, 104 } 105 106 for _, tt := range tests { 107 t.Run(tt.desc, func(t *testing.T) { 108 s := &MockSink{} 109 globalMetrics.Store(&Metrics{Config: Config{FilterDefault: true}, sink: s}) 110 tt.fn(tt.key, tt.val, tt.labels) 111 if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) { 112 t.Fatalf("got key %s want %s", got, want) 113 } 114 if got, want := s.precisionVals[0], tt.val; !reflect.DeepEqual(got, want) { 115 t.Fatalf("got val %v want %v", got, want) 116 } 117 if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) { 118 t.Fatalf("got val %s want %s", got, want) 119 } 120 }) 121 } 122 } 123 124 func Test_GlobalMetrics_DefaultLabels(t *testing.T) { 125 config := Config{ 126 HostName: "host1", 127 ServiceName: "redis", 128 EnableHostnameLabel: true, 129 EnableServiceLabel: true, 130 FilterDefault: true, 131 } 132 labels := []Label{ 133 {"host", config.HostName}, 134 {"service", config.ServiceName}, 135 } 136 var tests = []struct { 137 desc string 138 key []string 139 val float32 140 fn func([]string, float32, []Label) 141 labels []Label 142 }{ 143 {"SetGaugeWithLabels", []string{"test"}, 42, SetGaugeWithLabels, labels}, 144 {"IncrCounterWithLabels", []string{"test"}, 42, IncrCounterWithLabels, labels}, 145 {"AddSampleWithLabels", []string{"test"}, 42, AddSampleWithLabels, labels}, 146 } 147 148 for _, tt := range tests { 149 t.Run(tt.desc, func(t *testing.T) { 150 s := &MockSink{} 151 globalMetrics.Store(&Metrics{Config: config, sink: s}) 152 tt.fn(tt.key, tt.val, nil) 153 if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) { 154 t.Fatalf("got key %s want %s", got, want) 155 } 156 if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) { 157 t.Fatalf("got val %v want %v", got, want) 158 } 159 if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) { 160 t.Fatalf("got val %s want %s", got, want) 161 } 162 }) 163 } 164 } 165 166 func Test_GlobalPrecisionMetrics_DefaultLabels(t *testing.T) { 167 config := Config{ 168 HostName: "host1", 169 ServiceName: "redis", 170 EnableHostnameLabel: true, 171 EnableServiceLabel: true, 172 FilterDefault: true, 173 } 174 labels := []Label{ 175 {"host", config.HostName}, 176 {"service", config.ServiceName}, 177 } 178 var tests = []struct { 179 desc string 180 key []string 181 val float64 182 fn func([]string, float64, []Label) 183 labels []Label 184 }{ 185 {"SetGaugeWithLabels", []string{"test"}, 42, SetPrecisionGaugeWithLabels, labels}, 186 } 187 188 for _, tt := range tests { 189 t.Run(tt.desc, func(t *testing.T) { 190 s := &MockSink{} 191 globalMetrics.Store(&Metrics{Config: config, sink: s}) 192 tt.fn(tt.key, tt.val, nil) 193 if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) { 194 t.Fatalf("got key %s want %s", got, want) 195 } 196 if got, want := s.precisionVals[0], tt.val; !reflect.DeepEqual(got, want) { 197 t.Fatalf("got val %v want %v", got, want) 198 } 199 if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) { 200 t.Fatalf("got val %s want %s", got, want) 201 } 202 }) 203 } 204 } 205 206 func Test_GlobalMetrics_MeasureSince(t *testing.T) { 207 s := &MockSink{} 208 m := &Metrics{sink: s, Config: Config{TimerGranularity: time.Millisecond, FilterDefault: true}} 209 globalMetrics.Store(m) 210 211 k := []string{"test"} 212 now := time.Now() 213 MeasureSince(k, now) 214 215 if !reflect.DeepEqual(s.keys[0], k) { 216 t.Fatalf("key not equal") 217 } 218 if s.vals[0] > 0.1 { 219 t.Fatalf("val too large %v", s.vals[0]) 220 } 221 222 labels := []Label{{"a", "b"}} 223 MeasureSinceWithLabels(k, now, labels) 224 if got, want := s.keys[1], k; !reflect.DeepEqual(got, want) { 225 t.Fatalf("got key %s want %s", got, want) 226 } 227 if s.vals[1] > 0.1 { 228 t.Fatalf("val too large %v", s.vals[0]) 229 } 230 if got, want := s.labels[1], labels; !reflect.DeepEqual(got, want) { 231 t.Fatalf("got val %s want %s", got, want) 232 } 233 } 234 235 func Test_GlobalMetrics_UpdateFilter(t *testing.T) { 236 globalMetrics.Store(&Metrics{Config: Config{ 237 AllowedPrefixes: []string{"a"}, 238 BlockedPrefixes: []string{"b"}, 239 AllowedLabels: []string{"1"}, 240 BlockedLabels: []string{"2"}, 241 }}) 242 UpdateFilterAndLabels([]string{"c"}, []string{"d"}, []string{"3"}, []string{"4"}) 243 244 m := globalMetrics.Load().(*Metrics) 245 if m.AllowedPrefixes[0] != "c" { 246 t.Fatalf("bad: %v", m.AllowedPrefixes) 247 } 248 if m.BlockedPrefixes[0] != "d" { 249 t.Fatalf("bad: %v", m.BlockedPrefixes) 250 } 251 if m.AllowedLabels[0] != "3" { 252 t.Fatalf("bad: %v", m.AllowedPrefixes) 253 } 254 if m.BlockedLabels[0] != "4" { 255 t.Fatalf("bad: %v", m.AllowedPrefixes) 256 } 257 if _, ok := m.allowedLabels["3"]; !ok { 258 t.Fatalf("bad: %v", m.allowedLabels) 259 } 260 if _, ok := m.blockedLabels["4"]; !ok { 261 t.Fatalf("bad: %v", m.blockedLabels) 262 } 263 } 264 265 func Test_GlobalMetrics_Shutdown(t *testing.T) { 266 s := &MockSink{} 267 m := &Metrics{sink: s} 268 globalMetrics.Store(m) 269 270 Shutdown() 271 272 loaded := globalMetrics.Load() 273 metrics, ok := loaded.(*Metrics) 274 if !ok { 275 t.Fatalf("Expected globalMetrics to contain a Metrics pointer, but found: %v", loaded) 276 } 277 if metrics == m { 278 t.Errorf("Calling shutdown should have replaced the Metrics struct stored in globalMetrics") 279 } 280 if !s.shutdown { 281 t.Errorf("Expected Shutdown to have been called on MockSink") 282 } 283 } 284 285 // Benchmark_GlobalMetrics_Direct/direct-8 5000000 278 ns/op 286 // Benchmark_GlobalMetrics_Direct/atomic.Value-8 5000000 235 ns/op 287 func Benchmark_GlobalMetrics_Direct(b *testing.B) { 288 log.SetOutput(ioutil.Discard) 289 s := &MockSink{} 290 m := &Metrics{sink: s} 291 var v atomic.Value 292 v.Store(m) 293 k := []string{"test"} 294 b.Run("direct", func(b *testing.B) { 295 for i := 0; i < b.N; i++ { 296 m.IncrCounter(k, 1) 297 } 298 }) 299 b.Run("atomic.Value", func(b *testing.B) { 300 for i := 0; i < b.N; i++ { 301 v.Load().(*Metrics).IncrCounter(k, 1) 302 } 303 }) 304 // do something with m so that the compiler does not optimize this away 305 b.Logf("%d", m.lastNumGC) 306 }