mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2024-12-27 21:00:19 +01:00
492 lines
12 KiB
Go
492 lines
12 KiB
Go
// Copyright 2017, OpenCensus 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 view
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
"go.opencensus.io/exemplar"
|
|
|
|
"go.opencensus.io/stats"
|
|
"go.opencensus.io/tag"
|
|
)
|
|
|
|
func Test_View_MeasureFloat64_AggregationDistribution(t *testing.T) {
|
|
k1, _ := tag.NewKey("k1")
|
|
k2, _ := tag.NewKey("k2")
|
|
k3, _ := tag.NewKey("k3")
|
|
agg1 := Distribution(2)
|
|
m := stats.Int64("Test_View_MeasureFloat64_AggregationDistribution/m1", "", stats.UnitDimensionless)
|
|
view1 := &View{
|
|
TagKeys: []tag.Key{k1, k2},
|
|
Measure: m,
|
|
Aggregation: agg1,
|
|
}
|
|
view, err := newViewInternal(view1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
type tagString struct {
|
|
k tag.Key
|
|
v string
|
|
}
|
|
type record struct {
|
|
f float64
|
|
tags []tagString
|
|
}
|
|
|
|
type testCase struct {
|
|
label string
|
|
records []record
|
|
wantRows []*Row
|
|
}
|
|
|
|
tcs := []testCase{
|
|
{
|
|
"1",
|
|
[]record{
|
|
{1, []tagString{{k1, "v1"}}},
|
|
{5, []tagString{{k1, "v1"}}},
|
|
},
|
|
[]*Row{
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1"}},
|
|
&DistributionData{
|
|
Count: 2, Min: 1, Max: 5, Mean: 3, SumOfSquaredDev: 8, CountPerBucket: []int64{1, 1}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"2",
|
|
[]record{
|
|
{1, []tagString{{k1, "v1"}}},
|
|
{5, []tagString{{k2, "v2"}}},
|
|
},
|
|
[]*Row{
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1"}},
|
|
&DistributionData{
|
|
Count: 1, Min: 1, Max: 1, Mean: 1, CountPerBucket: []int64{1, 0}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k2, Value: "v2"}},
|
|
&DistributionData{
|
|
Count: 1, Min: 5, Max: 5, Mean: 5, CountPerBucket: []int64{0, 1}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"3",
|
|
[]record{
|
|
{1, []tagString{{k1, "v1"}}},
|
|
{5, []tagString{{k1, "v1"}, {k3, "v3"}}},
|
|
{1, []tagString{{k1, "v1 other"}}},
|
|
{5, []tagString{{k2, "v2"}}},
|
|
{5, []tagString{{k1, "v1"}, {k2, "v2"}}},
|
|
},
|
|
[]*Row{
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1"}},
|
|
&DistributionData{
|
|
Count: 2, Min: 1, Max: 5, Mean: 3, SumOfSquaredDev: 8, CountPerBucket: []int64{1, 1}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1 other"}},
|
|
&DistributionData{
|
|
Count: 1, Min: 1, Max: 1, Mean: 1, CountPerBucket: []int64{1, 0}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k2, Value: "v2"}},
|
|
&DistributionData{
|
|
Count: 1, Min: 5, Max: 5, Mean: 5, CountPerBucket: []int64{0, 1}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1"}, {Key: k2, Value: "v2"}},
|
|
&DistributionData{
|
|
Count: 1, Min: 5, Max: 5, Mean: 5, CountPerBucket: []int64{0, 1}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"4",
|
|
[]record{
|
|
{1, []tagString{{k1, "v1 is a very long value key"}}},
|
|
{5, []tagString{{k1, "v1 is a very long value key"}, {k3, "v3"}}},
|
|
{1, []tagString{{k1, "v1 is another very long value key"}}},
|
|
{1, []tagString{{k1, "v1 is a very long value key"}, {k2, "v2 is a very long value key"}}},
|
|
{5, []tagString{{k1, "v1 is a very long value key"}, {k2, "v2 is a very long value key"}}},
|
|
{3, []tagString{{k1, "v1 is a very long value key"}, {k2, "v2 is a very long value key"}}},
|
|
{3, []tagString{{k1, "v1 is a very long value key"}, {k2, "v2 is a very long value key"}}},
|
|
},
|
|
[]*Row{
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1 is a very long value key"}},
|
|
&DistributionData{
|
|
Count: 2, Min: 1, Max: 5, Mean: 3, SumOfSquaredDev: 8, CountPerBucket: []int64{1, 1}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1 is another very long value key"}},
|
|
&DistributionData{
|
|
Count: 1, Min: 1, Max: 1, Mean: 1, CountPerBucket: []int64{1, 0}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1 is a very long value key"}, {Key: k2, Value: "v2 is a very long value key"}},
|
|
&DistributionData{
|
|
Count: 4, Min: 1, Max: 5, Mean: 3, SumOfSquaredDev: 2.66666666666667 * 3, CountPerBucket: []int64{1, 3}, bounds: []float64{2}, ExemplarsPerBucket: []*exemplar.Exemplar{nil, nil},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tcs {
|
|
view.clearRows()
|
|
view.subscribe()
|
|
for _, r := range tc.records {
|
|
mods := []tag.Mutator{}
|
|
for _, t := range r.tags {
|
|
mods = append(mods, tag.Insert(t.k, t.v))
|
|
}
|
|
ctx, err := tag.New(context.Background(), mods...)
|
|
if err != nil {
|
|
t.Errorf("%v: New = %v", tc.label, err)
|
|
}
|
|
e := &exemplar.Exemplar{
|
|
Value: r.f,
|
|
Attachments: exemplar.AttachmentsFromContext(ctx),
|
|
}
|
|
view.addSample(tag.FromContext(ctx), e)
|
|
}
|
|
|
|
gotRows := view.collectedRows()
|
|
for i, got := range gotRows {
|
|
if !containsRow(tc.wantRows, got) {
|
|
t.Errorf("%v-%d: got row %v; want none", tc.label, i, got)
|
|
break
|
|
}
|
|
}
|
|
|
|
for i, want := range tc.wantRows {
|
|
if !containsRow(gotRows, want) {
|
|
t.Errorf("%v-%d: got none; want row %v", tc.label, i, want)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func Test_View_MeasureFloat64_AggregationSum(t *testing.T) {
|
|
k1, _ := tag.NewKey("k1")
|
|
k2, _ := tag.NewKey("k2")
|
|
k3, _ := tag.NewKey("k3")
|
|
m := stats.Int64("Test_View_MeasureFloat64_AggregationSum/m1", "", stats.UnitDimensionless)
|
|
view, err := newViewInternal(&View{TagKeys: []tag.Key{k1, k2}, Measure: m, Aggregation: Sum()})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
type tagString struct {
|
|
k tag.Key
|
|
v string
|
|
}
|
|
type record struct {
|
|
f float64
|
|
tags []tagString
|
|
}
|
|
|
|
tcs := []struct {
|
|
label string
|
|
records []record
|
|
wantRows []*Row
|
|
}{
|
|
{
|
|
"1",
|
|
[]record{
|
|
{1, []tagString{{k1, "v1"}}},
|
|
{5, []tagString{{k1, "v1"}}},
|
|
},
|
|
[]*Row{
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1"}},
|
|
&SumData{Value: 6},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"2",
|
|
[]record{
|
|
{1, []tagString{{k1, "v1"}}},
|
|
{5, []tagString{{k2, "v2"}}},
|
|
},
|
|
[]*Row{
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1"}},
|
|
&SumData{Value: 1},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k2, Value: "v2"}},
|
|
&SumData{Value: 5},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"3",
|
|
[]record{
|
|
{1, []tagString{{k1, "v1"}}},
|
|
{5, []tagString{{k1, "v1"}, {k3, "v3"}}},
|
|
{1, []tagString{{k1, "v1 other"}}},
|
|
{5, []tagString{{k2, "v2"}}},
|
|
{5, []tagString{{k1, "v1"}, {k2, "v2"}}},
|
|
},
|
|
[]*Row{
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1"}},
|
|
&SumData{Value: 6},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1 other"}},
|
|
&SumData{Value: 1},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k2, Value: "v2"}},
|
|
&SumData{Value: 5},
|
|
},
|
|
{
|
|
[]tag.Tag{{Key: k1, Value: "v1"}, {Key: k2, Value: "v2"}},
|
|
&SumData{Value: 5},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tcs {
|
|
view.clearRows()
|
|
view.subscribe()
|
|
for _, r := range tt.records {
|
|
mods := []tag.Mutator{}
|
|
for _, t := range r.tags {
|
|
mods = append(mods, tag.Insert(t.k, t.v))
|
|
}
|
|
ctx, err := tag.New(context.Background(), mods...)
|
|
if err != nil {
|
|
t.Errorf("%v: New = %v", tt.label, err)
|
|
}
|
|
e := &exemplar.Exemplar{
|
|
Value: r.f,
|
|
}
|
|
view.addSample(tag.FromContext(ctx), e)
|
|
}
|
|
|
|
gotRows := view.collectedRows()
|
|
for i, got := range gotRows {
|
|
if !containsRow(tt.wantRows, got) {
|
|
t.Errorf("%v-%d: got row %v; want none", tt.label, i, got)
|
|
break
|
|
}
|
|
}
|
|
|
|
for i, want := range tt.wantRows {
|
|
if !containsRow(gotRows, want) {
|
|
t.Errorf("%v-%d: got none; want row %v", tt.label, i, want)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCanonicalize(t *testing.T) {
|
|
k1, _ := tag.NewKey("k1")
|
|
k2, _ := tag.NewKey("k2")
|
|
m := stats.Int64("TestCanonicalize/m1", "desc desc", stats.UnitDimensionless)
|
|
v := &View{TagKeys: []tag.Key{k2, k1}, Measure: m, Aggregation: Sum()}
|
|
err := v.canonicalize()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, want := v.Name, "TestCanonicalize/m1"; got != want {
|
|
t.Errorf("vc.Name = %q; want %q", got, want)
|
|
}
|
|
if got, want := v.Description, "desc desc"; got != want {
|
|
t.Errorf("vc.Description = %q; want %q", got, want)
|
|
}
|
|
if got, want := len(v.TagKeys), 2; got != want {
|
|
t.Errorf("len(vc.TagKeys) = %d; want %d", got, want)
|
|
}
|
|
if got, want := v.TagKeys[0].Name(), "k1"; got != want {
|
|
t.Errorf("vc.TagKeys[0].Name() = %q; want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestViewSortedKeys(t *testing.T) {
|
|
k1, _ := tag.NewKey("a")
|
|
k2, _ := tag.NewKey("b")
|
|
k3, _ := tag.NewKey("c")
|
|
ks := []tag.Key{k1, k3, k2}
|
|
|
|
m := stats.Int64("TestViewSortedKeys/m1", "", stats.UnitDimensionless)
|
|
Register(&View{
|
|
Name: "sort_keys",
|
|
Description: "desc sort_keys",
|
|
TagKeys: ks,
|
|
Measure: m,
|
|
Aggregation: Sum(),
|
|
})
|
|
// Register normalizes the view by sorting the tag keys, retrieve the normalized view
|
|
v := Find("sort_keys")
|
|
|
|
want := []string{"a", "b", "c"}
|
|
vks := v.TagKeys
|
|
if len(vks) != len(want) {
|
|
t.Errorf("Keys = %+v; want %+v", vks, want)
|
|
}
|
|
|
|
for i, v := range want {
|
|
if got, want := v, vks[i].Name(); got != want {
|
|
t.Errorf("View name = %q; want %q", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// containsRow returns true if rows contain r.
|
|
func containsRow(rows []*Row, r *Row) bool {
|
|
for _, x := range rows {
|
|
if r.Equal(x) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func TestRegisterUnregisterParity(t *testing.T) {
|
|
measures := []stats.Measure{
|
|
stats.Int64("ifoo", "iFOO", "iBar"),
|
|
stats.Float64("ffoo", "fFOO", "fBar"),
|
|
}
|
|
aggregations := []*Aggregation{
|
|
Count(),
|
|
Sum(),
|
|
Distribution(1, 2.0, 4.0, 8.0, 16.0),
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
for _, m := range measures {
|
|
for _, agg := range aggregations {
|
|
v := &View{
|
|
Aggregation: agg,
|
|
Name: "Lookup here",
|
|
Measure: m,
|
|
}
|
|
if err := Register(v); err != nil {
|
|
t.Errorf("Iteration #%d:\nMeasure: (%#v)\nAggregation (%#v)\nError: %v", i, m, agg, err)
|
|
}
|
|
Unregister(v)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRegisterAfterMeasurement(t *testing.T) {
|
|
// Tests that we can register views after measurements are created and
|
|
// they still take effect.
|
|
|
|
m := stats.Int64(t.Name(), "", stats.UnitDimensionless)
|
|
mm := m.M(1)
|
|
ctx := context.Background()
|
|
|
|
stats.Record(ctx, mm)
|
|
v := &View{
|
|
Measure: m,
|
|
Aggregation: Count(),
|
|
}
|
|
if err := Register(v); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
rows, err := RetrieveData(v.Name)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rows) > 0 {
|
|
t.Error("View should not have data")
|
|
}
|
|
|
|
stats.Record(ctx, mm)
|
|
|
|
rows, err = RetrieveData(v.Name)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rows) == 0 {
|
|
t.Error("View should have data")
|
|
}
|
|
}
|
|
|
|
func TestViewRegister_negativeBucketBounds(t *testing.T) {
|
|
m := stats.Int64("TestViewRegister_negativeBucketBounds", "", "")
|
|
v := &View{
|
|
Measure: m,
|
|
Aggregation: Distribution(-1, 2),
|
|
}
|
|
err := Register(v)
|
|
if err != ErrNegativeBucketBounds {
|
|
t.Errorf("Expected ErrNegativeBucketBounds, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestViewRegister_sortBuckets(t *testing.T) {
|
|
m := stats.Int64("TestViewRegister_sortBuckets", "", "")
|
|
v := &View{
|
|
Measure: m,
|
|
Aggregation: Distribution(2, 1),
|
|
}
|
|
err := Register(v)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected err %s", err)
|
|
}
|
|
want := []float64{1, 2}
|
|
if diff := cmp.Diff(v.Aggregation.Buckets, want); diff != "" {
|
|
t.Errorf("buckets differ -got +want: %s", diff)
|
|
}
|
|
}
|
|
|
|
func TestViewRegister_dropZeroBuckets(t *testing.T) {
|
|
m := stats.Int64("TestViewRegister_dropZeroBuckets", "", "")
|
|
v := &View{
|
|
Measure: m,
|
|
Aggregation: Distribution(2, 0, 1),
|
|
}
|
|
err := Register(v)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected err %s", err)
|
|
}
|
|
want := []float64{1, 2}
|
|
if diff := cmp.Diff(v.Aggregation.Buckets, want); diff != "" {
|
|
t.Errorf("buckets differ -got +want: %s", diff)
|
|
}
|
|
}
|