
1) Fail if we can't read critical env vars 2) Don't rely on KUBE_ROOT env var when `go list` works 3) Don't rely on GOOS env var when `go env` works 4) Don't quietly ignore "can't read" errors Once we stop ignoring errors, some tests fail for real (and should always have failed). The "Imported k8s.io/staging constant" test seems to not be allowed at all anymore. Han said to nix it and he'd look async. Oversall this test is dodgy. You REALLY can't glue strings together and expect valid Go module paths. We should consider a deeper rework.
689 lines
17 KiB
Go
689 lines
17 KiB
Go
/*
|
|
Copyright 2019 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
"k8s.io/component-base/metrics"
|
|
)
|
|
|
|
const fakeFilename = "testdata/metric.go"
|
|
|
|
func TestSkipMetrics(t *testing.T) {
|
|
for _, test := range []struct {
|
|
testName string
|
|
src string
|
|
}{
|
|
{
|
|
testName: "Skip alpha metric with local variable",
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var name = "metric"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: name,
|
|
StabilityLevel: metrics.ALPHA,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Skip alpha metric created via function call",
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
func getName() string {
|
|
return "metric"
|
|
}
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: getName(),
|
|
StabilityLevel: metrics.ALPHA,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Skip metric without stability set",
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: "metric",
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Skip functions of similar signature (not imported from framework path) with import rename",
|
|
src: `
|
|
package test
|
|
import metrics "k8s.io/fake/path"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Skip functions of similar signature (not imported from framework path)",
|
|
src: `
|
|
package test
|
|
import "k8s.io/fake/path/metrics"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Skip . package import of non metric framework",
|
|
src: `
|
|
package test
|
|
import . "k8s.io/fake/path"
|
|
var _ = NewCounter(
|
|
&CounterOpts{
|
|
StabilityLevel: STABLE,
|
|
},
|
|
)
|
|
`},
|
|
} {
|
|
t.Run(test.testName, func(t *testing.T) {
|
|
metrics, errors := searchFileForStableMetrics(fakeFilename, test.src)
|
|
if len(metrics) != 0 {
|
|
t.Errorf("Didn't expect any stable metrics found, got: %d", len(metrics))
|
|
}
|
|
if len(errors) != 0 {
|
|
t.Errorf("Didn't expect any errors found, got: %s", errors)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStableMetric(t *testing.T) {
|
|
for _, test := range []struct {
|
|
testName string
|
|
src string
|
|
metric metric
|
|
}{
|
|
{
|
|
testName: "Counter",
|
|
metric: metric{
|
|
Name: "metric",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
StabilityLevel: "STABLE",
|
|
DeprecatedVersion: "1.16",
|
|
Help: "help",
|
|
Type: counterMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: "metric",
|
|
Subsystem: "subsystem",
|
|
Namespace: "namespace",
|
|
Help: "help",
|
|
DeprecatedVersion: "1.16",
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "CounterVec",
|
|
metric: metric{
|
|
Name: "metric",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
Labels: []string{"label-1"},
|
|
StabilityLevel: "STABLE",
|
|
DeprecatedVersion: "1.16",
|
|
Help: "help",
|
|
Type: counterMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewCounterVec(
|
|
&metrics.CounterOpts{
|
|
Name: "metric",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
Help: "help",
|
|
DeprecatedVersion: "1.16",
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
[]string{"label-1"},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Gauge",
|
|
metric: metric{
|
|
Name: "gauge",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
StabilityLevel: "STABLE",
|
|
DeprecatedVersion: "1.16",
|
|
Help: "help",
|
|
Type: gaugeMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewGauge(
|
|
&metrics.GaugeOpts{
|
|
Name: "gauge",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
Help: "help",
|
|
DeprecatedVersion: "1.16",
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "GaugeVec",
|
|
metric: metric{
|
|
Name: "gauge",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
StabilityLevel: "STABLE",
|
|
DeprecatedVersion: "1.16",
|
|
Help: "help",
|
|
Type: gaugeMetricType,
|
|
Labels: []string{"label-1", "label-2"},
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewGaugeVec(
|
|
&metrics.GaugeOpts{
|
|
Name: "gauge",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
Help: "help",
|
|
DeprecatedVersion: "1.16",
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
[]string{"label-2", "label-1"},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Histogram",
|
|
metric: metric{
|
|
Name: "histogram",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
DeprecatedVersion: "1.16",
|
|
StabilityLevel: "STABLE",
|
|
Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100},
|
|
Help: "help",
|
|
Type: histogramMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewHistogram(
|
|
&metrics.HistogramOpts{
|
|
Name: "histogram",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
StabilityLevel: metrics.STABLE,
|
|
Help: "help",
|
|
DeprecatedVersion: "1.16",
|
|
Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100},
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "HistogramVec",
|
|
metric: metric{
|
|
Name: "histogram",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
DeprecatedVersion: "1.16",
|
|
StabilityLevel: "STABLE",
|
|
Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100},
|
|
Help: "help",
|
|
Type: histogramMetricType,
|
|
Labels: []string{"label-1", "label-2"},
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewHistogramVec(
|
|
&metrics.HistogramOpts{
|
|
Name: "histogram",
|
|
Namespace: "namespace",
|
|
Subsystem: "subsystem",
|
|
StabilityLevel: metrics.STABLE,
|
|
Help: "help",
|
|
DeprecatedVersion: "1.16",
|
|
Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100},
|
|
},
|
|
[]string{"label-2", "label-1"},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Custom import",
|
|
metric: metric{
|
|
Name: "metric",
|
|
StabilityLevel: "STABLE",
|
|
Type: counterMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import custom "k8s.io/component-base/metrics"
|
|
var _ = custom.NewCounter(
|
|
&custom.CounterOpts{
|
|
Name: "metric",
|
|
StabilityLevel: custom.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Custom import NewDesc",
|
|
metric: metric{
|
|
Name: "apiserver_storage_size_bytes",
|
|
Help: "Size of the storage database file physically allocated in bytes.",
|
|
Labels: []string{"server"},
|
|
StabilityLevel: "STABLE",
|
|
Type: customType,
|
|
ConstLabels: map[string]string{},
|
|
},
|
|
src: `
|
|
package test
|
|
import custom "k8s.io/component-base/metrics"
|
|
var _ = custom.NewDesc("apiserver_storage_size_bytes", "Size of the storage database file physically allocated in bytes.", []string{"server"}, nil, custom.STABLE, "")
|
|
`},
|
|
{
|
|
testName: "Const",
|
|
metric: metric{
|
|
Name: "metric",
|
|
StabilityLevel: "STABLE",
|
|
Type: counterMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
const name = "metric"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: name,
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Variable",
|
|
metric: metric{
|
|
Name: "metric",
|
|
StabilityLevel: "STABLE",
|
|
Type: counterMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var name = "metric"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: name,
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Multiple consts in block",
|
|
metric: metric{
|
|
Name: "metric",
|
|
StabilityLevel: "STABLE",
|
|
Type: counterMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
const (
|
|
unrelated1 = "unrelated1"
|
|
name = "metric"
|
|
unrelated2 = "unrelated2"
|
|
)
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: name,
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Multiple variables in Block",
|
|
metric: metric{
|
|
Name: "metric",
|
|
StabilityLevel: "STABLE",
|
|
Type: counterMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var (
|
|
unrelated1 = "unrelated1"
|
|
name = "metric"
|
|
_ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: name,
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
)
|
|
`},
|
|
{
|
|
testName: "Histogram with linear buckets",
|
|
metric: metric{
|
|
Name: "histogram",
|
|
StabilityLevel: "STABLE",
|
|
Buckets: metrics.LinearBuckets(1, 1, 3),
|
|
Type: histogramMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewHistogram(
|
|
&metrics.HistogramOpts{
|
|
Name: "histogram",
|
|
StabilityLevel: metrics.STABLE,
|
|
Buckets: metrics.LinearBuckets(1, 1, 3),
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Histogram with exponential buckets",
|
|
metric: metric{
|
|
Name: "histogram",
|
|
StabilityLevel: "STABLE",
|
|
Buckets: metrics.ExponentialBuckets(1, 2, 3),
|
|
Type: histogramMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewHistogram(
|
|
&metrics.HistogramOpts{
|
|
Name: "histogram",
|
|
StabilityLevel: metrics.STABLE,
|
|
Buckets: metrics.ExponentialBuckets(1, 2, 3),
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Histogram with default buckets",
|
|
metric: metric{
|
|
Name: "histogram",
|
|
StabilityLevel: "STABLE",
|
|
Buckets: metrics.DefBuckets,
|
|
Type: histogramMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewHistogram(
|
|
&metrics.HistogramOpts{
|
|
Name: "histogram",
|
|
StabilityLevel: metrics.STABLE,
|
|
Buckets: metrics.DefBuckets,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Imported k8s.io constant",
|
|
metric: metric{
|
|
Name: "importedCounter",
|
|
StabilityLevel: "STABLE",
|
|
Subsystem: "kubelet",
|
|
Type: counterMetricType,
|
|
},
|
|
src: `
|
|
package test
|
|
import compbasemetrics "k8s.io/component-base/metrics"
|
|
import "k8s.io/kubernetes/pkg/kubelet/metrics"
|
|
var _ = compbasemetrics.NewCounter(
|
|
&compbasemetrics.CounterOpts{
|
|
Name: "importedCounter",
|
|
StabilityLevel: compbasemetrics.STABLE,
|
|
Subsystem: metrics.KubeletSubsystem,
|
|
},
|
|
)
|
|
`},
|
|
} {
|
|
t.Run(test.testName, func(t *testing.T) {
|
|
metrics, errors := searchFileForStableMetrics(fakeFilename, test.src)
|
|
if len(errors) != 0 {
|
|
t.Errorf("Unexpected errors: %s", errors)
|
|
}
|
|
if len(metrics) != 1 {
|
|
t.Fatalf("Unexpected number of metrics: got %d, want 1", len(metrics))
|
|
}
|
|
if test.metric.Labels == nil {
|
|
test.metric.Labels = []string{}
|
|
}
|
|
if diff := cmp.Diff(metrics[0], test.metric); diff != "" {
|
|
t.Errorf("metric diff: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIncorrectStableMetricDeclarations(t *testing.T) {
|
|
for _, test := range []struct {
|
|
testName string
|
|
src string
|
|
err error
|
|
}{
|
|
{
|
|
testName: "Fail on stable metric with attribute set to unknown variable",
|
|
err: fmt.Errorf("testdata/metric.go:6:4: Metric attribute was not correctly set. Please use only global consts in same file"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: unknownVariable,
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Fail on stable metric with attribute set to local function return",
|
|
err: fmt.Errorf("testdata/metric.go:9:4: Non string attribute is not supported"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
func getName() string {
|
|
return "metric"
|
|
}
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: getName(),
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Fail on stable metric with attribute set to imported function return",
|
|
err: fmt.Errorf("testdata/metric.go:7:4: Non string attribute is not supported"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
import "os"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
Name: os.Getenv("name"), // any imported function will do
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "Fail on metric with stability set to function return",
|
|
err: fmt.Errorf("testdata/metric.go:9:20: %s", errStabilityLevel),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
func getMetricStability() metrics.StabilityLevel {
|
|
return metrics.STABLE
|
|
}
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
StabilityLevel: getMetricsStability(),
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "error for passing stability as string",
|
|
err: fmt.Errorf("testdata/metric.go:6:20: %s", errStabilityLevel),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
StabilityLevel: "stable",
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "error for passing stability as variable",
|
|
err: fmt.Errorf("testdata/metric.go:7:20: %s", errStabilityLevel),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var stable = metrics.STABLE
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
StabilityLevel: stable,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "error for stable metric created via function call",
|
|
err: fmt.Errorf("testdata/metric.go:6:10: Opts for STABLE metric was not directly passed to new metric function"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewCounter(getStableCounterOpts())
|
|
func getStableCounterOpts() *metrics.CounterOpts {
|
|
return &metrics.CounterOpts{
|
|
StabilityLevel: metrics.STABLE,
|
|
}
|
|
}
|
|
`},
|
|
{
|
|
testName: "error . package import of metric framework",
|
|
err: fmt.Errorf(`testdata/metric.go:3:8: Importing using "." is not supported`),
|
|
src: `
|
|
package test
|
|
import . "k8s.io/component-base/metrics"
|
|
var _ = NewCounter(
|
|
&CounterOpts{
|
|
StabilityLevel: STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "error stable metric opts passed to local function",
|
|
err: fmt.Errorf("testdata/metric.go:4:9: Opts for STABLE metric was not directly passed to new metric function"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = RegisterMetric(
|
|
&metrics.CounterOpts{
|
|
StabilityLevel: metrics.STABLE,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "error stable metric opts passed to imported function",
|
|
err: fmt.Errorf("testdata/metric.go:6:4: Positional arguments are not supported"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
var _ = metrics.NewCounter(
|
|
&metrics.CounterOpts{
|
|
"counter",
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "error stable histogram with unknown prometheus bucket variable",
|
|
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"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
import "github.com/prometheus/client_golang/prometheus"
|
|
var _ = metrics.NewHistogram(
|
|
&metrics.HistogramOpts{
|
|
Name: "histogram",
|
|
StabilityLevel: metrics.STABLE,
|
|
Buckets: prometheus.FakeBuckets,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "error stable summary with unknown prometheus objective variable",
|
|
err: fmt.Errorf("testdata/metric.go:9:16: Objectives should be set to map of floats to floats"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
import "github.com/prometheus/client_golang/prometheus"
|
|
var _ = metrics.NewSummary(
|
|
&metrics.SummaryOpts{
|
|
Name: "summary",
|
|
StabilityLevel: metrics.STABLE,
|
|
Objectives: prometheus.FakeObjectives,
|
|
},
|
|
)
|
|
`},
|
|
{
|
|
testName: "error stable historgram with unknown bucket variable from unknown library",
|
|
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"),
|
|
src: `
|
|
package test
|
|
import "k8s.io/component-base/metrics"
|
|
import "github.com/prometheus/client_golang/prometheus"
|
|
var _ = metrics.NewHistogram(
|
|
&metrics.HistogramOpts{
|
|
Name: "histogram",
|
|
StabilityLevel: metrics.STABLE,
|
|
Buckets: prometheus.DefBuckets,
|
|
},
|
|
)
|
|
`},
|
|
} {
|
|
t.Run(test.testName, func(t *testing.T) {
|
|
_, errors := searchFileForStableMetrics(fakeFilename, test.src)
|
|
if len(errors) != 1 {
|
|
t.Errorf("Unexpected number of errors, got %d, want 1", len(errors))
|
|
}
|
|
if !reflect.DeepEqual(errors[0], test.err) {
|
|
t.Errorf("error:\ngot %v\nwant %v", errors[0], test.err)
|
|
}
|
|
})
|
|
}
|
|
}
|