github.com/hashicorp/go-metrics@v0.5.3/metrics_test.go (about) 1 package metrics 2 3 import ( 4 "reflect" 5 "runtime" 6 "testing" 7 "time" 8 ) 9 10 func mockMetric() (*MockSink, *Metrics) { 11 m := &MockSink{} 12 met := &Metrics{Config: Config{FilterDefault: true}, sink: m} 13 return m, met 14 } 15 16 func TestMetrics_SetGauge(t *testing.T) { 17 m, met := mockMetric() 18 met.SetGauge([]string{"key"}, float32(1)) 19 if m.getKeys()[0][0] != "key" { 20 t.Fatalf("") 21 } 22 if m.vals[0] != 1 { 23 t.Fatalf("") 24 } 25 26 m, met = mockMetric() 27 labels := []Label{{"a", "b"}} 28 met.SetGaugeWithLabels([]string{"key"}, float32(1), labels) 29 if m.getKeys()[0][0] != "key" { 30 t.Fatalf("") 31 } 32 if m.vals[0] != 1 { 33 t.Fatalf("") 34 } 35 if !reflect.DeepEqual(m.labels[0], labels) { 36 t.Fatalf("") 37 } 38 39 m, met = mockMetric() 40 met.HostName = "test" 41 met.EnableHostname = true 42 met.SetGauge([]string{"key"}, float32(1)) 43 if m.getKeys()[0][0] != "test" || m.getKeys()[0][1] != "key" { 44 t.Fatalf("") 45 } 46 if m.vals[0] != 1 { 47 t.Fatalf("") 48 } 49 50 m, met = mockMetric() 51 met.EnableTypePrefix = true 52 met.SetGauge([]string{"key"}, float32(1)) 53 if m.getKeys()[0][0] != "gauge" || m.getKeys()[0][1] != "key" { 54 t.Fatalf("") 55 } 56 if m.vals[0] != 1 { 57 t.Fatalf("") 58 } 59 60 m, met = mockMetric() 61 met.ServiceName = "service" 62 met.SetGauge([]string{"key"}, float32(1)) 63 if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" { 64 t.Fatalf("") 65 } 66 if m.vals[0] != 1 { 67 t.Fatalf("") 68 } 69 } 70 71 func TestMetrics_SetPrecisionGauge(t *testing.T) { 72 m, met := mockMetric() 73 met.SetPrecisionGauge([]string{"key"}, float64(1)) 74 if m.getKeys()[0][0] != "key" { 75 t.Fatalf("") 76 } 77 if m.precisionVals[0] != 1 { 78 t.Fatalf("") 79 } 80 81 m, met = mockMetric() 82 labels := []Label{{"a", "b"}} 83 met.SetPrecisionGaugeWithLabels([]string{"key"}, float64(1), labels) 84 if m.getKeys()[0][0] != "key" { 85 t.Fatalf("") 86 } 87 if m.precisionVals[0] != 1 { 88 t.Fatalf("") 89 } 90 if !reflect.DeepEqual(m.labels[0], labels) { 91 t.Fatalf("") 92 } 93 94 m, met = mockMetric() 95 met.HostName = "test" 96 met.EnableHostname = true 97 met.SetPrecisionGauge([]string{"key"}, float64(1)) 98 if m.getKeys()[0][0] != "test" || m.getKeys()[0][1] != "key" { 99 t.Fatalf("") 100 } 101 if m.precisionVals[0] != 1 { 102 t.Fatalf("") 103 } 104 105 m, met = mockMetric() 106 met.EnableTypePrefix = true 107 met.SetPrecisionGauge([]string{"key"}, float64(1)) 108 if m.getKeys()[0][0] != "gauge" || m.getKeys()[0][1] != "key" { 109 t.Fatalf("") 110 } 111 if m.precisionVals[0] != 1 { 112 t.Fatalf("") 113 } 114 115 m, met = mockMetric() 116 met.ServiceName = "service" 117 met.SetPrecisionGauge([]string{"key"}, float64(1)) 118 if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" { 119 t.Fatalf("") 120 } 121 if m.precisionVals[0] != 1 { 122 t.Fatalf("") 123 } 124 } 125 126 func TestMetrics_EmitKey(t *testing.T) { 127 m, met := mockMetric() 128 met.EmitKey([]string{"key"}, float32(1)) 129 if m.getKeys()[0][0] != "key" { 130 t.Fatalf("") 131 } 132 if m.vals[0] != 1 { 133 t.Fatalf("") 134 } 135 136 m, met = mockMetric() 137 met.EnableTypePrefix = true 138 met.EmitKey([]string{"key"}, float32(1)) 139 if m.getKeys()[0][0] != "kv" || m.getKeys()[0][1] != "key" { 140 t.Fatalf("") 141 } 142 if m.vals[0] != 1 { 143 t.Fatalf("") 144 } 145 146 m, met = mockMetric() 147 met.ServiceName = "service" 148 met.EmitKey([]string{"key"}, float32(1)) 149 if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" { 150 t.Fatalf("") 151 } 152 if m.vals[0] != 1 { 153 t.Fatalf("") 154 } 155 } 156 157 func TestMetrics_IncrCounter(t *testing.T) { 158 m, met := mockMetric() 159 met.IncrCounter([]string{"key"}, float32(1)) 160 if m.getKeys()[0][0] != "key" { 161 t.Fatalf("") 162 } 163 if m.vals[0] != 1 { 164 t.Fatalf("") 165 } 166 167 m, met = mockMetric() 168 labels := []Label{{"a", "b"}} 169 met.IncrCounterWithLabels([]string{"key"}, float32(1), labels) 170 if m.getKeys()[0][0] != "key" { 171 t.Fatalf("") 172 } 173 if m.vals[0] != 1 { 174 t.Fatalf("") 175 } 176 if !reflect.DeepEqual(m.labels[0], labels) { 177 t.Fatalf("") 178 } 179 180 m, met = mockMetric() 181 met.EnableTypePrefix = true 182 met.IncrCounter([]string{"key"}, float32(1)) 183 if m.getKeys()[0][0] != "counter" || m.getKeys()[0][1] != "key" { 184 t.Fatalf("") 185 } 186 if m.vals[0] != 1 { 187 t.Fatalf("") 188 } 189 190 m, met = mockMetric() 191 met.ServiceName = "service" 192 met.IncrCounter([]string{"key"}, float32(1)) 193 if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" { 194 t.Fatalf("") 195 } 196 if m.vals[0] != 1 { 197 t.Fatalf("") 198 } 199 } 200 201 func TestMetrics_AddSample(t *testing.T) { 202 m, met := mockMetric() 203 met.AddSample([]string{"key"}, float32(1)) 204 if m.getKeys()[0][0] != "key" { 205 t.Fatalf("") 206 } 207 if m.vals[0] != 1 { 208 t.Fatalf("") 209 } 210 211 m, met = mockMetric() 212 labels := []Label{{"a", "b"}} 213 met.AddSampleWithLabels([]string{"key"}, float32(1), labels) 214 if m.getKeys()[0][0] != "key" { 215 t.Fatalf("") 216 } 217 if m.vals[0] != 1 { 218 t.Fatalf("") 219 } 220 if !reflect.DeepEqual(m.labels[0], labels) { 221 t.Fatalf("") 222 } 223 224 m, met = mockMetric() 225 met.EnableTypePrefix = true 226 met.AddSample([]string{"key"}, float32(1)) 227 if m.getKeys()[0][0] != "sample" || m.getKeys()[0][1] != "key" { 228 t.Fatalf("") 229 } 230 if m.vals[0] != 1 { 231 t.Fatalf("") 232 } 233 234 m, met = mockMetric() 235 met.ServiceName = "service" 236 met.AddSample([]string{"key"}, float32(1)) 237 if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" { 238 t.Fatalf("") 239 } 240 if m.vals[0] != 1 { 241 t.Fatalf("") 242 } 243 } 244 245 func TestMetrics_MeasureSince(t *testing.T) { 246 m, met := mockMetric() 247 met.TimerGranularity = time.Millisecond 248 n := time.Now() 249 met.MeasureSince([]string{"key"}, n) 250 if m.getKeys()[0][0] != "key" { 251 t.Fatalf("") 252 } 253 if m.vals[0] > 0.1 { 254 t.Fatalf("") 255 } 256 257 m, met = mockMetric() 258 met.TimerGranularity = time.Millisecond 259 labels := []Label{{"a", "b"}} 260 met.MeasureSinceWithLabels([]string{"key"}, n, labels) 261 if m.getKeys()[0][0] != "key" { 262 t.Fatalf("") 263 } 264 if m.vals[0] > 0.1 { 265 t.Fatalf("") 266 } 267 if !reflect.DeepEqual(m.labels[0], labels) { 268 t.Fatalf("") 269 } 270 271 m, met = mockMetric() 272 met.TimerGranularity = time.Millisecond 273 met.EnableTypePrefix = true 274 met.MeasureSince([]string{"key"}, n) 275 if m.getKeys()[0][0] != "timer" || m.getKeys()[0][1] != "key" { 276 t.Fatalf("") 277 } 278 if m.vals[0] > 0.1 { 279 t.Fatalf("") 280 } 281 282 m, met = mockMetric() 283 met.TimerGranularity = time.Millisecond 284 met.ServiceName = "service" 285 met.MeasureSince([]string{"key"}, n) 286 if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" { 287 t.Fatalf("") 288 } 289 if m.vals[0] > 0.1 { 290 t.Fatalf("") 291 } 292 } 293 294 func TestMetrics_EmitRuntimeStats(t *testing.T) { 295 runtime.GC() 296 m, met := mockMetric() 297 met.EmitRuntimeStats() 298 299 if m.getKeys()[0][0] != "runtime" || m.getKeys()[0][1] != "num_goroutines" { 300 t.Fatalf("bad key %v", m.getKeys()) 301 } 302 if m.vals[0] <= 1 { 303 t.Fatalf("bad val: %v", m.vals) 304 } 305 306 if m.getKeys()[1][0] != "runtime" || m.getKeys()[1][1] != "alloc_bytes" { 307 t.Fatalf("bad key %v", m.getKeys()) 308 } 309 if m.vals[1] <= 40000 { 310 t.Fatalf("bad val: %v", m.vals) 311 } 312 313 if m.getKeys()[2][0] != "runtime" || m.getKeys()[2][1] != "sys_bytes" { 314 t.Fatalf("bad key %v", m.getKeys()) 315 } 316 if m.vals[2] <= 100000 { 317 t.Fatalf("bad val: %v", m.vals) 318 } 319 320 if m.getKeys()[3][0] != "runtime" || m.getKeys()[3][1] != "malloc_count" { 321 t.Fatalf("bad key %v", m.getKeys()) 322 } 323 if m.vals[3] <= 100 { 324 t.Fatalf("bad val: %v", m.vals) 325 } 326 327 if m.getKeys()[4][0] != "runtime" || m.getKeys()[4][1] != "free_count" { 328 t.Fatalf("bad key %v", m.getKeys()) 329 } 330 if m.vals[4] <= 100 { 331 t.Fatalf("bad val: %v", m.vals) 332 } 333 334 if m.getKeys()[5][0] != "runtime" || m.getKeys()[5][1] != "heap_objects" { 335 t.Fatalf("bad key %v", m.getKeys()) 336 } 337 if m.vals[5] <= 100 { 338 t.Fatalf("bad val: %v", m.vals) 339 } 340 341 if m.getKeys()[6][0] != "runtime" || m.getKeys()[6][1] != "total_gc_pause_ns" { 342 t.Fatalf("bad key %v", m.getKeys()) 343 } 344 if m.vals[6] <= 100 { 345 t.Fatalf("bad val: %v\nkeys: %v", m.vals, m.getKeys()) 346 } 347 348 if m.getKeys()[7][0] != "runtime" || m.getKeys()[7][1] != "total_gc_runs" { 349 t.Fatalf("bad key %v", m.getKeys()) 350 } 351 if m.vals[7] < 1 { 352 t.Fatalf("bad val: %v", m.vals) 353 } 354 355 if m.getKeys()[8][0] != "runtime" || m.getKeys()[8][1] != "gc_pause_ns" { 356 t.Fatalf("bad key %v", m.getKeys()) 357 } 358 if m.vals[8] <= 1000 { 359 t.Fatalf("bad val: %v", m.vals) 360 } 361 } 362 363 func TestInsert(t *testing.T) { 364 k := []string{"hi", "bob"} 365 exp := []string{"hi", "there", "bob"} 366 out := insert(1, "there", k) 367 if !reflect.DeepEqual(exp, out) { 368 t.Fatalf("bad insert %v %v", exp, out) 369 } 370 } 371 372 func TestMetrics_Filter_Blacklist(t *testing.T) { 373 m := &MockSink{} 374 conf := DefaultConfig("") 375 conf.AllowedPrefixes = []string{"service", "debug.thing"} 376 conf.BlockedPrefixes = []string{"debug"} 377 conf.EnableHostname = false 378 met, err := New(conf, m) 379 if err != nil { 380 t.Fatal(err) 381 } 382 383 // Allowed by default 384 key := []string{"thing"} 385 met.SetGauge(key, 1) 386 if !reflect.DeepEqual(m.getKeys()[0], key) { 387 t.Fatalf("key doesn't exist %v, %v", m.getKeys()[0], key) 388 } 389 if m.vals[0] != 1 { 390 t.Fatalf("bad val: %v", m.vals[0]) 391 } 392 393 // Allowed by filter 394 key = []string{"service", "thing"} 395 met.SetGauge(key, 2) 396 if !reflect.DeepEqual(m.getKeys()[1], key) { 397 t.Fatalf("key doesn't exist") 398 } 399 if m.vals[1] != 2 { 400 t.Fatalf("bad val: %v", m.vals[1]) 401 } 402 403 // Allowed by filter, subtree of a blocked entry 404 key = []string{"debug", "thing"} 405 met.SetGauge(key, 3) 406 if !reflect.DeepEqual(m.getKeys()[2], key) { 407 t.Fatalf("key doesn't exist") 408 } 409 if m.vals[2] != 3 { 410 t.Fatalf("bad val: %v", m.vals[2]) 411 } 412 413 // Blocked by filter 414 key = []string{"debug", "other-thing"} 415 met.SetGauge(key, 4) 416 if len(m.getKeys()) != 3 { 417 t.Fatalf("key shouldn't exist") 418 } 419 } 420 421 func HasElem(s interface{}, elem interface{}) bool { 422 arrV := reflect.ValueOf(s) 423 424 if arrV.Kind() == reflect.Slice { 425 for i := 0; i < arrV.Len(); i++ { 426 if arrV.Index(i).Interface() == elem { 427 return true 428 } 429 } 430 } 431 432 return false 433 } 434 435 func TestMetrics_Filter_Whitelist(t *testing.T) { 436 m := &MockSink{} 437 conf := DefaultConfig("") 438 conf.AllowedPrefixes = []string{"service", "debug.thing"} 439 conf.BlockedPrefixes = []string{"debug"} 440 conf.FilterDefault = false 441 conf.EnableHostname = false 442 conf.BlockedLabels = []string{"bad_label"} 443 met, err := New(conf, m) 444 if err != nil { 445 t.Fatal(err) 446 } 447 448 // Blocked by default 449 key := []string{"thing"} 450 met.SetGauge(key, 1) 451 if len(m.getKeys()) != 0 { 452 t.Fatalf("key should not exist") 453 } 454 455 // Allowed by filter 456 key = []string{"service", "thing"} 457 met.SetGauge(key, 2) 458 if !reflect.DeepEqual(m.getKeys()[0], key) { 459 t.Fatalf("key doesn't exist") 460 } 461 if m.vals[0] != 2 { 462 t.Fatalf("bad val: %v", m.vals[0]) 463 } 464 465 // Allowed by filter, subtree of a blocked entry 466 key = []string{"debug", "thing"} 467 met.SetGauge(key, 3) 468 if !reflect.DeepEqual(m.getKeys()[1], key) { 469 t.Fatalf("key doesn't exist") 470 } 471 if m.vals[1] != 3 { 472 t.Fatalf("bad val: %v", m.vals[1]) 473 } 474 475 // Blocked by filter 476 key = []string{"debug", "other-thing"} 477 met.SetGauge(key, 4) 478 if len(m.getKeys()) != 2 { 479 t.Fatalf("key shouldn't exist") 480 } 481 // Test blacklisting of labels 482 key = []string{"debug", "thing"} 483 goodLabel := Label{Name: "good", Value: "should be present"} 484 badLabel := Label{Name: "bad_label", Value: "should not be there"} 485 labels := []Label{badLabel, goodLabel} 486 met.SetGaugeWithLabels(key, 3, labels) 487 if !reflect.DeepEqual(m.getKeys()[1], key) { 488 t.Fatalf("key doesn't exist") 489 } 490 if m.vals[2] != 3 { 491 t.Fatalf("bad val: %v", m.vals[1]) 492 } 493 if HasElem(m.labels[2], badLabel) { 494 t.Fatalf("bad_label should not be present in %v", m.labels[2]) 495 } 496 if !HasElem(m.labels[2], goodLabel) { 497 t.Fatalf("good label is not present in %v", m.labels[2]) 498 } 499 } 500 501 func TestMetrics_Filter_Labels_Whitelist(t *testing.T) { 502 m := &MockSink{} 503 conf := DefaultConfig("") 504 conf.AllowedPrefixes = []string{"service", "debug.thing"} 505 conf.BlockedPrefixes = []string{"debug"} 506 conf.FilterDefault = false 507 conf.EnableHostname = false 508 conf.AllowedLabels = []string{"good_label"} 509 conf.BlockedLabels = []string{"bad_label"} 510 met, err := New(conf, m) 511 if err != nil { 512 t.Fatal(err) 513 } 514 515 // Blocked by default 516 key := []string{"thing"} 517 key = []string{"debug", "thing"} 518 goodLabel := Label{Name: "good_label", Value: "should be present"} 519 notReallyGoodLabel := Label{Name: "not_really_good_label", Value: "not whitelisted, but not blacklisted"} 520 badLabel := Label{Name: "bad_label", Value: "should not be there"} 521 labels := []Label{badLabel, notReallyGoodLabel, goodLabel} 522 met.SetGaugeWithLabels(key, 1, labels) 523 524 if HasElem(m.labels[0], badLabel) { 525 t.Fatalf("bad_label should not be present in %v", m.labels[0]) 526 } 527 if HasElem(m.labels[0], notReallyGoodLabel) { 528 t.Fatalf("not_really_good_label should not be present in %v", m.labels[0]) 529 } 530 if !HasElem(m.labels[0], goodLabel) { 531 t.Fatalf("good label is not present in %v", m.labels[0]) 532 } 533 534 conf.AllowedLabels = nil 535 met.UpdateFilterAndLabels(conf.AllowedPrefixes, conf.BlockedLabels, conf.AllowedLabels, conf.BlockedLabels) 536 met.SetGaugeWithLabels(key, 1, labels) 537 538 if HasElem(m.labels[1], badLabel) { 539 t.Fatalf("bad_label should not be present in %v", m.labels[1]) 540 } 541 // Since no whitelist, not_really_good_label should be there 542 if !HasElem(m.labels[1], notReallyGoodLabel) { 543 t.Fatalf("not_really_good_label is not present in %v", m.labels[1]) 544 } 545 if !HasElem(m.labels[1], goodLabel) { 546 t.Fatalf("good label is not present in %v", m.labels[1]) 547 } 548 } 549 550 func TestMetrics_Filter_Labels_ModifyArgs(t *testing.T) { 551 m := &MockSink{} 552 conf := DefaultConfig("") 553 conf.FilterDefault = false 554 conf.EnableHostname = false 555 conf.AllowedLabels = []string{"keep"} 556 conf.BlockedLabels = []string{"delete"} 557 met, err := New(conf, m) 558 if err != nil { 559 t.Fatal(err) 560 } 561 562 // Blocked by default 563 key := []string{"thing"} 564 key = []string{"debug", "thing"} 565 goodLabel := Label{Name: "keep", Value: "should be kept"} 566 badLabel := Label{Name: "delete", Value: "should be deleted"} 567 argLabels := []Label{badLabel, goodLabel, badLabel, goodLabel, badLabel, goodLabel, badLabel} 568 origLabels := append([]Label{}, argLabels...) 569 met.SetGaugeWithLabels(key, 1, argLabels) 570 571 if !reflect.DeepEqual(argLabels, origLabels) { 572 t.Fatalf("SetGaugeWithLabels modified the input argument") 573 } 574 }