|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- // 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)
- }
- }
|