Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit e44c43b

Browse files
authored
Add a matcher for TimeSeries protos and add missing stackdriver_utils_test cases. (#26)
1 parent 9f7970e commit e44c43b

9 files changed

Lines changed: 514 additions & 48 deletions

File tree

opencensus/exporters/stats/BUILD

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ load("//opencensus:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS")
1818

1919
licenses(["notice"]) # Apache License 2.0
2020

21-
package(default_visibility = ["//visibility:private"])
21+
package(default_visibility = ["//opencensus/exporters/stats:__subpackages__"])
2222

2323
# Public exporter libraries.
2424

@@ -76,6 +76,21 @@ cc_library(
7676
],
7777
)
7878

79+
cc_library(
80+
name = "test_utils",
81+
testonly = 1,
82+
srcs = ["internal/testing/time_series_matcher.cc"],
83+
hdrs = ["internal/testing/time_series_matcher.h"],
84+
deps = [
85+
"//google/api:distribution",
86+
"//google/api:metric",
87+
"//google/monitoring/v3:common",
88+
"//google/monitoring/v3:metric",
89+
"//opencensus/stats",
90+
"@com_google_googletest//:gtest",
91+
],
92+
)
93+
7994
# Tests.
8095
# ========================================================================= #
8196

@@ -85,9 +100,11 @@ cc_test(
85100
copts = TEST_COPTS,
86101
deps = [
87102
":stackdriver_utils",
103+
":test_utils",
88104
"//google/api:distribution",
89105
"//google/api:label",
90106
"//google/api:metric",
107+
"//google/monitoring/v3:common",
91108
"//google/monitoring/v3:metric",
92109
"//opencensus/stats",
93110
"//opencensus/stats:test_utils",

opencensus/exporters/stats/internal/stackdriver_utils_test.cc

Lines changed: 184 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@
2626
#include "google/monitoring/v3/common.pb.h"
2727
#include "google/protobuf/timestamp.pb.h"
2828
#include "gtest/gtest.h"
29+
#include "opencensus/exporters/stats/internal/testing/time_series_matcher.h"
2930
#include "opencensus/stats/stats.h"
3031
#include "opencensus/stats/testing/test_utils.h"
3132

33+
using opencensus::stats::testing::TestUtils;
34+
3235
namespace opencensus {
3336
namespace exporters {
3437
namespace stats {
@@ -142,7 +145,187 @@ TEST(StackdriverUtilsTest, SetMetricDescriptorDescription) {
142145
EXPECT_EQ(description, metric_descriptor.description());
143146
}
144147

145-
// TODO: MakeTimeSeriesSumDouble
148+
TEST(StackdriverUtilsTest, MakeTimeSeriesSumDouble) {
149+
const auto measure = opencensus::stats::MeasureRegistry::RegisterDouble(
150+
"measure_sum_double", "", "");
151+
const std::string task = "test_task";
152+
const std::string view_name = "test_view";
153+
const std::string tag_key_1 = "foo";
154+
const std::string tag_key_2 = "bar";
155+
const auto view_descriptor =
156+
opencensus::stats::ViewDescriptor()
157+
.set_name(view_name)
158+
.set_measure(measure.GetDescriptor().name())
159+
.set_aggregation(opencensus::stats::Aggregation::Sum())
160+
.set_aggregation_window(
161+
opencensus::stats::AggregationWindow::Cumulative())
162+
.add_column(tag_key_1)
163+
.add_column(tag_key_2);
164+
const opencensus::stats::ViewData data = TestUtils::MakeViewData(
165+
view_descriptor, {{{"v1", "v1"}, 1.0}, {{"v1", "v2"}, 2.0}});
166+
const std::vector<google::monitoring::v3::TimeSeries> time_series =
167+
MakeTimeSeries(view_descriptor, data, task);
168+
169+
for (const auto& ts : time_series) {
170+
EXPECT_EQ("custom.googleapis.com/opencensus/test_view", ts.metric().type());
171+
EXPECT_EQ("global", ts.resource().type());
172+
ASSERT_EQ(1, ts.points_size());
173+
EXPECT_EQ(absl::ToUnixSeconds(data.start_time()),
174+
ts.points(0).interval().start_time().seconds());
175+
EXPECT_EQ(absl::ToUnixSeconds(data.end_time()),
176+
ts.points(0).interval().end_time().seconds());
177+
}
178+
179+
EXPECT_THAT(
180+
time_series,
181+
::testing::UnorderedElementsAre(
182+
testing::TimeSeriesDouble(
183+
{{"opencensus_task", task}, {tag_key_1, "v1"}, {tag_key_2, "v1"}},
184+
1.0),
185+
testing::TimeSeriesDouble(
186+
{{"opencensus_task", task}, {tag_key_1, "v1"}, {tag_key_2, "v2"}},
187+
2.0)));
188+
}
189+
190+
TEST(StackdriverUtilsTest, MakeTimeSeriesSumInt) {
191+
const auto measure = opencensus::stats::MeasureRegistry::RegisterInt(
192+
"measure_sum_int", "", "");
193+
const std::string task = "test_task";
194+
const std::string view_name = "test_descriptor";
195+
const std::string tag_key_1 = "foo";
196+
const std::string tag_key_2 = "bar";
197+
const auto view_descriptor =
198+
opencensus::stats::ViewDescriptor()
199+
.set_name(view_name)
200+
.set_measure(measure.GetDescriptor().name())
201+
.set_aggregation(opencensus::stats::Aggregation::Sum())
202+
.set_aggregation_window(
203+
opencensus::stats::AggregationWindow::Cumulative())
204+
.add_column(tag_key_1)
205+
.add_column(tag_key_2);
206+
const opencensus::stats::ViewData data = TestUtils::MakeViewData(
207+
view_descriptor, {{{"v1", "v1"}, 1.0}, {{"v1", "v2"}, 2.0}});
208+
const std::vector<google::monitoring::v3::TimeSeries> time_series =
209+
MakeTimeSeries(view_descriptor, data, task);
210+
211+
for (const auto& ts : time_series) {
212+
EXPECT_EQ(absl::StrCat("custom.googleapis.com/opencensus/", view_name),
213+
ts.metric().type());
214+
EXPECT_EQ("global", ts.resource().type());
215+
ASSERT_EQ(1, ts.points_size());
216+
EXPECT_EQ(absl::ToUnixSeconds(data.start_time()),
217+
ts.points(0).interval().start_time().seconds());
218+
EXPECT_EQ(absl::ToUnixSeconds(data.end_time()),
219+
ts.points(0).interval().end_time().seconds());
220+
}
221+
222+
EXPECT_THAT(
223+
time_series,
224+
::testing::UnorderedElementsAre(
225+
testing::TimeSeriesInt(
226+
{{"opencensus_task", task}, {tag_key_1, "v1"}, {tag_key_2, "v1"}},
227+
1),
228+
testing::TimeSeriesInt(
229+
{{"opencensus_task", task}, {tag_key_1, "v1"}, {tag_key_2, "v2"}},
230+
2)));
231+
}
232+
233+
TEST(StackdriverUtilsTest, MakeTimeSeriesCountDouble) {
234+
const auto measure = opencensus::stats::MeasureRegistry::RegisterDouble(
235+
"measure_count_double", "", "");
236+
const std::string task = "test_task";
237+
const std::string view_name = "test_descriptor";
238+
const std::string tag_key_1 = "foo";
239+
const std::string tag_key_2 = "bar";
240+
const auto view_descriptor =
241+
opencensus::stats::ViewDescriptor()
242+
.set_name(view_name)
243+
.set_measure(measure.GetDescriptor().name())
244+
.set_aggregation(opencensus::stats::Aggregation::Count())
245+
.set_aggregation_window(
246+
opencensus::stats::AggregationWindow::Cumulative())
247+
.add_column(tag_key_1)
248+
.add_column(tag_key_2);
249+
const opencensus::stats::ViewData data = TestUtils::MakeViewData(
250+
view_descriptor,
251+
{{{"v1", "v1"}, 1.0}, {{"v1", "v1"}, 3.0}, {{"v1", "v2"}, 2.0}});
252+
const std::vector<google::monitoring::v3::TimeSeries> time_series =
253+
MakeTimeSeries(view_descriptor, data, task);
254+
255+
for (const auto& ts : time_series) {
256+
EXPECT_EQ(absl::StrCat("custom.googleapis.com/opencensus/", view_name),
257+
ts.metric().type());
258+
EXPECT_EQ("global", ts.resource().type());
259+
ASSERT_EQ(1, ts.points_size());
260+
EXPECT_EQ(absl::ToUnixSeconds(data.start_time()),
261+
ts.points(0).interval().start_time().seconds());
262+
EXPECT_EQ(absl::ToUnixSeconds(data.end_time()),
263+
ts.points(0).interval().end_time().seconds());
264+
}
265+
266+
EXPECT_THAT(
267+
time_series,
268+
::testing::UnorderedElementsAre(
269+
testing::TimeSeriesInt(
270+
{{"opencensus_task", task}, {tag_key_1, "v1"}, {tag_key_2, "v1"}},
271+
2),
272+
testing::TimeSeriesInt(
273+
{{"opencensus_task", task}, {tag_key_1, "v1"}, {tag_key_2, "v2"}},
274+
1)));
275+
}
276+
277+
TEST(StackdriverUtilsTest, MakeTimeSeriesDistributionDouble) {
278+
const auto measure = opencensus::stats::MeasureRegistry::RegisterDouble(
279+
"measure_distribution_double", "", "");
280+
const std::string task = "test_task";
281+
const std::string view_name = "test_view";
282+
const std::string tag_key_1 = "foo";
283+
const std::string tag_key_2 = "bar";
284+
const auto bucket_boundaries =
285+
opencensus::stats::BucketBoundaries::Explicit({0});
286+
const auto view_descriptor =
287+
opencensus::stats::ViewDescriptor()
288+
.set_name(view_name)
289+
.set_measure(measure.GetDescriptor().name())
290+
.set_aggregation(
291+
opencensus::stats::Aggregation::Distribution(bucket_boundaries))
292+
.set_aggregation_window(
293+
opencensus::stats::AggregationWindow::Cumulative())
294+
.add_column(tag_key_1)
295+
.add_column(tag_key_2);
296+
const opencensus::stats::ViewData data = TestUtils::MakeViewData(
297+
view_descriptor,
298+
{{{"v1", "v1"}, -1.0}, {{"v1", "v1"}, 7.0}, {{"v1", "v2"}, 1.0}});
299+
const std::vector<google::monitoring::v3::TimeSeries> time_series =
300+
MakeTimeSeries(view_descriptor, data, task);
301+
302+
for (const auto& ts : time_series) {
303+
EXPECT_EQ("custom.googleapis.com/opencensus/test_view", ts.metric().type());
304+
EXPECT_EQ("global", ts.resource().type());
305+
ASSERT_EQ(1, ts.points_size());
306+
EXPECT_EQ(absl::ToUnixSeconds(data.start_time()),
307+
ts.points(0).interval().start_time().seconds());
308+
EXPECT_EQ(absl::ToUnixSeconds(data.end_time()),
309+
ts.points(0).interval().end_time().seconds());
310+
}
311+
312+
auto distribution1 = TestUtils::MakeDistribution(&bucket_boundaries);
313+
TestUtils::AddToDistribution(&distribution1, -1.0);
314+
TestUtils::AddToDistribution(&distribution1, 7.0);
315+
316+
auto distribution2 = TestUtils::MakeDistribution(&bucket_boundaries);
317+
TestUtils::AddToDistribution(&distribution2, 1.0);
318+
319+
EXPECT_THAT(
320+
time_series,
321+
::testing::UnorderedElementsAre(
322+
testing::TimeSeriesDistribution(
323+
{{"opencensus_task", task}, {tag_key_1, "v1"}, {tag_key_2, "v1"}},
324+
distribution1),
325+
testing::TimeSeriesDistribution(
326+
{{"opencensus_task", task}, {tag_key_1, "v1"}, {tag_key_2, "v2"}},
327+
distribution2)));
328+
}
146329

147330
} // namespace
148331
} // namespace stats
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Copyright 2018, OpenCensus Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "opencensus/exporters/stats/internal/testing/time_series_matcher.h"
16+
17+
#include <cstdint>
18+
#include <map>
19+
#include <string>
20+
21+
#include "gmock/gmock.h"
22+
#include "google/api/distribution.pb.h"
23+
#include "google/api/metric.pb.h"
24+
#include "google/monitoring/v3/common.pb.h"
25+
#include "google/monitoring/v3/metric.pb.h"
26+
#include "opencensus/stats/stats.h"
27+
28+
namespace opencensus {
29+
namespace exporters {
30+
namespace stats {
31+
namespace testing {
32+
33+
bool TimeSeriesMatcher::MatchAndExplain(
34+
google::monitoring::v3::TimeSeries time_series,
35+
::testing::MatchResultListener* listener) const {
36+
// Check labels.
37+
const auto& labels = time_series.metric().labels();
38+
for (const auto& label : labels) {
39+
if (tags_.find(label.first) == tags_.end()) {
40+
*listener << "has an extra label \"" << label.first << "\"";
41+
return false;
42+
}
43+
}
44+
for (const auto& tag : tags_) {
45+
const auto& label = labels.find(tag.first);
46+
if (label == labels.end()) {
47+
*listener << "is missing the label \"" << tag.first << "\"";
48+
return false;
49+
}
50+
if (absl::string_view(label->second) != tag.second) {
51+
*listener << "has the wrong value for the label \"" << tag.first
52+
<< "\": actual \"" << label->second << "\"";
53+
return false;
54+
}
55+
}
56+
57+
// Check data.
58+
if (time_series.points_size() != 1) {
59+
*listener << "has " << time_series.points_size() << " points; expected 1";
60+
return false;
61+
}
62+
const auto& point = time_series.points(0);
63+
switch (type_) {
64+
case Type::kDouble: {
65+
// Note that proto3 does not allow distinguishing between default and
66+
// unset oneof cases.
67+
if (point.value().double_value() != double_value_) {
68+
*listener << "value is " << point.value().double_value()
69+
<< "; expected " << double_value_;
70+
return false;
71+
}
72+
return true;
73+
}
74+
case Type::kInt64: {
75+
if (point.value().int64_value() != int_value_) {
76+
*listener << "value is " << point.value().int64_value() << "; expected "
77+
<< int_value_;
78+
return false;
79+
}
80+
return true;
81+
}
82+
case Type::kDistribution: {
83+
const auto& distribution = point.value().distribution_value();
84+
if (distribution.count() != distribution_value_.count()) {
85+
*listener << "count is " << distribution.count() << "; expected "
86+
<< distribution_value_.count();
87+
return false;
88+
}
89+
if (distribution.mean() != distribution_value_.mean()) {
90+
*listener << "mean is " << distribution.mean() << "; expected "
91+
<< distribution_value_.mean();
92+
return false;
93+
}
94+
if (distribution.sum_of_squared_deviation() !=
95+
distribution_value_.sum_of_squared_deviation()) {
96+
*listener << "sum_of_squared_deviation is "
97+
<< distribution.sum_of_squared_deviation() << "; expected "
98+
<< distribution_value_.sum_of_squared_deviation();
99+
return false;
100+
}
101+
const auto& buckets = distribution.bucket_options().explicit_buckets();
102+
if (buckets.bounds_size() !=
103+
distribution_value_.bucket_boundaries().lower_boundaries().size()) {
104+
*listener << "has " << buckets.bounds_size() << " buckets; expected "
105+
<< distribution_value_.bucket_boundaries()
106+
.lower_boundaries()
107+
.size();
108+
return false;
109+
}
110+
for (int i = 0; i < buckets.bounds_size(); ++i) {
111+
if (buckets.bounds(i) !=
112+
distribution_value_.bucket_boundaries().lower_boundaries()[i]) {
113+
*listener << "has the wrong boundaries";
114+
return false;
115+
}
116+
if (distribution.bucket_counts(i) !=
117+
distribution_value_.bucket_counts()[i]) {
118+
*listener << "has " << distribution.bucket_counts(i)
119+
<< "values in the " << i << "th bucket; expected "
120+
<< distribution_value_.bucket_counts()[i];
121+
return false;
122+
}
123+
}
124+
return true;
125+
}
126+
}
127+
}
128+
129+
void TimeSeriesMatcher::DescribeTo(::std::ostream* os) const {
130+
switch (type_) {
131+
case Type::kDouble: {
132+
*os << double_value_;
133+
break;
134+
}
135+
case Type::kInt64: {
136+
*os << int_value_;
137+
break;
138+
}
139+
case Type::kDistribution: {
140+
*os << distribution_value_.DebugString();
141+
break;
142+
}
143+
}
144+
}
145+
146+
} // namespace testing
147+
} // namespace stats
148+
} // namespace exporters
149+
} // namespace opencensus

0 commit comments

Comments
 (0)