Finish implementation of stable metrics static analysis

Handle "DeprecatedVersion" field
Fix kube metrics framework path
Implement handling prometheus util functions for generating buckets
This commit is contained in:
Marek Siarkowicz 2019-08-16 14:12:08 +02:00
parent d6035f3e0d
commit 53fc6f9b58
6 changed files with 287 additions and 92 deletions

View File

@ -171,7 +171,6 @@ test/images/agnhost/pause
test/images/agnhost/serve-hostname test/images/agnhost/serve-hostname
test/images/agnhost/webhook test/images/agnhost/webhook
test/images/pets/peer-finder test/images/pets/peer-finder
test/instrumentation
test/integration/apiserver test/integration/apiserver
test/integration/apiserver/admissionwebhook test/integration/apiserver/admissionwebhook
test/integration/auth test/integration/auth

View File

@ -63,4 +63,5 @@ go_test(
srcs = ["main_test.go"], srcs = ["main_test.go"],
data = glob(["testdata/**"]), data = glob(["testdata/**"]),
embed = [":go_default_library"], embed = [":go_default_library"],
deps = ["//vendor/github.com/prometheus/client_golang/prometheus:go_default_library"],
) )

View File

@ -24,12 +24,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/component-base/metrics" "k8s.io/component-base/metrics"
) )
func decodeMetricCalls(fs []*ast.CallExpr, metricsImportName string) ([]metric, []error) { func decodeMetricCalls(fs []*ast.CallExpr, metricsImportName, prometheusImportName string) ([]metric, []error) {
finder := metricDecoder{ finder := metricDecoder{
metricsImportName: metricsImportName, kubeMetricsImportName: metricsImportName,
prometheusImportName: prometheusImportName,
} }
ms := make([]metric, 0, len(fs)) ms := make([]metric, 0, len(fs))
errors := []error{} errors := []error{}
@ -45,7 +47,8 @@ func decodeMetricCalls(fs []*ast.CallExpr, metricsImportName string) ([]metric,
} }
type metricDecoder struct { type metricDecoder struct {
metricsImportName string kubeMetricsImportName string
prometheusImportName string
} }
func (c *metricDecoder) decodeNewMetricCall(fc *ast.CallExpr) (metric, error) { func (c *metricDecoder) decodeNewMetricCall(fc *ast.CallExpr) (metric, error) {
@ -60,7 +63,7 @@ func (c *metricDecoder) decodeNewMetricCall(fc *ast.CallExpr) (metric, error) {
if !ok { if !ok {
return m, newDecodeErrorf(fc, errNotDirectCall) return m, newDecodeErrorf(fc, errNotDirectCall)
} }
if functionImport.String() != c.metricsImportName { if functionImport.String() != c.kubeMetricsImportName {
return m, newDecodeErrorf(fc, errNotDirectCall) return m, newDecodeErrorf(fc, errNotDirectCall)
} }
switch functionName { switch functionName {
@ -157,7 +160,7 @@ func (c *metricDecoder) decodeOpts(expr ast.Expr) (metric, error) {
key := fmt.Sprintf("%v", kv.Key) key := fmt.Sprintf("%v", kv.Key)
switch key { switch key {
case "Namespace", "Subsystem", "Name", "Help": case "Namespace", "Subsystem", "Name", "Help", "DeprecatedVersion":
k, ok := kv.Value.(*ast.BasicLit) k, ok := kv.Value.(*ast.BasicLit)
if !ok { if !ok {
return m, newDecodeErrorf(expr, errNonStringAttribute) return m, newDecodeErrorf(expr, errNonStringAttribute)
@ -173,18 +176,20 @@ func (c *metricDecoder) decodeOpts(expr ast.Expr) (metric, error) {
m.Subsystem = value m.Subsystem = value
case "Name": case "Name":
m.Name = value m.Name = value
case "DeprecatedVersion":
m.DeprecatedVersion = value
case "Help": case "Help":
m.Help = value m.Help = value
} }
case "Buckets": case "Buckets":
buckets, err := decodeBuckets(kv) buckets, err := c.decodeBuckets(kv.Value)
if err != nil { if err != nil {
return m, err return m, err
} }
sort.Float64s(buckets) sort.Float64s(buckets)
m.Buckets = buckets m.Buckets = buckets
case "StabilityLevel": case "StabilityLevel":
level, err := decodeStabilityLevel(kv.Value, c.metricsImportName) level, err := decodeStabilityLevel(kv.Value, c.kubeMetricsImportName)
if err != nil { if err != nil {
return m, err return m, err
} }
@ -196,13 +201,46 @@ func (c *metricDecoder) decodeOpts(expr ast.Expr) (metric, error) {
return m, nil return m, nil
} }
func decodeBuckets(kv *ast.KeyValueExpr) ([]float64, error) { func (c *metricDecoder) decodeBuckets(expr ast.Expr) ([]float64, error) {
cl, ok := kv.Value.(*ast.CompositeLit) switch v := expr.(type) {
if !ok { case *ast.CompositeLit:
return nil, newDecodeErrorf(kv, errBuckets) return decodeListOfFloats(v.Elts)
case *ast.SelectorExpr:
variableName := v.Sel.String()
importName, ok := v.X.(*ast.Ident)
if ok && importName.String() == c.prometheusImportName && variableName == "DefBuckets" {
return prometheus.DefBuckets, nil
}
case *ast.CallExpr:
se, ok := v.Fun.(*ast.SelectorExpr)
if !ok {
return nil, newDecodeErrorf(v, errBuckets)
}
functionName := se.Sel.String()
functionImport, ok := se.X.(*ast.Ident)
if !ok {
return nil, newDecodeErrorf(v, errBuckets)
}
if functionImport.String() != c.prometheusImportName {
return nil, newDecodeErrorf(v, errBuckets)
}
firstArg, secondArg, thirdArg, err := decodeBucketArguments(v)
if err != nil {
return nil, err
}
switch functionName {
case "LinearBuckets":
return prometheus.LinearBuckets(firstArg, secondArg, thirdArg), nil
case "ExponentialBuckets":
return prometheus.ExponentialBuckets(firstArg, secondArg, thirdArg), nil
}
} }
buckets := make([]float64, len(cl.Elts)) return nil, newDecodeErrorf(expr, errBuckets)
for i, elt := range cl.Elts { }
func decodeListOfFloats(exprs []ast.Expr) ([]float64, error) {
buckets := make([]float64, len(exprs))
for i, elt := range exprs {
bl, ok := elt.(*ast.BasicLit) bl, ok := elt.(*ast.BasicLit)
if !ok { if !ok {
return nil, newDecodeErrorf(bl, errBuckets) return nil, newDecodeErrorf(bl, errBuckets)
@ -219,6 +257,37 @@ func decodeBuckets(kv *ast.KeyValueExpr) ([]float64, error) {
return buckets, nil return buckets, nil
} }
func decodeBucketArguments(fc *ast.CallExpr) (float64, float64, int, error) {
if len(fc.Args) != 3 {
return 0, 0, 0, newDecodeErrorf(fc, errBuckets)
}
strArgs := make([]string, len(fc.Args))
for i, elt := range fc.Args {
bl, ok := elt.(*ast.BasicLit)
if !ok {
return 0, 0, 0, newDecodeErrorf(bl, errBuckets)
}
if bl.Kind != token.FLOAT && bl.Kind != token.INT {
return 0, 0, 0, newDecodeErrorf(bl, errBuckets)
}
strArgs[i] = bl.Value
}
firstArg, err := strconv.ParseFloat(strArgs[0], 64)
if err != nil {
return 0, 0, 0, newDecodeErrorf(fc.Args[0], errBuckets)
}
secondArg, err := strconv.ParseFloat(strArgs[1], 64)
if err != nil {
return 0, 0, 0, newDecodeErrorf(fc.Args[1], errBuckets)
}
thirdArg, err := strconv.ParseInt(strArgs[2], 10, 64)
if err != nil {
return 0, 0, 0, newDecodeErrorf(fc.Args[2], errBuckets)
}
return firstArg, secondArg, int(thirdArg), nil
}
func decodeStabilityLevel(expr ast.Expr, metricsFrameworkImportName string) (*metrics.StabilityLevel, error) { func decodeStabilityLevel(expr ast.Expr, metricsFrameworkImportName string) (*metrics.StabilityLevel, error) {
se, ok := expr.(*ast.SelectorExpr) se, ok := expr.(*ast.SelectorExpr)
if !ok { if !ok {

View File

@ -30,9 +30,9 @@ const (
errInvalidNewMetricCall = "Invalid new metric call, please ensure code compiles" errInvalidNewMetricCall = "Invalid new metric call, please ensure code compiles"
errNonStringAttribute = "Non string attribute it not supported" errNonStringAttribute = "Non string attribute it not supported"
errFieldNotSupported = "Field %s is not supported" errFieldNotSupported = "Field %s is not supported"
errBuckets = "Buckets were not set to list of floats" errBuckets = "Buckets should be set to list of floats, result from function call of prometheus.LinearBuckets or prometheus.ExponentialBuckets"
errLabels = "Labels were not set to list of strings" errLabels = "Labels were not set to list of strings"
errImport = `Importing through "." metrics framework is not supported` errImport = `Importing using "." is not supported`
) )
type decodeError struct { type decodeError struct {

View File

@ -31,9 +31,12 @@ import (
) )
const ( const (
metricFrameworkPath = `"k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics"` kubeMetricImportPath = `"k8s.io/component-base/metrics"`
// Should equal to final directory name of metricFrameworkPath // Should equal to final directory name of kubeMetricImportPath
defaultFrameworkImportName = "metrics" kubeMetricsDefaultImportName = "metrics"
prometheusImportPath = `"github.com/prometheus/client_golang/prometheus"`
// Should equal to final directory name of kubeMetricImportPath
prometheusDefaultImportName = "prometheus"
) )
func main() { func main() {
@ -67,7 +70,7 @@ func main() {
} }
func searchPathForStableMetrics(path string) ([]metric, []error) { func searchPathForStableMetrics(path string) ([]metric, []error) {
ms := []metric{} metrics := []metric{}
errors := []error{} errors := []error{}
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if strings.HasPrefix(path, "vendor") { if strings.HasPrefix(path, "vendor") {
@ -78,13 +81,13 @@ func searchPathForStableMetrics(path string) ([]metric, []error) {
} }
ms, es := searchFileForStableMetrics(path, nil) ms, es := searchFileForStableMetrics(path, nil)
errors = append(errors, es...) errors = append(errors, es...)
ms = append(ms, ms...) metrics = append(metrics, ms...)
return nil return nil
}) })
if err != nil { if err != nil {
errors = append(errors, err) errors = append(errors, err)
} }
return ms, errors return metrics, errors
} }
// Pass either only filename of existing file or src including source code in any format and a filename that it comes from // Pass either only filename of existing file or src including source code in any format and a filename that it comes from
@ -94,26 +97,30 @@ func searchFileForStableMetrics(filename string, src interface{}) ([]metric, []e
if err != nil { if err != nil {
return []metric{}, []error{err} return []metric{}, []error{err}
} }
metricsImportName, err := getMetricsFrameworkImportName(tree) metricsImportName, err := getLocalNameOfImportedPackage(tree, kubeMetricImportPath, kubeMetricsDefaultImportName)
if err != nil { if err != nil {
return []metric{}, addFileInformationToErrors([]error{err}, fileset) return []metric{}, addFileInformationToErrors([]error{err}, fileset)
} }
if metricsImportName == "" { if metricsImportName == "" {
return []metric{}, []error{} return []metric{}, []error{}
} }
prometheusImportName, err := getLocalNameOfImportedPackage(tree, prometheusImportPath, prometheusDefaultImportName)
if err != nil {
return []metric{}, addFileInformationToErrors([]error{err}, fileset)
}
stableMetricsFunctionCalls, errors := findStableMetricDeclaration(tree, metricsImportName) stableMetricsFunctionCalls, errors := findStableMetricDeclaration(tree, metricsImportName)
metrics, es := decodeMetricCalls(stableMetricsFunctionCalls, metricsImportName) metrics, es := decodeMetricCalls(stableMetricsFunctionCalls, metricsImportName, prometheusImportName)
errors = append(errors, es...) errors = append(errors, es...)
return metrics, addFileInformationToErrors(errors, fileset) return metrics, addFileInformationToErrors(errors, fileset)
} }
func getMetricsFrameworkImportName(tree *ast.File) (string, error) { func getLocalNameOfImportedPackage(tree *ast.File, importPath, defaultImportName string) (string, error) {
var importName string var importName string
for _, im := range tree.Imports { for _, im := range tree.Imports {
if im.Path.Value == metricFrameworkPath { if im.Path.Value == importPath {
if im.Name == nil { if im.Name == nil {
importName = defaultFrameworkImportName importName = defaultImportName
} else { } else {
if im.Name.Name == "." { if im.Name.Name == "." {
return "", newDecodeErrorf(im, errImport) return "", newDecodeErrorf(im, errImport)

View File

@ -20,6 +20,8 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"testing" "testing"
"github.com/prometheus/client_golang/prometheus"
) )
const fakeFilename = "testdata/metric.go" const fakeFilename = "testdata/metric.go"
@ -33,7 +35,7 @@ func TestSkipMetrics(t *testing.T) {
testName: "Skip alpha metric with local variable", testName: "Skip alpha metric with local variable",
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var name = "metric" var name = "metric"
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
@ -46,7 +48,7 @@ var _ = metrics.NewCounter(
testName: "Skip alpha metric created via function call", testName: "Skip alpha metric created via function call",
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
func getName() string { func getName() string {
return "metric" return "metric"
} }
@ -61,7 +63,7 @@ var _ = metrics.NewCounter(
testName: "Skip metric without stability set", testName: "Skip metric without stability set",
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
Name: "metric", Name: "metric",
@ -123,22 +125,24 @@ func TestStableMetric(t *testing.T) {
{ {
testName: "Counter", testName: "Counter",
metric: metric{ metric: metric{
Name: "metric", Name: "metric",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
StabilityLevel: "STABLE", StabilityLevel: "STABLE",
Help: "help", DeprecatedVersion: "1.16",
Type: counterMetricType, Help: "help",
Type: counterMetricType,
}, },
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
Name: "metric", Name: "metric",
Subsystem: "subsystem", Subsystem: "subsystem",
Namespace: "namespace", Namespace: "namespace",
Help: "help", Help: "help",
DeprecatedVersion: "1.16",
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
}, },
) )
@ -146,23 +150,25 @@ var _ = metrics.NewCounter(
{ {
testName: "CounterVec", testName: "CounterVec",
metric: metric{ metric: metric{
Name: "metric", Name: "metric",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
Labels: []string{"label-1"}, Labels: []string{"label-1"},
StabilityLevel: "STABLE", StabilityLevel: "STABLE",
Help: "help", DeprecatedVersion: "1.16",
Type: counterMetricType, Help: "help",
Type: counterMetricType,
}, },
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewCounterVec( var _ = metrics.NewCounterVec(
&metrics.CounterOpts{ &metrics.CounterOpts{
Name: "metric", Name: "metric",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
Help: "help", Help: "help",
DeprecatedVersion: "1.16",
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
}, },
[]string{"label-1"}, []string{"label-1"},
@ -171,22 +177,24 @@ var _ = metrics.NewCounterVec(
{ {
testName: "Gauge", testName: "Gauge",
metric: metric{ metric: metric{
Name: "gauge", Name: "gauge",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
StabilityLevel: "STABLE", StabilityLevel: "STABLE",
Help: "help", DeprecatedVersion: "1.16",
Type: gaugeMetricType, Help: "help",
Type: gaugeMetricType,
}, },
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewGauge( var _ = metrics.NewGauge(
&metrics.GaugeOpts{ &metrics.GaugeOpts{
Name: "gauge", Name: "gauge",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
Help: "help", Help: "help",
DeprecatedVersion: "1.16",
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
}, },
) )
@ -194,23 +202,25 @@ var _ = metrics.NewGauge(
{ {
testName: "GaugeVec", testName: "GaugeVec",
metric: metric{ metric: metric{
Name: "gauge", Name: "gauge",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
StabilityLevel: "STABLE", StabilityLevel: "STABLE",
Help: "help", DeprecatedVersion: "1.16",
Type: gaugeMetricType, Help: "help",
Labels: []string{"label-1", "label-2"}, Type: gaugeMetricType,
Labels: []string{"label-1", "label-2"},
}, },
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewGaugeVec( var _ = metrics.NewGaugeVec(
&metrics.GaugeOpts{ &metrics.GaugeOpts{
Name: "gauge", Name: "gauge",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
Help: "help", Help: "help",
DeprecatedVersion: "1.16",
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
}, },
[]string{"label-2", "label-1"}, []string{"label-2", "label-1"},
@ -219,17 +229,18 @@ var _ = metrics.NewGaugeVec(
{ {
testName: "Histogram", testName: "Histogram",
metric: metric{ metric: metric{
Name: "histogram", Name: "histogram",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
StabilityLevel: "STABLE", DeprecatedVersion: "1.16",
Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100}, StabilityLevel: "STABLE",
Help: "help", Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100},
Type: histogramMetricType, Help: "help",
Type: histogramMetricType,
}, },
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewHistogram( var _ = metrics.NewHistogram(
&metrics.HistogramOpts{ &metrics.HistogramOpts{
Name: "histogram", Name: "histogram",
@ -237,6 +248,7 @@ var _ = metrics.NewHistogram(
Subsystem: "subsystem", Subsystem: "subsystem",
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
Help: "help", Help: "help",
DeprecatedVersion: "1.16",
Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100}, Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100},
}, },
) )
@ -244,18 +256,19 @@ var _ = metrics.NewHistogram(
{ {
testName: "HistogramVec", testName: "HistogramVec",
metric: metric{ metric: metric{
Name: "histogram", Name: "histogram",
Namespace: "namespace", Namespace: "namespace",
Subsystem: "subsystem", Subsystem: "subsystem",
StabilityLevel: "STABLE", DeprecatedVersion: "1.16",
Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100}, StabilityLevel: "STABLE",
Help: "help", Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100},
Type: histogramMetricType, Help: "help",
Labels: []string{"label-1", "label-2"}, Type: histogramMetricType,
Labels: []string{"label-1", "label-2"},
}, },
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewHistogramVec( var _ = metrics.NewHistogramVec(
&metrics.HistogramOpts{ &metrics.HistogramOpts{
Name: "histogram", Name: "histogram",
@ -263,6 +276,7 @@ var _ = metrics.NewHistogramVec(
Subsystem: "subsystem", Subsystem: "subsystem",
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
Help: "help", Help: "help",
DeprecatedVersion: "1.16",
Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100}, Buckets: []float64{0.001, 0.01, 0.1, 1, 10, 100},
}, },
[]string{"label-2", "label-1"}, []string{"label-2", "label-1"},
@ -277,13 +291,73 @@ var _ = metrics.NewHistogramVec(
}, },
src: ` src: `
package test package test
import custom "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import custom "k8s.io/component-base/metrics"
var _ = custom.NewCounter( var _ = custom.NewCounter(
&custom.CounterOpts{ &custom.CounterOpts{
Name: "metric", Name: "metric",
StabilityLevel: custom.STABLE, StabilityLevel: custom.STABLE,
}, },
) )
`},
{
testName: "Histogram with linear buckets",
metric: metric{
Name: "histogram",
StabilityLevel: "STABLE",
Buckets: prometheus.LinearBuckets(1, 1, 3),
Type: histogramMetricType,
},
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.LinearBuckets(1, 1, 3),
},
)
`},
{
testName: "Histogram with exponential buckets",
metric: metric{
Name: "histogram",
StabilityLevel: "STABLE",
Buckets: prometheus.ExponentialBuckets(1, 2, 3),
Type: histogramMetricType,
},
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.ExponentialBuckets(1, 2, 3),
},
)
`},
{
testName: "Histogram with default buckets",
metric: metric{
Name: "histogram",
StabilityLevel: "STABLE",
Buckets: prometheus.DefBuckets,
Type: histogramMetricType,
},
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) { t.Run(test.testName, func(t *testing.T) {
@ -315,7 +389,7 @@ func TestIncorrectStableMetricDeclarations(t *testing.T) {
err: fmt.Errorf("testdata/metric.go:4:9: Stable summary metric is not supported"), err: fmt.Errorf("testdata/metric.go:4:9: Stable summary metric is not supported"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewSummary( var _ = metrics.NewSummary(
&metrics.SummaryOpts{ &metrics.SummaryOpts{
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
@ -327,7 +401,7 @@ var _ = metrics.NewSummary(
err: fmt.Errorf("testdata/metric.go:7:4: Non string attribute it not supported"), err: fmt.Errorf("testdata/metric.go:7:4: Non string attribute it not supported"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
const name = "metric" const name = "metric"
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
@ -341,7 +415,7 @@ var _ = metrics.NewCounter(
err: fmt.Errorf("testdata/metric.go:9:4: Non string attribute it not supported"), err: fmt.Errorf("testdata/metric.go:9:4: Non string attribute it not supported"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
func getName() string { func getName() string {
return "metric" return "metric"
} }
@ -357,7 +431,7 @@ var _ = metrics.NewCounter(
err: fmt.Errorf("testdata/metric.go:7:4: Non string attribute it not supported"), err: fmt.Errorf("testdata/metric.go:7:4: Non string attribute it not supported"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
import "k8s.io/kubernetes/utils" import "k8s.io/kubernetes/utils"
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
@ -371,7 +445,7 @@ var _ = metrics.NewCounter(
err: fmt.Errorf("testdata/metric.go:9:20: StabilityLevel should be passed STABLE, ALPHA or removed"), err: fmt.Errorf("testdata/metric.go:9:20: StabilityLevel should be passed STABLE, ALPHA or removed"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
func getMetricStability() metrics.StabilityLevel { func getMetricStability() metrics.StabilityLevel {
return metrics.STABLE return metrics.STABLE
} }
@ -386,7 +460,7 @@ var _ = metrics.NewCounter(
err: fmt.Errorf("testdata/metric.go:6:20: StabilityLevel should be passed STABLE, ALPHA or removed"), err: fmt.Errorf("testdata/metric.go:6:20: StabilityLevel should be passed STABLE, ALPHA or removed"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
StabilityLevel: "stable", StabilityLevel: "stable",
@ -398,7 +472,7 @@ var _ = metrics.NewCounter(
err: fmt.Errorf("testdata/metric.go:6:20: StabilityLevel should be passed STABLE, ALPHA or removed"), err: fmt.Errorf("testdata/metric.go:6:20: StabilityLevel should be passed STABLE, ALPHA or removed"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
StabilityLevel: metrics.UNKNOWN, StabilityLevel: metrics.UNKNOWN,
@ -410,7 +484,7 @@ var _ = metrics.NewCounter(
err: fmt.Errorf("testdata/metric.go:7:20: StabilityLevel should be passed STABLE, ALPHA or removed"), err: fmt.Errorf("testdata/metric.go:7:20: StabilityLevel should be passed STABLE, ALPHA or removed"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var stable = metrics.STABLE var stable = metrics.STABLE
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
@ -423,7 +497,7 @@ var _ = metrics.NewCounter(
err: fmt.Errorf("testdata/metric.go:6:10: Opts for STABLE metric was not directly passed to new metric function"), err: fmt.Errorf("testdata/metric.go:6:10: Opts for STABLE metric was not directly passed to new metric function"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewCounter(getStableCounterOpts()) var _ = metrics.NewCounter(getStableCounterOpts())
func getStableCounterOpts() *metrics.CounterOpts { func getStableCounterOpts() *metrics.CounterOpts {
return &metrics.CounterOpts{ return &metrics.CounterOpts{
@ -433,10 +507,10 @@ func getStableCounterOpts() *metrics.CounterOpts {
`}, `},
{ {
testName: "error . package import of metric framework", testName: "error . package import of metric framework",
err: fmt.Errorf(`testdata/metric.go:3:8: Importing through "." metrics framework is not supported`), err: fmt.Errorf(`testdata/metric.go:3:8: Importing using "." is not supported`),
src: ` src: `
package test package test
import . "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import . "k8s.io/component-base/metrics"
var _ = NewCounter( var _ = NewCounter(
&CounterOpts{ &CounterOpts{
StabilityLevel: STABLE, StabilityLevel: STABLE,
@ -448,7 +522,7 @@ var _ = NewCounter(
err: fmt.Errorf("testdata/metric.go:4:9: Opts for STABLE metric was not directly passed to new metric function"), err: fmt.Errorf("testdata/metric.go:4:9: Opts for STABLE metric was not directly passed to new metric function"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = RegisterMetric( var _ = RegisterMetric(
&metrics.CounterOpts{ &metrics.CounterOpts{
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
@ -460,7 +534,7 @@ var _ = RegisterMetric(
err: fmt.Errorf("testdata/metric.go:4:9: Opts for STABLE metric was not directly passed to new metric function"), err: fmt.Errorf("testdata/metric.go:4:9: Opts for STABLE metric was not directly passed to new metric function"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = test.RegisterMetric( var _ = test.RegisterMetric(
&metrics.CounterOpts{ &metrics.CounterOpts{
StabilityLevel: metrics.STABLE, StabilityLevel: metrics.STABLE,
@ -472,12 +546,57 @@ var _ = test.RegisterMetric(
err: fmt.Errorf("testdata/metric.go:6:4: Positional arguments are not supported"), err: fmt.Errorf("testdata/metric.go:6:4: Positional arguments are not supported"),
src: ` src: `
package test package test
import "k8s.io/kubernetes/staging/src/k8s.io/component-base/metrics" import "k8s.io/component-base/metrics"
var _ = metrics.NewCounter( var _ = metrics.NewCounter(
&metrics.CounterOpts{ &metrics.CounterOpts{
"counter", "counter",
}, },
) )
`},
{
testName: "error stable historgram 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 historgram with unknown 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"
var buckets = []float64{1, 2, 3}
var _ = metrics.NewHistogram(
&metrics.HistogramOpts{
Name: "histogram",
StabilityLevel: metrics.STABLE,
Buckets: buckets,
},
)
`},
{
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/fake_prometheus/prometheus"
var _ = metrics.NewHistogram(
&metrics.HistogramOpts{
Name: "histogram",
StabilityLevel: metrics.STABLE,
Buckets: prometheus.DefBuckets,
},
)
`}, `},
} { } {
t.Run(test.testName, func(t *testing.T) { t.Run(test.testName, func(t *testing.T) {