k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/instrumentation/main_test.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "fmt" 21 "reflect" 22 "testing" 23 24 "github.com/google/go-cmp/cmp" 25 26 "k8s.io/component-base/metrics" 27 ) 28 29 const fakeFilename = "testdata/metric.go" 30 31 func TestSkipMetrics(t *testing.T) { 32 for _, test := range []struct { 33 testName string 34 src string 35 }{ 36 { 37 testName: "Skip alpha metric with local variable", 38 src: ` 39 package test 40 import "k8s.io/component-base/metrics" 41 var name = "metric" 42 var _ = metrics.NewCounter( 43 &metrics.CounterOpts{ 44 Name: name, 45 StabilityLevel: metrics.ALPHA, 46 }, 47 ) 48 `}, 49 { 50 testName: "Skip alpha metric created via function call", 51 src: ` 52 package test 53 import "k8s.io/component-base/metrics" 54 func getName() string { 55 return "metric" 56 } 57 var _ = metrics.NewCounter( 58 &metrics.CounterOpts{ 59 Name: getName(), 60 StabilityLevel: metrics.ALPHA, 61 }, 62 ) 63 `}, 64 { 65 testName: "Skip metric without stability set", 66 src: ` 67 package test 68 import "k8s.io/component-base/metrics" 69 var _ = metrics.NewCounter( 70 &metrics.CounterOpts{ 71 Name: "metric", 72 }, 73 ) 74 `}, 75 { 76 testName: "Skip functions of similar signature (not imported from framework path) with import rename", 77 src: ` 78 package test 79 import metrics "k8s.io/fake/path" 80 var _ = metrics.NewCounter( 81 &metrics.CounterOpts{ 82 StabilityLevel: metrics.STABLE, 83 }, 84 ) 85 `}, 86 { 87 testName: "Skip functions of similar signature (not imported from framework path)", 88 src: ` 89 package test 90 import "k8s.io/fake/path/metrics" 91 var _ = metrics.NewCounter( 92 &metrics.CounterOpts{ 93 StabilityLevel: metrics.STABLE, 94 }, 95 ) 96 `}, 97 { 98 testName: "Skip . package import of non metric framework", 99 src: ` 100 package test 101 import . "k8s.io/fake/path" 102 var _ = NewCounter( 103 &CounterOpts{ 104 StabilityLevel: STABLE, 105 }, 106 ) 107 `}, 108 } { 109 t.Run(test.testName, func(t *testing.T) { 110 metrics, errors := searchFileForStableMetrics(fakeFilename, test.src) 111 if len(metrics) != 0 { 112 t.Errorf("Didn't expect any stable metrics found, got: %d", len(metrics)) 113 } 114 if len(errors) != 0 { 115 t.Errorf("Didn't expect any errors found, got: %s", errors) 116 } 117 }) 118 } 119 } 120 121 func TestStableMetric(t *testing.T) { 122 for _, test := range []struct { 123 testName string 124 src string 125 metric metric 126 }{ 127 { 128 testName: "Counter", 129 metric: metric{ 130 Name: "metric", 131 Namespace: "namespace", 132 Subsystem: "subsystem", 133 StabilityLevel: "STABLE", 134 DeprecatedVersion: "1.16", 135 Help: "help", 136 Type: counterMetricType, 137 }, 138 src: ` 139 package test 140 import "k8s.io/component-base/metrics" 141 var _ = metrics.NewCounter( 142 &metrics.CounterOpts{ 143 Name: "metric", 144 Subsystem: "subsystem", 145 Namespace: "namespace", 146 Help: "help", 147 DeprecatedVersion: "1.16", 148 StabilityLevel: metrics.STABLE, 149 }, 150 ) 151 `}, 152 { 153 testName: "CounterVec", 154 metric: metric{ 155 Name: "metric", 156 Namespace: "namespace", 157 Subsystem: "subsystem", 158 Labels: []string{"label-1"}, 159 StabilityLevel: "STABLE", 160 DeprecatedVersion: "1.16", 161 Help: "help", 162 Type: counterMetricType, 163 }, 164 src: ` 165 package test 166 import "k8s.io/component-base/metrics" 167 var _ = metrics.NewCounterVec( 168 &metrics.CounterOpts{ 169 Name: "metric", 170 Namespace: "namespace", 171 Subsystem: "subsystem", 172 Help: "help", 173 DeprecatedVersion: "1.16", 174 StabilityLevel: metrics.STABLE, 175 }, 176 []string{"label-1"}, 177 ) 178 `}, 179 { 180 testName: "Gauge", 181 metric: metric{ 182 Name: "gauge", 183 Namespace: "namespace", 184 Subsystem: "subsystem", 185 StabilityLevel: "STABLE", 186 DeprecatedVersion: "1.16", 187 Help: "help", 188 Type: gaugeMetricType, 189 }, 190 src: ` 191 package test 192 import "k8s.io/component-base/metrics" 193 var _ = metrics.NewGauge( 194 &metrics.GaugeOpts{ 195 Name: "gauge", 196 Namespace: "namespace", 197 Subsystem: "subsystem", 198 Help: "help", 199 DeprecatedVersion: "1.16", 200 StabilityLevel: metrics.STABLE, 201 }, 202 ) 203 `}, 204 { 205 testName: "GaugeVec", 206 metric: metric{ 207 Name: "gauge", 208 Namespace: "namespace", 209 Subsystem: "subsystem", 210 StabilityLevel: "STABLE", 211 DeprecatedVersion: "1.16", 212 Help: "help", 213 Type: gaugeMetricType, 214 Labels: []string{"label-1", "label-2"}, 215 }, 216 src: ` 217 package test 218 import "k8s.io/component-base/metrics" 219 var _ = metrics.NewGaugeVec( 220 &metrics.GaugeOpts{ 221 Name: "gauge", 222 Namespace: "namespace", 223 Subsystem: "subsystem", 224 Help: "help", 225 DeprecatedVersion: "1.16", 226 StabilityLevel: metrics.STABLE, 227 }, 228 []string{"label-2", "label-1"}, 229 ) 230 `}, 231 { 232 testName: "Histogram", 233 metric: metric{ 234 Name: "histogram", 235 Namespace: "namespace", 236 Subsystem: "subsystem", 237 DeprecatedVersion: "1.16", 238 StabilityLevel: "STABLE", 239 Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100}, 240 Help: "help", 241 Type: histogramMetricType, 242 }, 243 src: ` 244 package test 245 import "k8s.io/component-base/metrics" 246 var _ = metrics.NewHistogram( 247 &metrics.HistogramOpts{ 248 Name: "histogram", 249 Namespace: "namespace", 250 Subsystem: "subsystem", 251 StabilityLevel: metrics.STABLE, 252 Help: "help", 253 DeprecatedVersion: "1.16", 254 Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100}, 255 }, 256 ) 257 `}, 258 { 259 testName: "HistogramVec", 260 metric: metric{ 261 Name: "histogram", 262 Namespace: "namespace", 263 Subsystem: "subsystem", 264 DeprecatedVersion: "1.16", 265 StabilityLevel: "STABLE", 266 Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100}, 267 Help: "help", 268 Type: histogramMetricType, 269 Labels: []string{"label-1", "label-2"}, 270 }, 271 src: ` 272 package test 273 import "k8s.io/component-base/metrics" 274 var _ = metrics.NewHistogramVec( 275 &metrics.HistogramOpts{ 276 Name: "histogram", 277 Namespace: "namespace", 278 Subsystem: "subsystem", 279 StabilityLevel: metrics.STABLE, 280 Help: "help", 281 DeprecatedVersion: "1.16", 282 Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100}, 283 }, 284 []string{"label-2", "label-1"}, 285 ) 286 `}, 287 { 288 testName: "Custom import", 289 metric: metric{ 290 Name: "metric", 291 StabilityLevel: "STABLE", 292 Type: counterMetricType, 293 }, 294 src: ` 295 package test 296 import custom "k8s.io/component-base/metrics" 297 var _ = custom.NewCounter( 298 &custom.CounterOpts{ 299 Name: "metric", 300 StabilityLevel: custom.STABLE, 301 }, 302 ) 303 `}, 304 { 305 testName: "Custom import NewDesc", 306 metric: metric{ 307 Name: "apiserver_storage_size_bytes", 308 Help: "Size of the storage database file physically allocated in bytes.", 309 Labels: []string{"server"}, 310 StabilityLevel: "STABLE", 311 Type: customType, 312 ConstLabels: map[string]string{}, 313 }, 314 src: ` 315 package test 316 import custom "k8s.io/component-base/metrics" 317 var _ = custom.NewDesc("apiserver_storage_size_bytes", "Size of the storage database file physically allocated in bytes.", []string{"server"}, nil, custom.STABLE, "") 318 `}, 319 { 320 testName: "Const", 321 metric: metric{ 322 Name: "metric", 323 StabilityLevel: "STABLE", 324 Type: counterMetricType, 325 }, 326 src: ` 327 package test 328 import "k8s.io/component-base/metrics" 329 const name = "metric" 330 var _ = metrics.NewCounter( 331 &metrics.CounterOpts{ 332 Name: name, 333 StabilityLevel: metrics.STABLE, 334 }, 335 ) 336 `}, 337 { 338 testName: "Variable", 339 metric: metric{ 340 Name: "metric", 341 StabilityLevel: "STABLE", 342 Type: counterMetricType, 343 }, 344 src: ` 345 package test 346 import "k8s.io/component-base/metrics" 347 var name = "metric" 348 var _ = metrics.NewCounter( 349 &metrics.CounterOpts{ 350 Name: name, 351 StabilityLevel: metrics.STABLE, 352 }, 353 ) 354 `}, 355 { 356 testName: "Multiple consts in block", 357 metric: metric{ 358 Name: "metric", 359 StabilityLevel: "STABLE", 360 Type: counterMetricType, 361 }, 362 src: ` 363 package test 364 import "k8s.io/component-base/metrics" 365 const ( 366 unrelated1 = "unrelated1" 367 name = "metric" 368 unrelated2 = "unrelated2" 369 ) 370 var _ = metrics.NewCounter( 371 &metrics.CounterOpts{ 372 Name: name, 373 StabilityLevel: metrics.STABLE, 374 }, 375 ) 376 `}, 377 { 378 testName: "Multiple variables in Block", 379 metric: metric{ 380 Name: "metric", 381 StabilityLevel: "STABLE", 382 Type: counterMetricType, 383 }, 384 src: ` 385 package test 386 import "k8s.io/component-base/metrics" 387 var ( 388 unrelated1 = "unrelated1" 389 name = "metric" 390 _ = metrics.NewCounter( 391 &metrics.CounterOpts{ 392 Name: name, 393 StabilityLevel: metrics.STABLE, 394 }, 395 ) 396 ) 397 `}, 398 { 399 testName: "Histogram with linear buckets", 400 metric: metric{ 401 Name: "histogram", 402 StabilityLevel: "STABLE", 403 Buckets: metrics.LinearBuckets(1, 1, 3), 404 Type: histogramMetricType, 405 }, 406 src: ` 407 package test 408 import "k8s.io/component-base/metrics" 409 var _ = metrics.NewHistogram( 410 &metrics.HistogramOpts{ 411 Name: "histogram", 412 StabilityLevel: metrics.STABLE, 413 Buckets: metrics.LinearBuckets(1, 1, 3), 414 }, 415 ) 416 `}, 417 { 418 testName: "Histogram with exponential buckets", 419 metric: metric{ 420 Name: "histogram", 421 StabilityLevel: "STABLE", 422 Buckets: metrics.ExponentialBuckets(1, 2, 3), 423 Type: histogramMetricType, 424 }, 425 src: ` 426 package test 427 import "k8s.io/component-base/metrics" 428 var _ = metrics.NewHistogram( 429 &metrics.HistogramOpts{ 430 Name: "histogram", 431 StabilityLevel: metrics.STABLE, 432 Buckets: metrics.ExponentialBuckets(1, 2, 3), 433 }, 434 ) 435 `}, 436 { 437 testName: "Histogram with default buckets", 438 metric: metric{ 439 Name: "histogram", 440 StabilityLevel: "STABLE", 441 Buckets: metrics.DefBuckets, 442 Type: histogramMetricType, 443 }, 444 src: ` 445 package test 446 import "k8s.io/component-base/metrics" 447 var _ = metrics.NewHistogram( 448 &metrics.HistogramOpts{ 449 Name: "histogram", 450 StabilityLevel: metrics.STABLE, 451 Buckets: metrics.DefBuckets, 452 }, 453 ) 454 `}, 455 { 456 testName: "Imported k8s.io constant", 457 metric: metric{ 458 Name: "importedCounter", 459 StabilityLevel: "STABLE", 460 Subsystem: "kubelet", 461 Type: counterMetricType, 462 }, 463 src: ` 464 package test 465 import compbasemetrics "k8s.io/component-base/metrics" 466 import "k8s.io/kubernetes/pkg/kubelet/metrics" 467 var _ = compbasemetrics.NewCounter( 468 &compbasemetrics.CounterOpts{ 469 Name: "importedCounter", 470 StabilityLevel: compbasemetrics.STABLE, 471 Subsystem: metrics.KubeletSubsystem, 472 }, 473 ) 474 `}, 475 } { 476 t.Run(test.testName, func(t *testing.T) { 477 metrics, errors := searchFileForStableMetrics(fakeFilename, test.src) 478 if len(errors) != 0 { 479 t.Errorf("Unexpected errors: %s", errors) 480 } 481 if len(metrics) != 1 { 482 t.Fatalf("Unexpected number of metrics: got %d, want 1", len(metrics)) 483 } 484 if test.metric.Labels == nil { 485 test.metric.Labels = []string{} 486 } 487 if diff := cmp.Diff(metrics[0], test.metric); diff != "" { 488 t.Errorf("metric diff: %s", diff) 489 } 490 }) 491 } 492 } 493 494 func TestIncorrectStableMetricDeclarations(t *testing.T) { 495 for _, test := range []struct { 496 testName string 497 src string 498 err error 499 }{ 500 { 501 testName: "Fail on stable metric with attribute set to unknown variable", 502 err: fmt.Errorf("testdata/metric.go:6:4: Metric attribute was not correctly set. Please use only global consts in same file"), 503 src: ` 504 package test 505 import "k8s.io/component-base/metrics" 506 var _ = metrics.NewCounter( 507 &metrics.CounterOpts{ 508 Name: unknownVariable, 509 StabilityLevel: metrics.STABLE, 510 }, 511 ) 512 `}, 513 { 514 testName: "Fail on stable metric with attribute set to local function return", 515 err: fmt.Errorf("testdata/metric.go:9:4: Non string attribute is not supported"), 516 src: ` 517 package test 518 import "k8s.io/component-base/metrics" 519 func getName() string { 520 return "metric" 521 } 522 var _ = metrics.NewCounter( 523 &metrics.CounterOpts{ 524 Name: getName(), 525 StabilityLevel: metrics.STABLE, 526 }, 527 ) 528 `}, 529 { 530 testName: "Fail on stable metric with attribute set to imported function return", 531 err: fmt.Errorf("testdata/metric.go:7:4: Non string attribute is not supported"), 532 src: ` 533 package test 534 import "k8s.io/component-base/metrics" 535 import "os" 536 var _ = metrics.NewCounter( 537 &metrics.CounterOpts{ 538 Name: os.Getenv("name"), // any imported function will do 539 StabilityLevel: metrics.STABLE, 540 }, 541 ) 542 `}, 543 { 544 testName: "Fail on metric with stability set to function return", 545 err: fmt.Errorf("testdata/metric.go:9:20: %s", errStabilityLevel), 546 src: ` 547 package test 548 import "k8s.io/component-base/metrics" 549 func getMetricStability() metrics.StabilityLevel { 550 return metrics.STABLE 551 } 552 var _ = metrics.NewCounter( 553 &metrics.CounterOpts{ 554 StabilityLevel: getMetricsStability(), 555 }, 556 ) 557 `}, 558 { 559 testName: "error for passing stability as string", 560 err: fmt.Errorf("testdata/metric.go:6:20: %s", errStabilityLevel), 561 src: ` 562 package test 563 import "k8s.io/component-base/metrics" 564 var _ = metrics.NewCounter( 565 &metrics.CounterOpts{ 566 StabilityLevel: "stable", 567 }, 568 ) 569 `}, 570 { 571 testName: "error for passing stability as variable", 572 err: fmt.Errorf("testdata/metric.go:7:20: %s", errStabilityLevel), 573 src: ` 574 package test 575 import "k8s.io/component-base/metrics" 576 var stable = metrics.STABLE 577 var _ = metrics.NewCounter( 578 &metrics.CounterOpts{ 579 StabilityLevel: stable, 580 }, 581 ) 582 `}, 583 { 584 testName: "error for stable metric created via function call", 585 err: fmt.Errorf("testdata/metric.go:6:10: Opts for STABLE metric was not directly passed to new metric function"), 586 src: ` 587 package test 588 import "k8s.io/component-base/metrics" 589 var _ = metrics.NewCounter(getStableCounterOpts()) 590 func getStableCounterOpts() *metrics.CounterOpts { 591 return &metrics.CounterOpts{ 592 StabilityLevel: metrics.STABLE, 593 } 594 } 595 `}, 596 { 597 testName: "error . package import of metric framework", 598 err: fmt.Errorf(`testdata/metric.go:3:8: Importing using "." is not supported`), 599 src: ` 600 package test 601 import . "k8s.io/component-base/metrics" 602 var _ = NewCounter( 603 &CounterOpts{ 604 StabilityLevel: STABLE, 605 }, 606 ) 607 `}, 608 { 609 testName: "error stable metric opts passed to local function", 610 err: fmt.Errorf("testdata/metric.go:4:9: Opts for STABLE metric was not directly passed to new metric function"), 611 src: ` 612 package test 613 import "k8s.io/component-base/metrics" 614 var _ = RegisterMetric( 615 &metrics.CounterOpts{ 616 StabilityLevel: metrics.STABLE, 617 }, 618 ) 619 `}, 620 { 621 testName: "error stable metric opts passed to imported function", 622 err: fmt.Errorf("testdata/metric.go:6:4: Positional arguments are not supported"), 623 src: ` 624 package test 625 import "k8s.io/component-base/metrics" 626 var _ = metrics.NewCounter( 627 &metrics.CounterOpts{ 628 "counter", 629 }, 630 ) 631 `}, 632 { 633 testName: "error stable histogram with unknown prometheus bucket variable", 634 err: fmt.Errorf("testdata/metric.go:9:13: Buckets should be set to list of floats, result from function call of prometheus.LinearBuckets or prometheus.ExponentialBuckets"), 635 src: ` 636 package test 637 import "k8s.io/component-base/metrics" 638 import "github.com/prometheus/client_golang/prometheus" 639 var _ = metrics.NewHistogram( 640 &metrics.HistogramOpts{ 641 Name: "histogram", 642 StabilityLevel: metrics.STABLE, 643 Buckets: prometheus.FakeBuckets, 644 }, 645 ) 646 `}, 647 { 648 testName: "error stable summary with unknown prometheus objective variable", 649 err: fmt.Errorf("testdata/metric.go:9:16: Objectives should be set to map of floats to floats"), 650 src: ` 651 package test 652 import "k8s.io/component-base/metrics" 653 import "github.com/prometheus/client_golang/prometheus" 654 var _ = metrics.NewSummary( 655 &metrics.SummaryOpts{ 656 Name: "summary", 657 StabilityLevel: metrics.STABLE, 658 Objectives: prometheus.FakeObjectives, 659 }, 660 ) 661 `}, 662 { 663 testName: "error stable historgram with unknown bucket variable from unknown library", 664 err: fmt.Errorf("testdata/metric.go:9:13: Buckets should be set to list of floats, result from function call of prometheus.LinearBuckets or prometheus.ExponentialBuckets"), 665 src: ` 666 package test 667 import "k8s.io/component-base/metrics" 668 import "github.com/prometheus/client_golang/prometheus" 669 var _ = metrics.NewHistogram( 670 &metrics.HistogramOpts{ 671 Name: "histogram", 672 StabilityLevel: metrics.STABLE, 673 Buckets: prometheus.DefBuckets, 674 }, 675 ) 676 `}, 677 } { 678 t.Run(test.testName, func(t *testing.T) { 679 _, errors := searchFileForStableMetrics(fakeFilename, test.src) 680 if len(errors) != 1 { 681 t.Errorf("Unexpected number of errors, got %d, want 1", len(errors)) 682 } 683 if !reflect.DeepEqual(errors[0], test.err) { 684 t.Errorf("error:\ngot %v\nwant %v", errors[0], test.err) 685 } 686 }) 687 } 688 }