github.com/thanos-io/thanos@v0.32.5/pkg/store/labelpb/label_test.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package labelpb 5 6 import ( 7 "fmt" 8 "io" 9 "reflect" 10 "sort" 11 "strings" 12 "testing" 13 14 "github.com/prometheus/prometheus/model/labels" 15 16 "github.com/efficientgo/core/testutil" 17 ) 18 19 var testLsetMap = map[string]string{ 20 "a": "1", 21 "c": "2", 22 "d": "dsfsdfsdfsdf123414234", 23 "124134235423534534ffdasdfsf": "1", 24 "": "", 25 "b": "", 26 } 27 28 func TestLabelsToPromLabels_LabelsToPromLabels(t *testing.T) { 29 testutil.Equals(t, labels.FromMap(testLsetMap), ZLabelsToPromLabels(ZLabelsFromPromLabels(labels.FromMap(testLsetMap)))) 30 31 lset := labels.FromMap(testLsetMap) 32 for i := range ZLabelsFromPromLabels(lset) { 33 if lset[i].Name != "a" { 34 continue 35 } 36 lset[i].Value += "yolo" 37 38 } 39 m := lset.Map() 40 testutil.Equals(t, "1yolo", m["a"]) 41 42 m["a"] = "1" 43 testutil.Equals(t, testLsetMap, m) 44 } 45 46 func TestLabelMarshal_Unmarshal(t *testing.T) { 47 l := ZLabelsFromPromLabels(labels.FromStrings("aaaaaaa", "bbbbb"))[0] 48 b, err := (&l).Marshal() 49 testutil.Ok(t, err) 50 51 l2 := &ZLabel{} 52 testutil.Ok(t, l2.Unmarshal(b)) 53 testutil.Equals(t, labels.FromStrings("aaaaaaa", "bbbbb"), ZLabelsToPromLabels([]ZLabel{*l2})) 54 } 55 56 func TestExtendLabels(t *testing.T) { 57 testutil.Equals(t, labels.Labels{{Name: "a", Value: "1"}, {Name: "replica", Value: "01"}, {Name: "xb", Value: "2"}}, 58 ExtendSortedLabels(labels.Labels{{Name: "a", Value: "1"}, {Name: "xb", Value: "2"}}, labels.FromStrings("replica", "01"))) 59 60 testutil.Equals(t, labels.Labels{{Name: "replica", Value: "01"}}, 61 ExtendSortedLabels(labels.Labels{}, labels.FromStrings("replica", "01"))) 62 63 testutil.Equals(t, labels.Labels{{Name: "a", Value: "1"}, {Name: "replica", Value: "01"}, {Name: "xb", Value: "2"}}, 64 ExtendSortedLabels(labels.Labels{{Name: "a", Value: "1"}, {Name: "replica", Value: "NOT01"}, {Name: "xb", Value: "2"}}, labels.FromStrings("replica", "01"))) 65 66 testInjectExtLabels(testutil.NewTB(t)) 67 } 68 69 func TestValidateLabels(t *testing.T) { 70 testCases := []struct { 71 labelSet []ZLabel 72 expectedErr error 73 }{ 74 { 75 // No labels at all. 76 labelSet: []ZLabel{}, 77 expectedErr: ErrEmptyLabels, 78 }, 79 { 80 // Empty label. 81 labelSet: []ZLabel{ 82 { 83 Name: "foo", 84 Value: "bar", 85 }, 86 { 87 Name: "", 88 Value: "baz", 89 }, 90 }, 91 expectedErr: ErrEmptyLabels, 92 }, 93 { 94 // Empty label (first label). 95 labelSet: []ZLabel{ 96 { 97 Name: "", 98 Value: "bar", 99 }, 100 { 101 Name: "foo", 102 Value: "baz", 103 }, 104 }, 105 expectedErr: ErrEmptyLabels, 106 }, 107 { 108 // Empty label (empty value). 109 labelSet: []ZLabel{ 110 { 111 Name: "foo", 112 Value: "bar", 113 }, 114 { 115 Name: "baz", 116 Value: "", 117 }, 118 }, 119 expectedErr: ErrEmptyLabels, 120 }, 121 { 122 // Out-of-order and duplicate label (out-of-order comes first). 123 labelSet: []ZLabel{ 124 { 125 Name: "foo", 126 Value: "bar", 127 }, 128 { 129 Name: "test", 130 Value: "baz", 131 }, 132 { 133 Name: "foo", 134 Value: "bar", 135 }, 136 }, 137 expectedErr: ErrOutOfOrderLabels, 138 }, 139 { 140 // Out-of-order and duplicate label (out-of-order comes first). 141 labelSet: []ZLabel{ 142 { 143 Name: "__test__", 144 Value: "baz", 145 }, 146 { 147 Name: "foo", 148 Value: "bar", 149 }, 150 { 151 Name: "foo", 152 Value: "bar", 153 }, 154 { 155 Name: "test", 156 Value: "baz", 157 }, 158 }, 159 expectedErr: ErrDuplicateLabels, 160 }, 161 { 162 // Empty and duplicate label (empty comes first). 163 labelSet: []ZLabel{ 164 { 165 Name: "foo", 166 Value: "bar", 167 }, 168 { 169 Name: "", 170 Value: "baz", 171 }, 172 { 173 Name: "foo", 174 Value: "bar", 175 }, 176 }, 177 expectedErr: ErrEmptyLabels, 178 }, 179 { 180 // Wrong order. 181 labelSet: []ZLabel{ 182 { 183 Name: "a", 184 Value: "bar", 185 }, 186 { 187 Name: "b", 188 Value: "baz", 189 }, 190 { 191 Name: "__name__", 192 Value: "test", 193 }, 194 }, 195 expectedErr: ErrOutOfOrderLabels, 196 }, 197 { 198 // Wrong order and duplicate (wrong order comes first). 199 labelSet: []ZLabel{ 200 { 201 Name: "a", 202 Value: "bar", 203 }, 204 { 205 Name: "__name__", 206 Value: "test", 207 }, 208 { 209 Name: "a", 210 Value: "bar", 211 }, 212 }, 213 expectedErr: ErrOutOfOrderLabels, 214 }, 215 { 216 // All good. 217 labelSet: []ZLabel{ 218 { 219 Name: "__name__", 220 Value: "test", 221 }, 222 { 223 Name: "a1", 224 Value: "bar", 225 }, 226 { 227 Name: "a2", 228 Value: "baz", 229 }, 230 }, 231 expectedErr: nil, 232 }, 233 } 234 235 for i, tc := range testCases { 236 t.Run(fmt.Sprintf("case %d", i+1), func(t *testing.T) { 237 err := ValidateLabels(tc.labelSet) 238 testutil.Equals(t, tc.expectedErr, err) 239 }) 240 } 241 242 } 243 244 func BenchmarkExtendLabels(b *testing.B) { 245 testInjectExtLabels(testutil.NewTB(b)) 246 } 247 248 var x labels.Labels 249 250 func testInjectExtLabels(tb testutil.TB) { 251 in := labels.FromStrings( 252 "__name__", "subscription_labels", 253 "_id", "0dfsdfsdsfdsffd1e96-4432-9abe-e33436ea969a", 254 "account", "1afsdfsddsfsdfsdfsdfsdfs", 255 "ebs_account", "1asdasdad45", 256 "email_domain", "asdasddgfkw.example.com", 257 "endpoint", "metrics", 258 "external_organization", "dfsdfsdf", 259 "instance", "10.128.4.231:8080", 260 "job", "sdd-acct-mngr-metrics", 261 "managed", "false", 262 "namespace", "production", 263 "organization", "dasdadasdasasdasaaFGDSG", 264 "pod", "sdd-acct-mngr-6669c947c8-xjx7f", 265 "prometheus", "telemeter-production/telemeter", 266 "prometheus_replica", "prometheus-telemeter-1", 267 "risk", "5", 268 "service", "sdd-acct-mngr-metrics", 269 "support", "Self-Support", // Should be overwritten. 270 ) 271 extLset := labels.FromStrings( 272 "support", "Host-Support", 273 "replica", "1", 274 "tenant", "2342", 275 ) 276 tb.ResetTimer() 277 for i := 0; i < tb.N(); i++ { 278 x = ExtendSortedLabels(in, extLset) 279 280 if !tb.IsBenchmark() { 281 testutil.Equals(tb, labels.FromStrings( 282 "__name__", "subscription_labels", 283 "_id", "0dfsdfsdsfdsffd1e96-4432-9abe-e33436ea969a", 284 "account", "1afsdfsddsfsdfsdfsdfsdfs", 285 "ebs_account", "1asdasdad45", 286 "email_domain", "asdasddgfkw.example.com", 287 "endpoint", "metrics", 288 "external_organization", "dfsdfsdf", 289 "instance", "10.128.4.231:8080", 290 "job", "sdd-acct-mngr-metrics", 291 "managed", "false", 292 "namespace", "production", 293 "organization", "dasdadasdasasdasaaFGDSG", 294 "pod", "sdd-acct-mngr-6669c947c8-xjx7f", 295 "prometheus", "telemeter-production/telemeter", 296 "prometheus_replica", "prometheus-telemeter-1", 297 "replica", "1", 298 "risk", "5", 299 "service", "sdd-acct-mngr-metrics", 300 "support", "Host-Support", 301 "tenant", "2342", 302 ), x) 303 } 304 } 305 fmt.Fprint(io.Discard, x) 306 } 307 308 var ( 309 zdest ZLabel 310 dest Label 311 ) 312 313 func BenchmarkZLabelsMarshalUnmarshal(b *testing.B) { 314 const ( 315 fmtLbl = "%07daaaaaaaaaabbbbbbbbbbccccccccccdddddddddd" 316 num = 1000000 317 ) 318 319 b.Run("Label", func(b *testing.B) { 320 b.ReportAllocs() 321 lbls := LabelSet{Labels: make([]Label, 0, num)} 322 for i := 0; i < num; i++ { 323 lbls.Labels = append(lbls.Labels, Label{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)}) 324 } 325 b.ResetTimer() 326 327 for i := 0; i < b.N; i++ { 328 data, err := lbls.Marshal() 329 testutil.Ok(b, err) 330 331 dest = Label{} 332 testutil.Ok(b, (&dest).Unmarshal(data)) 333 } 334 }) 335 336 b.Run("ZLabel", func(b *testing.B) { 337 b.ReportAllocs() 338 lbls := ZLabelSet{Labels: make([]ZLabel, 0, num)} 339 for i := 0; i < num; i++ { 340 lbls.Labels = append(lbls.Labels, ZLabel{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)}) 341 } 342 b.ResetTimer() 343 344 for i := 0; i < b.N; i++ { 345 data, err := lbls.Marshal() 346 testutil.Ok(b, err) 347 348 zdest = ZLabel{} 349 testutil.Ok(b, (&zdest).Unmarshal(data)) 350 } 351 }) 352 } 353 354 func BenchmarkTransformWithAndWithoutCopyWithSingleLabel(b *testing.B) { 355 benchmarkTransformWithAndWithoutCopy(b, 1) 356 } 357 358 func BenchmarkTransformWithAndWithoutCopyWith1000Labels(b *testing.B) { 359 benchmarkTransformWithAndWithoutCopy(b, 1000) 360 } 361 362 func BenchmarkTransformWithAndWithoutCopyWith100000Labels(b *testing.B) { 363 benchmarkTransformWithAndWithoutCopy(b, 100000) 364 } 365 366 var ret labels.Labels 367 368 func benchmarkTransformWithAndWithoutCopy(b *testing.B, num int) { 369 const fmtLbl = "%07daaaaaaaaaabbbbbbbbbbccccccccccdddddddddd" 370 371 b.Run("ZLabelsToPromLabels", func(b *testing.B) { 372 b.ReportAllocs() 373 lbls := make([]ZLabel, num) 374 for i := 0; i < num; i++ { 375 lbls[i] = ZLabel{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)} 376 } 377 b.ResetTimer() 378 379 for i := 0; i < b.N; i++ { 380 ret = ZLabelsToPromLabels(lbls) 381 } 382 }) 383 b.Run("ZLabelsToPromLabelsWithRealloc", func(b *testing.B) { 384 b.ReportAllocs() 385 lbls := make([]ZLabel, num) 386 for i := 0; i < num; i++ { 387 lbls[i] = ZLabel{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)} 388 } 389 b.ResetTimer() 390 391 for i := 0; i < b.N; i++ { 392 ReAllocZLabelsStrings(&lbls, true) 393 ret = ZLabelsToPromLabels(lbls) 394 } 395 }) 396 } 397 398 func TestSortZLabelSets(t *testing.T) { 399 expectedResult := ZLabelSets{ 400 { 401 Labels: ZLabelsFromPromLabels( 402 labels.FromMap(map[string]string{ 403 "__name__": "grpc_client_handled_total", 404 "cluster": "test", 405 "grpc_code": "OK", 406 "grpc_method": "Info", 407 }), 408 ), 409 }, 410 { 411 Labels: ZLabelsFromPromLabels( 412 labels.FromMap(map[string]string{ 413 "__name__": "grpc_client_handled_total", 414 "cluster": "test", 415 "grpc_code": "OK", 416 "grpc_method": "LabelNames", 417 }), 418 ), 419 }, 420 { 421 Labels: ZLabelsFromPromLabels( 422 labels.FromMap(map[string]string{ 423 "__name__": "grpc_client_handled_total", 424 "cluster": "test", 425 "grpc_code": "OK", 426 "aa": "1", 427 "bb": "2", 428 "cc": "3", 429 "dd": "4", 430 "ee": "5", 431 }), 432 ), 433 }, 434 { 435 Labels: ZLabelsFromPromLabels( 436 labels.FromMap(map[string]string{ 437 "__name__": "grpc_client_handled_total", 438 "cluster": "test", 439 "grpc_code": "OK", 440 "aa": "1", 441 "bb": "2", 442 "cc": "3", 443 "dd": "4", 444 "ee": "5", 445 }), 446 ), 447 }, 448 { 449 Labels: ZLabelsFromPromLabels( 450 labels.FromMap(map[string]string{ 451 "__name__": "grpc_server_handled_total", 452 "cluster": "test", 453 "grpc_code": "OK", 454 "grpc_method": "Info", 455 }), 456 ), 457 }, 458 { 459 Labels: ZLabelsFromPromLabels( 460 labels.FromMap(map[string]string{ 461 "__name__": "up", 462 "instance": "localhost:10908", 463 }), 464 ), 465 }, 466 } 467 468 list := ZLabelSets{ 469 { 470 Labels: ZLabelsFromPromLabels( 471 labels.FromMap(map[string]string{ 472 "__name__": "up", 473 "instance": "localhost:10908", 474 }), 475 ), 476 }, 477 { 478 Labels: ZLabelsFromPromLabels( 479 labels.FromMap(map[string]string{ 480 "__name__": "grpc_server_handled_total", 481 "cluster": "test", 482 "grpc_code": "OK", 483 "grpc_method": "Info", 484 }), 485 ), 486 }, 487 { 488 Labels: ZLabelsFromPromLabels( 489 labels.FromMap(map[string]string{ 490 "__name__": "grpc_client_handled_total", 491 "cluster": "test", 492 "grpc_code": "OK", 493 "grpc_method": "LabelNames", 494 }), 495 ), 496 }, 497 { 498 Labels: ZLabelsFromPromLabels( 499 labels.FromMap(map[string]string{ 500 "__name__": "grpc_client_handled_total", 501 "cluster": "test", 502 "grpc_code": "OK", 503 "grpc_method": "Info", 504 }), 505 ), 506 }, 507 { 508 Labels: ZLabelsFromPromLabels( 509 labels.FromMap(map[string]string{ 510 "__name__": "grpc_client_handled_total", 511 "cluster": "test", 512 "grpc_code": "OK", 513 "aa": "1", 514 "bb": "2", 515 "cc": "3", 516 "dd": "4", 517 "ee": "5", 518 }), 519 ), 520 }, 521 // This label set is the same as the previous one, which should correctly return 0 in Less() function. 522 { 523 Labels: ZLabelsFromPromLabels( 524 labels.FromMap(map[string]string{ 525 "cluster": "test", 526 "__name__": "grpc_client_handled_total", 527 "grpc_code": "OK", 528 "aa": "1", 529 "bb": "2", 530 "cc": "3", 531 "dd": "4", 532 "ee": "5", 533 }), 534 ), 535 }, 536 } 537 538 sort.Sort(list) 539 reflect.DeepEqual(expectedResult, list) 540 } 541 542 func TestHashWithPrefix(t *testing.T) { 543 lbls := []ZLabel{ 544 {Name: "foo", Value: "bar"}, 545 {Name: "baz", Value: "qux"}, 546 } 547 testutil.Equals(t, HashWithPrefix("a", lbls), HashWithPrefix("a", lbls)) 548 testutil.Assert(t, HashWithPrefix("a", lbls) != HashWithPrefix("a", []ZLabel{lbls[0]})) 549 testutil.Assert(t, HashWithPrefix("a", lbls) != HashWithPrefix("a", []ZLabel{lbls[1], lbls[0]})) 550 testutil.Assert(t, HashWithPrefix("a", lbls) != HashWithPrefix("b", lbls)) 551 } 552 553 var benchmarkLabelsResult uint64 554 555 func BenchmarkHasWithPrefix(b *testing.B) { 556 for _, tcase := range []struct { 557 name string 558 lbls []ZLabel 559 }{ 560 { 561 name: "typical labels under 1KB", 562 lbls: func() []ZLabel { 563 lbls := make([]ZLabel, 10) 564 for i := 0; i < len(lbls); i++ { 565 // ZLabel ~20B name, 50B value. 566 lbls[i] = ZLabel{Name: fmt.Sprintf("abcdefghijabcdefghijabcdefghij%d", i), Value: fmt.Sprintf("abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij%d", i)} 567 } 568 return lbls 569 }(), 570 }, 571 { 572 name: "bigger labels over 1KB", 573 lbls: func() []ZLabel { 574 lbls := make([]ZLabel, 10) 575 for i := 0; i < len(lbls); i++ { 576 //ZLabel ~50B name, 50B value. 577 lbls[i] = ZLabel{Name: fmt.Sprintf("abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij%d", i), Value: fmt.Sprintf("abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij%d", i)} 578 } 579 return lbls 580 }(), 581 }, 582 { 583 name: "extremely large label value 10MB", 584 lbls: func() []ZLabel { 585 lbl := &strings.Builder{} 586 lbl.Grow(1024 * 1024 * 10) // 10MB. 587 word := "abcdefghij" 588 for i := 0; i < lbl.Cap()/len(word); i++ { 589 _, _ = lbl.WriteString(word) 590 } 591 return []ZLabel{{Name: "__name__", Value: lbl.String()}} 592 }(), 593 }, 594 } { 595 b.Run(tcase.name, func(b *testing.B) { 596 var h uint64 597 598 const prefix = "test-" 599 600 b.ReportAllocs() 601 b.ResetTimer() 602 for i := 0; i < b.N; i++ { 603 h = HashWithPrefix(prefix, tcase.lbls) 604 } 605 benchmarkLabelsResult = h 606 }) 607 } 608 }