mirror of https://github.com/knative/pkg.git
445 lines
12 KiB
Go
445 lines
12 KiB
Go
/*
|
|
Copyright 2020 The Knative 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 metricstest simplifies some of the common boilerplate around testing
|
|
// metrics exports. It should work with or without the code in metrics, but this
|
|
// code particularly knows how to deal with metrics which are exported for
|
|
// multiple Resources in the same process.
|
|
package metricstest
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"go.opencensus.io/metric/metricdata"
|
|
"go.opencensus.io/resource"
|
|
"go.opencensus.io/stats"
|
|
"go.opencensus.io/stats/view"
|
|
"go.opencensus.io/tag"
|
|
)
|
|
|
|
func TestMetricEqual(t *testing.T) {
|
|
pointValues := []int64{127, -1}
|
|
baseValue := &metricdata.Metric{
|
|
Descriptor: metricdata.Descriptor{
|
|
Name: "testing/metric",
|
|
Unit: metricdata.UnitMilliseconds,
|
|
Type: metricdata.TypeGaugeInt64,
|
|
LabelKeys: []metricdata.LabelKey{{"key1", ""}, {"key2", ""}},
|
|
},
|
|
Resource: &resource.Resource{
|
|
Type: "testObject",
|
|
Labels: map[string]string{"rl1": "aaa", "rl2": "bbb"},
|
|
},
|
|
TimeSeries: []*metricdata.TimeSeries{
|
|
{
|
|
LabelValues: []metricdata.LabelValue{{"val1", true}, {"val2", true}},
|
|
Points: []metricdata.Point{metricdata.NewInt64Point(time.Now(), pointValues[0])},
|
|
},
|
|
{
|
|
LabelValues: []metricdata.LabelValue{{"val1", true}, {"val3", true}},
|
|
Points: []metricdata.Point{metricdata.NewInt64Point(time.Now(), pointValues[1])},
|
|
},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
want *Metric
|
|
notEqual bool
|
|
}{{
|
|
name: "Minimal test",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
},
|
|
}, {
|
|
name: "Test resource not equal",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
VerifyResource: true,
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Test unit not equal",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
Unit: metricdata.UnitBytes,
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Test unit missing",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
Type: metricdata.TypeGaugeInt64,
|
|
VerifyMetadata: true,
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Test type not equal",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
Unit: metricdata.UnitMilliseconds,
|
|
Type: metricdata.TypeCumulativeInt64,
|
|
VerifyMetadata: true,
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Check resource",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
Resource: &resource.Resource{
|
|
Type: "testObject",
|
|
Labels: map[string]string{"rl2": "bbb", "rl1": "aaa"},
|
|
},
|
|
},
|
|
}, {
|
|
name: "Mismatched resource",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
Resource: &resource.Resource{
|
|
Type: "testObject",
|
|
Labels: map[string]string{"rl1": "aaa"},
|
|
},
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Test value match",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
Values: []Value{
|
|
{
|
|
Tags: map[string]string{"key1": "val1", "key2": "val2"},
|
|
Int64: &pointValues[0],
|
|
}, {
|
|
Tags: map[string]string{"key1": "val1", "key2": "val3"},
|
|
Int64: &pointValues[1],
|
|
},
|
|
},
|
|
},
|
|
}, {
|
|
name: "Too few values",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
Values: []Value{
|
|
{
|
|
Tags: map[string]string{"key1": "val1", "key2": "val2"},
|
|
Int64: &pointValues[0],
|
|
},
|
|
},
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Wrong tags",
|
|
want: &Metric{
|
|
Name: "testing/metric",
|
|
Values: []Value{
|
|
{
|
|
Tags: map[string]string{"key1": "val1", "key2": "val2"},
|
|
Int64: &pointValues[0],
|
|
},
|
|
{
|
|
Tags: map[string]string{"key1": "val1", "key2": "bbb"},
|
|
Int64: &pointValues[1],
|
|
},
|
|
},
|
|
},
|
|
notEqual: true,
|
|
}}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
m := NewMetric(baseValue) // cmp needs to match types to find the Equal method.
|
|
if diff := cmp.Diff(tc.want, &m); (diff == "") == tc.notEqual {
|
|
t.Errorf("Metric.Equal() = %t failed (-want +base):\n%s", !tc.notEqual, diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func buckets(v ...int64) []metricdata.Bucket {
|
|
ret := []metricdata.Bucket{}
|
|
for _, c := range v {
|
|
ret = append(ret, metricdata.Bucket{Count: c})
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func bucketOpts(bounds ...float64) *metricdata.BucketOptions {
|
|
return &metricdata.BucketOptions{Bounds: bounds}
|
|
}
|
|
|
|
func TestDistributionEqual(t *testing.T) {
|
|
baseValue := NewMetric(&metricdata.Metric{
|
|
Descriptor: metricdata.Descriptor{
|
|
Name: "testing/distribution",
|
|
LabelKeys: []metricdata.LabelKey{{"key1", ""}},
|
|
},
|
|
TimeSeries: []*metricdata.TimeSeries{
|
|
{
|
|
LabelValues: []metricdata.LabelValue{{"val1", true}},
|
|
Points: []metricdata.Point{metricdata.NewDistributionPoint(
|
|
time.Now(),
|
|
&metricdata.Distribution{
|
|
Count: 5, // Values: 0.5, 5, 5, 5, 10
|
|
Sum: 25.5,
|
|
SumOfSquaredDeviation: 45.2,
|
|
BucketOptions: bucketOpts(2, 4, 8),
|
|
Buckets: buckets(1, 0, 3, 1),
|
|
},
|
|
)},
|
|
},
|
|
},
|
|
})
|
|
floatVal := -3.22
|
|
|
|
tests := []struct {
|
|
name string
|
|
want Value
|
|
notEqual bool
|
|
}{{
|
|
name: "Equal",
|
|
want: Value{
|
|
Tags: map[string]string{"key1": "val1"},
|
|
Distribution: &metricdata.Distribution{
|
|
Count: 5,
|
|
Sum: 25.5,
|
|
SumOfSquaredDeviation: 45.2,
|
|
BucketOptions: bucketOpts(2, 4, 8),
|
|
Buckets: buckets(1, 0, 3, 1),
|
|
},
|
|
},
|
|
}, {
|
|
name: "Equal when count only is set",
|
|
want: Value{
|
|
Tags: map[string]string{"key1": "val1"},
|
|
Distribution: &metricdata.Distribution{
|
|
Count: 5,
|
|
},
|
|
VerifyDistributionCountOnly: true,
|
|
},
|
|
}, {
|
|
name: "Not equal when count only is not set",
|
|
want: Value{
|
|
Tags: map[string]string{"key1": "val1"},
|
|
Distribution: &metricdata.Distribution{
|
|
Count: 5,
|
|
},
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Missing summary",
|
|
want: Value{
|
|
Tags: map[string]string{"key1": "val1"},
|
|
Distribution: &metricdata.Distribution{
|
|
BucketOptions: bucketOpts(2, 4, 8),
|
|
Buckets: buckets(1, 0, 3, 1),
|
|
},
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Wrong bucket splits",
|
|
want: Value{
|
|
Tags: map[string]string{"key1": "val1"},
|
|
Distribution: &metricdata.Distribution{
|
|
Count: 5,
|
|
Sum: 25.5,
|
|
SumOfSquaredDeviation: 45.2,
|
|
BucketOptions: bucketOpts(1, 2, 3, 5, 8),
|
|
Buckets: buckets(1, 0, 3, 1),
|
|
},
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Wrong bucket values",
|
|
want: Value{
|
|
Tags: map[string]string{"key1": "val1"},
|
|
Distribution: &metricdata.Distribution{
|
|
Count: 5,
|
|
Sum: 25.5,
|
|
SumOfSquaredDeviation: 45.2,
|
|
BucketOptions: bucketOpts(2, 4, 8),
|
|
Buckets: buckets(1, 3, 1, 0),
|
|
},
|
|
},
|
|
notEqual: true,
|
|
}, {
|
|
name: "Wrong type",
|
|
want: Value{
|
|
Tags: map[string]string{"key1": "val1"},
|
|
Float64: &floatVal,
|
|
},
|
|
notEqual: true,
|
|
}}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
wantMetric := Metric{
|
|
Name: "testing/distribution",
|
|
Values: []Value{tc.want},
|
|
}
|
|
if diff := cmp.Diff(&wantMetric, &baseValue); (diff == "") == tc.notEqual {
|
|
t.Errorf("Value.Equal() = %t failed (-want +base):\n%s", !tc.notEqual, diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMetricShortcuts(t *testing.T) {
|
|
tags := map[string]string{
|
|
"foo": "bar",
|
|
}
|
|
r := &resource.Resource{
|
|
Type: "test-resource",
|
|
Labels: map[string]string{"foo1": "bar1"},
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
want Metric
|
|
got metricdata.Metric
|
|
}{{
|
|
name: "IntMetric",
|
|
want: IntMetric("test/int", 17, map[string]string{"key1": "val1", "key2": "val2"}),
|
|
got: metricdata.Metric{
|
|
Descriptor: metricdata.Descriptor{
|
|
Name: "test/int",
|
|
LabelKeys: []metricdata.LabelKey{{"key1", ""}, {"key2", ""}},
|
|
},
|
|
TimeSeries: []*metricdata.TimeSeries{{
|
|
LabelValues: []metricdata.LabelValue{{"val1", true}, {"val2", true}},
|
|
Points: []metricdata.Point{metricdata.NewInt64Point(time.Now(), 17)},
|
|
}},
|
|
},
|
|
}, {
|
|
name: "FloatMetric",
|
|
want: FloatMetric("test/float", 0.17, map[string]string{"key1": "val1", "key2": "val2"}),
|
|
got: metricdata.Metric{
|
|
Descriptor: metricdata.Descriptor{
|
|
Name: "test/float",
|
|
LabelKeys: []metricdata.LabelKey{{"key1", ""}, {"key2", ""}},
|
|
},
|
|
TimeSeries: []*metricdata.TimeSeries{{
|
|
LabelValues: []metricdata.LabelValue{{"val1", true}, {"val2", true}},
|
|
Points: []metricdata.Point{metricdata.NewFloat64Point(time.Now(), 0.17)},
|
|
}},
|
|
},
|
|
}, {
|
|
name: "IntMetricWithResource",
|
|
want: IntMetric("test/int", 18, tags).WithResource(r),
|
|
got: metricdata.Metric{
|
|
Descriptor: metricdata.Descriptor{
|
|
Name: "test/int",
|
|
LabelKeys: []metricdata.LabelKey{{"foo", ""}},
|
|
},
|
|
Resource: r,
|
|
TimeSeries: []*metricdata.TimeSeries{{
|
|
LabelValues: []metricdata.LabelValue{{"bar", true}},
|
|
Points: []metricdata.Point{metricdata.NewInt64Point(time.Now(), 18)},
|
|
}},
|
|
},
|
|
}, {
|
|
name: "FloatMetricWithResource",
|
|
want: FloatMetric("test/float", 0.18, tags).WithResource(r),
|
|
got: metricdata.Metric{
|
|
Descriptor: metricdata.Descriptor{
|
|
Name: "test/float",
|
|
LabelKeys: []metricdata.LabelKey{{"foo", ""}},
|
|
},
|
|
Resource: r,
|
|
TimeSeries: []*metricdata.TimeSeries{{
|
|
LabelValues: []metricdata.LabelValue{{"bar", true}},
|
|
Points: []metricdata.Point{metricdata.NewFloat64Point(time.Now(), 0.18)},
|
|
}},
|
|
},
|
|
}, {
|
|
name: "DistributionCountOnlyMetricWithResource",
|
|
want: DistributionCountOnlyMetric("test/distribution", 19, tags).WithResource(r),
|
|
got: metricdata.Metric{
|
|
Descriptor: metricdata.Descriptor{
|
|
Name: "test/distribution",
|
|
LabelKeys: []metricdata.LabelKey{{"foo", ""}},
|
|
},
|
|
Resource: r,
|
|
TimeSeries: []*metricdata.TimeSeries{{
|
|
LabelValues: []metricdata.LabelValue{{"bar", true}},
|
|
Points: []metricdata.Point{metricdata.NewDistributionPoint(time.Now(), &metricdata.Distribution{
|
|
Count: 19,
|
|
Sum: 25.5,
|
|
SumOfSquaredDeviation: 45.2,
|
|
BucketOptions: bucketOpts(2, 4, 8),
|
|
Buckets: buckets(1, 3, 1, 0),
|
|
})},
|
|
}},
|
|
},
|
|
}}
|
|
|
|
for _, tc := range tests {
|
|
if diff := cmp.Diff(tc.want, NewMetric(&tc.got)); diff != "" {
|
|
t.Errorf("Metric.Equal() failed (-want +got): %s", diff)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMetricFetch(t *testing.T) {
|
|
count := stats.Int64("count", "Test count metric", stats.UnitBytes)
|
|
tagKey := tag.MustNewKey("tag")
|
|
countView := &view.View{
|
|
Measure: count,
|
|
Aggregation: view.Sum(),
|
|
TagKeys: []tag.Key{tagKey},
|
|
}
|
|
|
|
view.Register(countView)
|
|
|
|
ctx, err := tag.New(context.Background(), tag.Upsert(tagKey, "alpha"))
|
|
if err != nil {
|
|
t.Errorf("Unable to create context: %v", err)
|
|
}
|
|
stats.Record(ctx, count.M(5))
|
|
stats.Record(ctx, count.M(3))
|
|
|
|
AssertMetricExists(t, "count")
|
|
AssertNoMetric(t, "other")
|
|
|
|
ctx, err = tag.New(ctx, tag.Upsert(tagKey, "beta"))
|
|
if err != nil {
|
|
t.Errorf("Unable to create context: %v", err)
|
|
}
|
|
stats.Record(ctx, count.M(20))
|
|
EnsureRecorded()
|
|
m := GetMetric("count")
|
|
|
|
if len(m) != 1 {
|
|
t.Errorf("Unexpected number of found metrics (%d): %+v", len(m), m)
|
|
}
|
|
|
|
alphaValue, betaValue := int64(8), int64(20)
|
|
|
|
want := Metric{
|
|
Name: "count",
|
|
Type: metricdata.TypeCumulativeInt64,
|
|
Unit: metricdata.UnitBytes,
|
|
Values: []Value{
|
|
{Tags: map[string]string{"tag": "alpha"}, Int64: &alphaValue},
|
|
{Tags: map[string]string{"tag": "beta"}, Int64: &betaValue},
|
|
},
|
|
}
|
|
if diff := cmp.Diff(want, m[0]); diff != "" {
|
|
t.Errorf("Incorrect received metrics (-want +got): %s", diff)
|
|
}
|
|
|
|
}
|