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