...

Source file src/k8s.io/kubernetes/test/instrumentation/main_test.go

Documentation: k8s.io/kubernetes/test/instrumentation

     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  }
   689  

View as plain text