| // 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 stackdriver |
| |
| import ( |
| "context" |
| "fmt" |
| "testing" |
| "time" |
| |
| "contrib.go.opencensus.io/exporter/stackdriver/monitoredresource" |
| |
| "cloud.google.com/go/monitoring/apiv3" |
| "github.com/golang/protobuf/ptypes/timestamp" |
| "github.com/google/go-cmp/cmp" |
| "go.opencensus.io/stats" |
| "go.opencensus.io/stats/view" |
| "go.opencensus.io/tag" |
| "google.golang.org/api/option" |
| "google.golang.org/genproto/googleapis/api/distribution" |
| "google.golang.org/genproto/googleapis/api/label" |
| "google.golang.org/genproto/googleapis/api/metric" |
| metricpb "google.golang.org/genproto/googleapis/api/metric" |
| monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" |
| monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" |
| "google.golang.org/grpc" |
| ) |
| |
| var authOptions = []option.ClientOption{option.WithGRPCConn(&grpc.ClientConn{})} |
| |
| var testOptions = Options{ProjectID: "opencensus-test", MonitoringClientOptions: authOptions} |
| |
| func TestRejectBlankProjectID(t *testing.T) { |
| ids := []string{"", " ", " "} |
| for _, projectID := range ids { |
| opts := Options{ProjectID: projectID, MonitoringClientOptions: authOptions} |
| exp, err := newStatsExporter(opts) |
| if err == nil || exp != nil { |
| t.Errorf("%q ProjectID must be rejected: NewExporter() = %v err = %q", projectID, exp, err) |
| } |
| } |
| } |
| |
| func TestExporter_makeReq(t *testing.T) { |
| m := stats.Float64("test-measure", "measure desc", "unit") |
| |
| key, err := tag.NewKey("test_key") |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| v := &view.View{ |
| Name: "example.com/views/testview", |
| Description: "desc", |
| TagKeys: []tag.Key{key}, |
| Measure: m, |
| Aggregation: view.Count(), |
| } |
| |
| lastValueView := &view.View{ |
| Name: "lasttestview", |
| Description: "desc", |
| TagKeys: []tag.Key{key}, |
| Measure: m, |
| Aggregation: view.LastValue(), |
| } |
| |
| distView := &view.View{ |
| Name: "distview", |
| Description: "desc", |
| Measure: m, |
| Aggregation: view.Distribution(2, 4, 7), |
| } |
| |
| start := time.Now() |
| end := start.Add(time.Minute) |
| count1 := &view.CountData{Value: 10} |
| count2 := &view.CountData{Value: 16} |
| sum1 := &view.SumData{Value: 5.5} |
| sum2 := &view.SumData{Value: -11.1} |
| last1 := view.LastValueData{Value: 100} |
| last2 := view.LastValueData{Value: 200} |
| taskValue := getTaskValue() |
| |
| tests := []struct { |
| name string |
| projID string |
| vd *view.Data |
| want []*monitoringpb.CreateTimeSeriesRequest |
| opts Options |
| }{ |
| { |
| name: "count agg + timeline", |
| projID: "proj-id", |
| vd: newTestViewData(v, start, end, count1, count2), |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/example.com/views/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 10, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/example.com/views/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 16, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "metric type formatter", |
| projID: "proj-id", |
| vd: newTestViewData(v, start, end, sum1, sum2), |
| opts: Options{ |
| GetMetricType: func(v *view.View) string { |
| return fmt.Sprintf("external.googleapis.com/%s", v.Name) |
| }, |
| }, |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "external.googleapis.com/example.com/views/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ |
| DoubleValue: 5.5, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "external.googleapis.com/example.com/views/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ |
| DoubleValue: -11.1, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "sum agg + timeline", |
| projID: "proj-id", |
| vd: newTestViewData(v, start, end, sum1, sum2), |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/example.com/views/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ |
| DoubleValue: 5.5, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/example.com/views/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ |
| DoubleValue: -11.1, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "last value agg", |
| projID: "proj-id", |
| vd: newTestViewData(lastValueView, start, end, &last1, &last2), |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/lasttestview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ |
| DoubleValue: 100, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/lasttestview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{ |
| DoubleValue: 200, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "dist agg + time window - without zero bucket", |
| projID: "proj-id", |
| vd: newTestDistViewData(distView, start, end), |
| want: []*monitoringpb.CreateTimeSeriesRequest{{ |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/distview", |
| Labels: map[string]string{ |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DistributionValue{ |
| DistributionValue: &distribution.Distribution{ |
| Count: 5, |
| Mean: 3.0, |
| SumOfSquaredDeviation: 1.5, |
| BucketOptions: &distribution.Distribution_BucketOptions{ |
| Options: &distribution.Distribution_BucketOptions_ExplicitBuckets{ |
| ExplicitBuckets: &distribution.Distribution_BucketOptions_Explicit{ |
| Bounds: []float64{0.0, 2.0, 4.0, 7.0}}}}, |
| BucketCounts: []int64{0, 2, 2, 1}}, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }}, |
| }, |
| { |
| name: "dist agg + time window + zero bucket", |
| projID: "proj-id", |
| vd: newTestDistViewData(distView, start, end), |
| want: []*monitoringpb.CreateTimeSeriesRequest{{ |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/distview", |
| Labels: map[string]string{ |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: &monitoredrespb.MonitoredResource{ |
| Type: "global", |
| }, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DistributionValue{ |
| DistributionValue: &distribution.Distribution{ |
| Count: 5, |
| Mean: 3.0, |
| SumOfSquaredDeviation: 1.5, |
| BucketOptions: &distribution.Distribution_BucketOptions{ |
| Options: &distribution.Distribution_BucketOptions_ExplicitBuckets{ |
| ExplicitBuckets: &distribution.Distribution_BucketOptions_Explicit{ |
| Bounds: []float64{0.0, 2.0, 4.0, 7.0}}}}, |
| BucketCounts: []int64{0, 2, 2, 1}}, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }}, |
| }, |
| } |
| |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| opts := tt.opts |
| opts.ProjectID = tt.projID |
| opts.MonitoringClientOptions = authOptions |
| e, err := newStatsExporter(opts) |
| if err != nil { |
| t.Fatal(err) |
| } |
| resps := e.makeReq([]*view.Data{tt.vd}, maxTimeSeriesPerUpload) |
| if got, want := len(resps), len(tt.want); got != want { |
| t.Fatalf("%v: Exporter.makeReq() returned %d responses; want %d", tt.name, got, want) |
| } |
| if len(tt.want) == 0 { |
| return |
| } |
| if diff := cmp.Diff(resps, tt.want); diff != "" { |
| t.Errorf("Values differ -got +want: %s", diff) |
| } |
| }) |
| } |
| } |
| |
| func TestExporter_makeReq_batching(t *testing.T) { |
| m := stats.Float64("test-measure/makeReq_batching", "measure desc", "unit") |
| |
| key, err := tag.NewKey("test_key") |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| v := &view.View{ |
| Name: "view", |
| Description: "desc", |
| TagKeys: []tag.Key{key}, |
| Measure: m, |
| Aggregation: view.Count(), |
| } |
| |
| tests := []struct { |
| name string |
| iter int |
| limit int |
| wantReqs int |
| wantTotal int |
| }{ |
| { |
| name: "4 vds; 3 limit", |
| iter: 2, |
| limit: 3, |
| wantReqs: 4, |
| wantTotal: 4, |
| }, |
| { |
| name: "4 vds; 4 limit", |
| iter: 2, |
| limit: 4, |
| wantReqs: 4, |
| wantTotal: 4, |
| }, |
| { |
| name: "4 vds; 5 limit", |
| iter: 2, |
| limit: 5, |
| wantReqs: 4, |
| wantTotal: 4, |
| }, |
| } |
| |
| count1 := &view.CountData{Value: 10} |
| count2 := &view.CountData{Value: 16} |
| |
| for _, tt := range tests { |
| var vds []*view.Data |
| for i := 0; i < tt.iter; i++ { |
| vds = append(vds, newTestViewData(v, time.Now(), time.Now(), count1, count2)) |
| } |
| |
| e, err := newStatsExporter(testOptions) |
| if err != nil { |
| t.Fatal(err) |
| } |
| resps := e.makeReq(vds, tt.limit) |
| if len(resps) != tt.wantReqs { |
| t.Errorf("%v:\ngot %d:: %v;\n\nwant %d requests\n\n", tt.name, len(resps), resps, tt.wantReqs) |
| } |
| |
| var total int |
| for _, resp := range resps { |
| total += len(resp.TimeSeries) |
| } |
| if got, want := total, tt.wantTotal; got != want { |
| t.Errorf("%v: len(resps[...].TimeSeries) = %d; want %d", tt.name, got, want) |
| } |
| } |
| } |
| |
| func TestEqualAggWindowTagKeys(t *testing.T) { |
| key1, _ := tag.NewKey("test-key-one") |
| key2, _ := tag.NewKey("test-key-two") |
| tests := []struct { |
| name string |
| md *metricpb.MetricDescriptor |
| m stats.Measure |
| agg *view.Aggregation |
| keys []tag.Key |
| wantErr bool |
| }{ |
| { |
| name: "count agg with in64 measure", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_INT64, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Int64("name", "", ""), |
| agg: view.Count(), |
| wantErr: false, |
| }, |
| { |
| name: "count agg with double measure", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_INT64, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Float64("name", "", ""), |
| agg: view.Count(), |
| wantErr: false, |
| }, |
| { |
| name: "sum agg double", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_DOUBLE, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Float64("name", "", ""), |
| agg: view.Sum(), |
| wantErr: false, |
| }, |
| { |
| name: "sum agg int64", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_INT64, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Int64("name", "", ""), |
| agg: view.Sum(), |
| wantErr: false, |
| }, |
| { |
| name: "last value agg double", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_DOUBLE, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Float64("name", "", ""), |
| agg: view.LastValue(), |
| wantErr: false, |
| }, |
| { |
| name: "last value agg int64", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_INT64, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Int64("name", "", ""), |
| agg: view.LastValue(), |
| wantErr: false, |
| }, |
| { |
| name: "distribution - mismatch", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_DISTRIBUTION, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Int64("name", "", ""), |
| agg: view.Count(), |
| wantErr: true, |
| }, |
| { |
| name: "last value - measure mismatch", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_INT64, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Float64("name", "", ""), |
| agg: view.LastValue(), |
| wantErr: true, |
| }, |
| { |
| name: "distribution agg with keys", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_DISTRIBUTION, |
| Labels: []*label.LabelDescriptor{ |
| {Key: "test_key_one"}, |
| {Key: "test_key_two"}, |
| {Key: opencensusTaskKey}, |
| }, |
| }, |
| m: stats.Int64("name", "", ""), |
| agg: view.Distribution(), |
| keys: []tag.Key{key1, key2}, |
| wantErr: false, |
| }, |
| { |
| name: "distribution agg with keys -- mismatch", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_DISTRIBUTION, |
| }, |
| m: stats.Int64("name", "", ""), |
| agg: view.Distribution(), |
| keys: []tag.Key{key1, key2}, |
| wantErr: true, |
| }, |
| { |
| name: "count agg with pointers", |
| md: &metricpb.MetricDescriptor{ |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_INT64, |
| Labels: []*label.LabelDescriptor{{Key: opencensusTaskKey}}, |
| }, |
| m: stats.Int64("name", "", ""), |
| agg: view.Count(), |
| wantErr: false, |
| }, |
| } |
| e, err := newStatsExporter(testOptions) |
| if err != nil { |
| t.Fatal(err) |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| err := e.equalMeasureAggTagKeys(tt.md, tt.m, tt.agg, tt.keys) |
| if err != nil && !tt.wantErr { |
| t.Errorf("equalAggTagKeys() = %q; want no error", err) |
| } |
| if err == nil && tt.wantErr { |
| t.Errorf("equalAggTagKeys() = %q; want error", err) |
| } |
| |
| }) |
| } |
| } |
| |
| func TestExporter_createMeasure(t *testing.T) { |
| oldCreateMetricDescriptor := createMetricDescriptor |
| |
| defer func() { |
| createMetricDescriptor = oldCreateMetricDescriptor |
| }() |
| |
| key, _ := tag.NewKey("test-key-one") |
| m := stats.Float64("test-measure/TestExporter_createMeasure", "measure desc", stats.UnitMilliseconds) |
| |
| v := &view.View{ |
| Name: "test_view_sum", |
| Description: "view_description", |
| TagKeys: []tag.Key{key}, |
| Measure: m, |
| Aggregation: view.Sum(), |
| } |
| |
| data := &view.CountData{Value: 0} |
| vd := newTestViewData(v, time.Now(), time.Now(), data, data) |
| |
| var customLabels Labels |
| customLabels.Set("pid", "1234", "Local process identifier") |
| customLabels.Set("hostname", "test.example.com", "Local hostname") |
| customLabels.Set("a/b/c/host-name", "test.example.com", "Local hostname") |
| |
| tests := []struct { |
| name string |
| opts Options |
| }{ |
| { |
| name: "default", |
| }, |
| { |
| name: "no default labels", |
| opts: Options{DefaultMonitoringLabels: &Labels{}}, |
| }, |
| { |
| name: "custom default labels", |
| opts: Options{DefaultMonitoringLabels: &customLabels}, |
| }, |
| } |
| |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| opts := tt.opts |
| opts.MonitoringClientOptions = authOptions |
| opts.ProjectID = "test_project" |
| e, err := newStatsExporter(opts) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| var createCalls int |
| createMetricDescriptor = func(ctx context.Context, c *monitoring.MetricClient, mdr *monitoringpb.CreateMetricDescriptorRequest) (*metric.MetricDescriptor, error) { |
| createCalls++ |
| if got, want := mdr.MetricDescriptor.Name, "projects/test_project/metricDescriptors/custom.googleapis.com/opencensus/test_view_sum"; got != want { |
| t.Errorf("MetricDescriptor.Name = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.Type, "custom.googleapis.com/opencensus/test_view_sum"; got != want { |
| t.Errorf("MetricDescriptor.Type = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.ValueType, metricpb.MetricDescriptor_DOUBLE; got != want { |
| t.Errorf("MetricDescriptor.ValueType = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.MetricKind, metricpb.MetricDescriptor_CUMULATIVE; got != want { |
| t.Errorf("MetricDescriptor.MetricKind = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.Description, "view_description"; got != want { |
| t.Errorf("MetricDescriptor.Description = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.DisplayName, "OpenCensus/test_view_sum"; got != want { |
| t.Errorf("MetricDescriptor.DisplayName = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.Unit, stats.UnitMilliseconds; got != want { |
| t.Errorf("MetricDescriptor.Unit = %q; want %q", got, want) |
| } |
| return &metric.MetricDescriptor{ |
| DisplayName: "OpenCensus/test_view_sum", |
| Description: "view_description", |
| Unit: stats.UnitMilliseconds, |
| Type: "custom.googleapis.com/opencensus/test_view_sum", |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_DOUBLE, |
| Labels: newLabelDescriptors(e.defaultLabels, vd.View.TagKeys), |
| }, nil |
| } |
| |
| ctx := context.Background() |
| if err := e.createMeasure(ctx, vd.View); err != nil { |
| t.Errorf("Exporter.createMeasure() error = %v", err) |
| } |
| if err := e.createMeasure(ctx, vd.View); err != nil { |
| t.Errorf("Exporter.createMeasure() error = %v", err) |
| } |
| if count := createCalls; count != 1 { |
| t.Errorf("createMetricDescriptor needs to be called for once; called %v times", count) |
| } |
| if count := len(e.createdViews); count != 1 { |
| t.Errorf("len(e.createdViews) = %v; want 1", count) |
| } |
| }) |
| } |
| } |
| |
| func TestExporter_createMeasure_CountAggregation(t *testing.T) { |
| oldCreateMetricDescriptor := createMetricDescriptor |
| |
| defer func() { |
| createMetricDescriptor = oldCreateMetricDescriptor |
| }() |
| |
| key, _ := tag.NewKey("test-key-one") |
| m := stats.Float64("test-measure/TestExporter_createMeasure", "measure desc", stats.UnitMilliseconds) |
| |
| v := &view.View{ |
| Name: "test_view_count", |
| Description: "view_description", |
| TagKeys: []tag.Key{key}, |
| Measure: m, |
| Aggregation: view.Count(), |
| } |
| |
| data := &view.CountData{Value: 0} |
| vd := newTestViewData(v, time.Now(), time.Now(), data, data) |
| |
| e := &statsExporter{ |
| createdViews: make(map[string]*metricpb.MetricDescriptor), |
| o: Options{ProjectID: "test_project"}, |
| } |
| |
| createMetricDescriptor = func(ctx context.Context, c *monitoring.MetricClient, mdr *monitoringpb.CreateMetricDescriptorRequest) (*metric.MetricDescriptor, error) { |
| if got, want := mdr.MetricDescriptor.Name, "projects/test_project/metricDescriptors/custom.googleapis.com/opencensus/test_view_count"; got != want { |
| t.Errorf("MetricDescriptor.Name = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.Type, "custom.googleapis.com/opencensus/test_view_count"; got != want { |
| t.Errorf("MetricDescriptor.Type = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.ValueType, metricpb.MetricDescriptor_INT64; got != want { |
| t.Errorf("MetricDescriptor.ValueType = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.MetricKind, metricpb.MetricDescriptor_CUMULATIVE; got != want { |
| t.Errorf("MetricDescriptor.MetricKind = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.Description, "view_description"; got != want { |
| t.Errorf("MetricDescriptor.Description = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.DisplayName, "OpenCensus/test_view_count"; got != want { |
| t.Errorf("MetricDescriptor.DisplayName = %q; want %q", got, want) |
| } |
| if got, want := mdr.MetricDescriptor.Unit, stats.UnitDimensionless; got != want { |
| t.Errorf("MetricDescriptor.Unit = %q; want %q", got, want) |
| } |
| return &metric.MetricDescriptor{ |
| DisplayName: "OpenCensus/test_view_sum", |
| Description: "view_description", |
| Unit: stats.UnitDimensionless, |
| Type: "custom.googleapis.com/opencensus/test_view_count", |
| MetricKind: metricpb.MetricDescriptor_CUMULATIVE, |
| ValueType: metricpb.MetricDescriptor_INT64, |
| Labels: newLabelDescriptors(nil, vd.View.TagKeys), |
| }, nil |
| } |
| ctx := context.Background() |
| if err := e.createMeasure(ctx, vd.View); err != nil { |
| t.Errorf("Exporter.createMeasure() error = %v", err) |
| } |
| } |
| |
| func TestExporter_makeReq_withCustomMonitoredResource(t *testing.T) { |
| m := stats.Float64("test-measure/TestExporter_makeReq_withCustomMonitoredResource", "measure desc", "unit") |
| |
| key, err := tag.NewKey("test_key") |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| v := &view.View{ |
| Name: "testview", |
| Description: "desc", |
| TagKeys: []tag.Key{key}, |
| Measure: m, |
| Aggregation: view.Count(), |
| } |
| if err := view.Register(v); err != nil { |
| t.Fatal(err) |
| } |
| defer view.Unregister(v) |
| |
| start := time.Now() |
| end := start.Add(time.Minute) |
| count1 := &view.CountData{Value: 10} |
| count2 := &view.CountData{Value: 16} |
| taskValue := getTaskValue() |
| |
| resource := &monitoredrespb.MonitoredResource{ |
| Type: "gce_instance", |
| Labels: map[string]string{ |
| "project_id": "proj-id", |
| "instance_id": "instance", |
| "zone": "us-west-1a", |
| }, |
| } |
| |
| gceInst := &monitoredresource.GCEInstance{ |
| ProjectID: "proj-id", |
| InstanceID: "instance", |
| Zone: "us-west-1a", |
| } |
| |
| tests := []struct { |
| name string |
| opts Options |
| vd *view.Data |
| want []*monitoringpb.CreateTimeSeriesRequest |
| }{ |
| { |
| name: "count agg timeline", |
| opts: Options{Resource: resource}, |
| vd: newTestViewData(v, start, end, count1, count2), |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 10, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 16, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "with MonitoredResource and labels", |
| opts: func() Options { |
| var labels Labels |
| labels.Set("pid", "1234", "Process identifier") |
| return Options{ |
| MonitoredResource: gceInst, |
| DefaultMonitoringLabels: &labels, |
| } |
| }(), |
| vd: newTestViewData(v, start, end, count1, count2), |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| "pid": "1234", |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 10, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| "pid": "1234", |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 16, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "GetMonitoredResource and labels", |
| opts: func() Options { |
| var labels Labels |
| labels.Set("pid", "1234", "Process identifier") |
| return Options{ |
| GetMonitoredResource: func(v *view.View, t []tag.Tag) ([]tag.Tag, monitoredresource.Interface) { |
| return t, gceInst |
| }, |
| DefaultMonitoringLabels: &labels, |
| } |
| }(), |
| vd: newTestViewData(v, start, end, count1, count2), |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| "pid": "1234", |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 10, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| "pid": "1234", |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 16, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "custom default monitoring labels", |
| opts: func() Options { |
| var labels Labels |
| labels.Set("pid", "1234", "Process identifier") |
| return Options{ |
| Resource: resource, |
| DefaultMonitoringLabels: &labels, |
| } |
| }(), |
| vd: newTestViewData(v, start, end, count1, count2), |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| "pid": "1234", |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 10, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| "pid": "1234", |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 16, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "count agg timeline", |
| opts: Options{Resource: resource}, |
| vd: newTestViewData(v, start, end, count1, count2), |
| want: []*monitoringpb.CreateTimeSeriesRequest{ |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-1", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 10, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: monitoring.MetricProjectPath("proj-id"), |
| TimeSeries: []*monitoringpb.TimeSeries{ |
| { |
| Metric: &metricpb.Metric{ |
| Type: "custom.googleapis.com/opencensus/testview", |
| Labels: map[string]string{ |
| "test_key": "test-value-2", |
| opencensusTaskKey: taskValue, |
| }, |
| }, |
| Resource: resource, |
| Points: []*monitoringpb.Point{ |
| { |
| Interval: &monitoringpb.TimeInterval{ |
| StartTime: ×tamp.Timestamp{ |
| Seconds: start.Unix(), |
| Nanos: int32(start.Nanosecond()), |
| }, |
| EndTime: ×tamp.Timestamp{ |
| Seconds: end.Unix(), |
| Nanos: int32(end.Nanosecond()), |
| }, |
| }, |
| Value: &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{ |
| Int64Value: 16, |
| }}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| opts := tt.opts |
| opts.MonitoringClientOptions = authOptions |
| opts.ProjectID = "proj-id" |
| e, err := NewExporter(opts) |
| if err != nil { |
| t.Fatal(err) |
| } |
| resps := e.statsExporter.makeReq([]*view.Data{tt.vd}, maxTimeSeriesPerUpload) |
| if got, want := len(resps), len(tt.want); got != want { |
| t.Fatalf("%v: Exporter.makeReq() returned %d responses; want %d", tt.name, got, want) |
| } |
| if len(tt.want) == 0 { |
| return |
| } |
| if diff := cmp.Diff(resps, tt.want); diff != "" { |
| t.Errorf("Requests differ, -got +want: %s", diff) |
| } |
| }) |
| } |
| } |
| |
| func TestExporter_customContext(t *testing.T) { |
| oldCreateMetricDescriptor := createMetricDescriptor |
| oldCreateTimeSeries := createTimeSeries |
| |
| defer func() { |
| createMetricDescriptor = oldCreateMetricDescriptor |
| createTimeSeries = oldCreateTimeSeries |
| }() |
| |
| var timedOut = 0 |
| createMetricDescriptor = func(ctx context.Context, c *monitoring.MetricClient, mdr *monitoringpb.CreateMetricDescriptorRequest) (*metric.MetricDescriptor, error) { |
| select { |
| case <-time.After(1 * time.Second): |
| fmt.Println("createMetricDescriptor did not time out") |
| case <-ctx.Done(): |
| timedOut++ |
| } |
| return &metric.MetricDescriptor{}, nil |
| } |
| createTimeSeries = func(ctx context.Context, c *monitoring.MetricClient, ts *monitoringpb.CreateTimeSeriesRequest) error { |
| select { |
| case <-time.After(1 * time.Second): |
| fmt.Println("createTimeSeries did not time out") |
| case <-ctx.Done(): |
| timedOut++ |
| } |
| return nil |
| } |
| |
| v := &view.View{ |
| Name: "test_view_count", |
| Description: "view_description", |
| Measure: stats.Float64("test-measure/TestExporter_createMeasure", "measure desc", stats.UnitMilliseconds), |
| Aggregation: view.Count(), |
| } |
| |
| data := &view.CountData{Value: 0} |
| vd := newTestViewData(v, time.Now(), time.Now(), data, data) |
| |
| ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) |
| defer cancel() |
| e := &statsExporter{ |
| createdViews: make(map[string]*metricpb.MetricDescriptor), |
| o: Options{ProjectID: "test_project", Context: ctx}, |
| } |
| if err := e.uploadStats([]*view.Data{vd}); err != nil { |
| t.Errorf("Exporter.uploadStats() error = %v", err) |
| } |
| if ctx.Err() != context.DeadlineExceeded { |
| t.Errorf("expected context to time out; got %v", ctx.Err()) |
| } |
| if timedOut != 3 { |
| t.Errorf("expected two functions to time out; got %d", timedOut) |
| } |
| } |
| |
| func newTestViewData(v *view.View, start, end time.Time, data1, data2 view.AggregationData) *view.Data { |
| key, _ := tag.NewKey("test-key") |
| tag1 := tag.Tag{Key: key, Value: "test-value-1"} |
| tag2 := tag.Tag{Key: key, Value: "test-value-2"} |
| return &view.Data{ |
| View: v, |
| Rows: []*view.Row{ |
| { |
| Tags: []tag.Tag{tag1}, |
| Data: data1, |
| }, |
| { |
| Tags: []tag.Tag{tag2}, |
| Data: data2, |
| }, |
| }, |
| Start: start, |
| End: end, |
| } |
| } |
| |
| func newTestDistViewData(v *view.View, start, end time.Time) *view.Data { |
| return &view.Data{ |
| View: v, |
| Rows: []*view.Row{ |
| {Data: &view.DistributionData{ |
| Count: 5, |
| Min: 1, |
| Max: 7, |
| Mean: 3, |
| SumOfSquaredDev: 1.5, |
| CountPerBucket: []int64{2, 2, 1}, |
| }}, |
| }, |
| Start: start, |
| End: end, |
| } |
| } |
| |
| func newTestDistViewDataWithZeroBucket(v *view.View, start, end time.Time) *view.Data { |
| return &view.Data{ |
| View: v, |
| Rows: []*view.Row{ |
| {Data: &view.DistributionData{ |
| Count: 5, |
| Min: 1, |
| Max: 7, |
| Mean: 3, |
| SumOfSquaredDev: 1.5, |
| CountPerBucket: []int64{0, 2, 2, 1}, |
| }}, |
| }, |
| Start: start, |
| End: end, |
| } |
| } |