1 // Copyright (C) 2017 The Android Open Source Project
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 <gtest/gtest.h>
16
17 #include <vector>
18
19 #include "src/StatsLogProcessor.h"
20 #include "src/stats_log_util.h"
21 #include "stats_event.h"
22 #include "tests/statsd_test_util.h"
23
24 namespace android {
25 namespace os {
26 namespace statsd {
27
28 #ifdef __ANDROID__
29
30 namespace {
31
CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type)32 StatsdConfig CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type) {
33 StatsdConfig config;
34 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
35 *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
36 *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
37
38 auto atomMatcher = CreateSimpleAtomMatcher("", util::APP_START_OCCURRED);
39 *config.add_atom_matcher() = atomMatcher;
40
41 auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
42 *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
43 CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
44 *config.add_predicate() = isInBackgroundPredicate;
45
46 auto gaugeMetric = config.add_gauge_metric();
47 gaugeMetric->set_id(123456);
48 gaugeMetric->set_what(atomMatcher.id());
49 gaugeMetric->set_condition(isInBackgroundPredicate.id());
50 gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false);
51 gaugeMetric->set_sampling_type(sampling_type);
52 auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
53 fieldMatcher->set_field(util::APP_START_OCCURRED);
54 fieldMatcher->add_child()->set_field(3); // type (enum)
55 fieldMatcher->add_child()->set_field(4); // activity_name(str)
56 fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64)
57 *gaugeMetric->mutable_dimensions_in_what() =
58 CreateDimensions(util::APP_START_OCCURRED, {1 /* uid field */ });
59 gaugeMetric->set_bucket(FIVE_MINUTES);
60
61 auto links = gaugeMetric->add_links();
62 links->set_condition(isInBackgroundPredicate.id());
63 auto dimensionWhat = links->mutable_fields_in_what();
64 dimensionWhat->set_field(util::APP_START_OCCURRED);
65 dimensionWhat->add_child()->set_field(1); // uid field.
66 auto dimensionCondition = links->mutable_fields_in_condition();
67 dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
68 dimensionCondition->add_child()->set_field(1); // uid field.
69 return config;
70 }
71
CreateStatsdConfigForRepeatedFieldsPushedEvent(const GaugeMetric::SamplingType sampling_type)72 StatsdConfig CreateStatsdConfigForRepeatedFieldsPushedEvent(
73 const GaugeMetric::SamplingType sampling_type) {
74 StatsdConfig config;
75 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
76
77 AtomMatcher testAtomReportedAtomMatcher =
78 CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
79 *config.add_atom_matcher() = testAtomReportedAtomMatcher;
80
81 GaugeMetric* gaugeMetric = config.add_gauge_metric();
82 gaugeMetric->set_id(123456);
83 gaugeMetric->set_what(testAtomReportedAtomMatcher.id());
84 gaugeMetric->set_sampling_type(sampling_type);
85 FieldMatcher* fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
86 fieldMatcher->set_field(util::TEST_ATOM_REPORTED);
87
88 FieldMatcher* childFieldMatcher = fieldMatcher->add_child();
89 childFieldMatcher->set_field(9); // repeated_int_field
90 childFieldMatcher->set_position(Position::FIRST);
91
92 childFieldMatcher = fieldMatcher->add_child();
93 childFieldMatcher->set_field(10); // repeated_long_field
94 childFieldMatcher->set_position(Position::LAST);
95
96 childFieldMatcher = fieldMatcher->add_child();
97 childFieldMatcher->set_field(11); // repeated_float_field
98 childFieldMatcher->set_position(Position::ALL);
99
100 childFieldMatcher = fieldMatcher->add_child();
101 childFieldMatcher->set_field(12); // repeated_string_field
102 childFieldMatcher->set_position(Position::FIRST);
103
104 childFieldMatcher = fieldMatcher->add_child();
105 childFieldMatcher->set_field(13); // repeated_boolean_field
106 childFieldMatcher->set_position(Position::LAST);
107
108 childFieldMatcher = fieldMatcher->add_child();
109 childFieldMatcher->set_field(14); // repeated_enum_field
110 childFieldMatcher->set_position(Position::ALL);
111
112 gaugeMetric->set_bucket(FIVE_MINUTES);
113 return config;
114 }
115
116 } // namespace
117
118 // Setup for test fixture.
119 class GaugeMetricE2ePushedTest : public ::testing::Test {
SetUp()120 void SetUp() override {
121 FlagProvider::getInstance().overrideFuncs(&isAtLeastSFuncTrue);
122 }
123
TearDown()124 void TearDown() override {
125 FlagProvider::getInstance().resetOverrides();
126 }
127 };
128
TEST_F(GaugeMetricE2ePushedTest,TestMultipleFieldsForPushedEvent)129 TEST_F(GaugeMetricE2ePushedTest, TestMultipleFieldsForPushedEvent) {
130 for (const auto& sampling_type :
131 {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
132 auto config = CreateStatsdConfigForPushedEvent(sampling_type);
133 int64_t bucketStartTimeNs = 10000000000;
134 int64_t bucketSizeNs =
135 TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
136
137 ConfigKey cfgKey;
138 auto processor =
139 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
140 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
141 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
142
143 int appUid1 = 123;
144 int appUid2 = 456;
145 std::vector<std::unique_ptr<LogEvent>> events;
146 events.push_back(CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid1));
147 events.push_back(
148 CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid1));
149 events.push_back(
150 CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid1));
151 events.push_back(
152 CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, appUid1));
153
154 events.push_back(CreateAppStartOccurredEvent(
155 bucketStartTimeNs + 10, appUid1, "app1", AppStartOccurred::WARM, "activity_name1",
156 "calling_pkg_name1", true /*is_instant_app*/, 101 /*activity_start_msec*/));
157 events.push_back(CreateAppStartOccurredEvent(
158 bucketStartTimeNs + 20, appUid1, "app1", AppStartOccurred::HOT, "activity_name2",
159 "calling_pkg_name2", true /*is_instant_app*/, 102 /*activity_start_msec*/));
160 events.push_back(CreateAppStartOccurredEvent(
161 bucketStartTimeNs + 30, appUid1, "app1", AppStartOccurred::COLD, "activity_name3",
162 "calling_pkg_name3", true /*is_instant_app*/, 103 /*activity_start_msec*/));
163 events.push_back(CreateAppStartOccurredEvent(
164 bucketStartTimeNs + bucketSizeNs + 30, appUid1, "app1", AppStartOccurred::WARM,
165 "activity_name4", "calling_pkg_name4", true /*is_instant_app*/,
166 104 /*activity_start_msec*/));
167 events.push_back(CreateAppStartOccurredEvent(
168 bucketStartTimeNs + 2 * bucketSizeNs, appUid1, "app1", AppStartOccurred::COLD,
169 "activity_name5", "calling_pkg_name5", true /*is_instant_app*/,
170 105 /*activity_start_msec*/));
171 events.push_back(CreateAppStartOccurredEvent(
172 bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid1, "app1", AppStartOccurred::HOT,
173 "activity_name6", "calling_pkg_name6", false /*is_instant_app*/,
174 106 /*activity_start_msec*/));
175
176 events.push_back(
177 CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 10, appUid2));
178 events.push_back(CreateAppStartOccurredEvent(
179 bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid2, "app2", AppStartOccurred::COLD,
180 "activity_name7", "calling_pkg_name7", true /*is_instant_app*/,
181 201 /*activity_start_msec*/));
182
183 sortLogEventsByTimestamp(&events);
184
185 for (const auto& event : events) {
186 processor->OnLogEvent(event.get());
187 }
188 ConfigMetricsReportList reports;
189 vector<uint8_t> buffer;
190 processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
191 FAST, &buffer);
192 EXPECT_TRUE(buffer.size() > 0);
193 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
194 backfillDimensionPath(&reports);
195 backfillStringInReport(&reports);
196 backfillStartEndTimestamp(&reports);
197 backfillAggregatedAtoms(&reports);
198 ASSERT_EQ(1, reports.reports_size());
199 ASSERT_EQ(1, reports.reports(0).metrics_size());
200 StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
201 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
202 &gaugeMetrics);
203 ASSERT_EQ(2, gaugeMetrics.data_size());
204
205 auto data = gaugeMetrics.data(0);
206 EXPECT_EQ(util::APP_START_OCCURRED, data.dimensions_in_what().field());
207 ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
208 EXPECT_EQ(1 /* uid field */,
209 data.dimensions_in_what().value_tuple().dimensions_value(0).field());
210 EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
211 ASSERT_EQ(3, data.bucket_info_size());
212 if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
213 ASSERT_EQ(2, data.bucket_info(0).atom_size());
214 ASSERT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
215 ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
216 EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
217 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
218 data.bucket_info(0).end_bucket_elapsed_nanos());
219 EXPECT_EQ(AppStartOccurred::HOT,
220 data.bucket_info(0).atom(0).app_start_occurred().type());
221 EXPECT_EQ("activity_name2",
222 data.bucket_info(0).atom(0).app_start_occurred().activity_name());
223 EXPECT_EQ(102L,
224 data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
225 EXPECT_EQ(AppStartOccurred::COLD,
226 data.bucket_info(0).atom(1).app_start_occurred().type());
227 EXPECT_EQ("activity_name3",
228 data.bucket_info(0).atom(1).app_start_occurred().activity_name());
229 EXPECT_EQ(103L,
230 data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
231
232 ASSERT_EQ(1, data.bucket_info(1).atom_size());
233 ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
234 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
235 data.bucket_info(1).start_bucket_elapsed_nanos());
236 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
237 data.bucket_info(1).end_bucket_elapsed_nanos());
238 EXPECT_EQ(AppStartOccurred::WARM,
239 data.bucket_info(1).atom(0).app_start_occurred().type());
240 EXPECT_EQ("activity_name4",
241 data.bucket_info(1).atom(0).app_start_occurred().activity_name());
242 EXPECT_EQ(104L,
243 data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
244
245 ASSERT_EQ(2, data.bucket_info(2).atom_size());
246 ASSERT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
247 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
248 data.bucket_info(2).start_bucket_elapsed_nanos());
249 EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
250 data.bucket_info(2).end_bucket_elapsed_nanos());
251 EXPECT_EQ(AppStartOccurred::COLD,
252 data.bucket_info(2).atom(0).app_start_occurred().type());
253 EXPECT_EQ("activity_name5",
254 data.bucket_info(2).atom(0).app_start_occurred().activity_name());
255 EXPECT_EQ(105L,
256 data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
257 EXPECT_EQ(AppStartOccurred::HOT,
258 data.bucket_info(2).atom(1).app_start_occurred().type());
259 EXPECT_EQ("activity_name6",
260 data.bucket_info(2).atom(1).app_start_occurred().activity_name());
261 EXPECT_EQ(106L,
262 data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
263 } else {
264 ASSERT_EQ(1, data.bucket_info(0).atom_size());
265 ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
266 EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
267 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
268 data.bucket_info(0).end_bucket_elapsed_nanos());
269 EXPECT_EQ(AppStartOccurred::HOT,
270 data.bucket_info(0).atom(0).app_start_occurred().type());
271 EXPECT_EQ("activity_name2",
272 data.bucket_info(0).atom(0).app_start_occurred().activity_name());
273 EXPECT_EQ(102L,
274 data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
275
276 ASSERT_EQ(1, data.bucket_info(1).atom_size());
277 ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
278 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
279 data.bucket_info(1).start_bucket_elapsed_nanos());
280 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
281 data.bucket_info(1).end_bucket_elapsed_nanos());
282 EXPECT_EQ(AppStartOccurred::WARM,
283 data.bucket_info(1).atom(0).app_start_occurred().type());
284 EXPECT_EQ("activity_name4",
285 data.bucket_info(1).atom(0).app_start_occurred().activity_name());
286 EXPECT_EQ(104L,
287 data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
288
289 ASSERT_EQ(1, data.bucket_info(2).atom_size());
290 ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
291 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
292 data.bucket_info(2).start_bucket_elapsed_nanos());
293 EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
294 data.bucket_info(2).end_bucket_elapsed_nanos());
295 EXPECT_EQ(AppStartOccurred::COLD,
296 data.bucket_info(2).atom(0).app_start_occurred().type());
297 EXPECT_EQ("activity_name5",
298 data.bucket_info(2).atom(0).app_start_occurred().activity_name());
299 EXPECT_EQ(105L,
300 data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
301 }
302
303 data = gaugeMetrics.data(1);
304
305 EXPECT_EQ(data.dimensions_in_what().field(), util::APP_START_OCCURRED);
306 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
307 EXPECT_EQ(1 /* uid field */,
308 data.dimensions_in_what().value_tuple().dimensions_value(0).field());
309 EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
310 ASSERT_EQ(1, data.bucket_info_size());
311 ASSERT_EQ(1, data.bucket_info(0).atom_size());
312 ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
313 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
314 data.bucket_info(0).start_bucket_elapsed_nanos());
315 EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
316 data.bucket_info(0).end_bucket_elapsed_nanos());
317 EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
318 EXPECT_EQ("activity_name7",
319 data.bucket_info(0).atom(0).app_start_occurred().activity_name());
320 EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
321 }
322 }
323
TEST_F(GaugeMetricE2ePushedTest,TestRepeatedFieldsForPushedEvent)324 TEST_F(GaugeMetricE2ePushedTest, TestRepeatedFieldsForPushedEvent) {
325 for (const auto& sampling_type :
326 {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
327 StatsdConfig config = CreateStatsdConfigForRepeatedFieldsPushedEvent(sampling_type);
328 int64_t bucketStartTimeNs = 10000000000;
329 int64_t bucketSizeNs =
330 TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
331
332 ConfigKey cfgKey;
333 sp<StatsLogProcessor> processor =
334 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
335
336 std::vector<std::unique_ptr<LogEvent>> events;
337
338 vector<int> intArray = {3, 6};
339 vector<int64_t> longArray = {1000L, 10002L};
340 vector<float> floatArray = {0.3f, 0.09f};
341 vector<string> stringArray = {"str1", "str2"};
342 int boolArrayLength = 2;
343 bool boolArray[boolArrayLength];
344 boolArray[0] = 1;
345 boolArray[1] = 0;
346 vector<bool> boolArrayVector = {1, 0};
347 vector<int> enumArray = {TestAtomReported::ON, TestAtomReported::OFF};
348
349 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
350 bucketStartTimeNs + 10 * NS_PER_SEC, intArray, longArray, floatArray, stringArray,
351 boolArray, boolArrayLength, enumArray));
352 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
353 bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {}));
354
355 for (const auto& event : events) {
356 processor->OnLogEvent(event.get());
357 }
358
359 ConfigMetricsReportList reports;
360 vector<uint8_t> buffer;
361 processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
362 FAST, &buffer);
363 EXPECT_TRUE(buffer.size() > 0);
364 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
365 backfillDimensionPath(&reports);
366 backfillStringInReport(&reports);
367 backfillStartEndTimestamp(&reports);
368 backfillAggregatedAtoms(&reports);
369
370 ASSERT_EQ(1, reports.reports_size());
371 ASSERT_EQ(1, reports.reports(0).metrics_size());
372 StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
373 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
374 &gaugeMetrics);
375 ASSERT_EQ(1, gaugeMetrics.data_size());
376
377 GaugeMetricData data = gaugeMetrics.data(0);
378 ASSERT_EQ(1, data.bucket_info_size());
379 if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
380 EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
381 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
382 data.bucket_info(0).end_bucket_elapsed_nanos());
383 ASSERT_EQ(2, data.bucket_info(0).atom_size());
384
385 TestAtomReported atom = data.bucket_info(0).atom(0).test_atom_reported();
386 EXPECT_THAT(atom.repeated_int_field(), ElementsAreArray({3}));
387 EXPECT_THAT(atom.repeated_long_field(), ElementsAreArray({10002L}));
388 EXPECT_THAT(atom.repeated_float_field(), ElementsAreArray(floatArray));
389 EXPECT_THAT(atom.repeated_string_field(), ElementsAreArray({"str1"}));
390 EXPECT_THAT(atom.repeated_boolean_field(), ElementsAreArray({0}));
391 EXPECT_THAT(atom.repeated_enum_field(), ElementsAreArray(enumArray));
392
393 atom = data.bucket_info(0).atom(1).test_atom_reported();
394 EXPECT_EQ(atom.repeated_int_field_size(), 0);
395 EXPECT_EQ(atom.repeated_long_field_size(), 0);
396 EXPECT_EQ(atom.repeated_float_field_size(), 0);
397 EXPECT_EQ(atom.repeated_string_field_size(), 0);
398 EXPECT_EQ(atom.repeated_boolean_field_size(), 0);
399 EXPECT_EQ(atom.repeated_enum_field_size(), 0);
400 } else {
401 EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
402 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
403 data.bucket_info(0).end_bucket_elapsed_nanos());
404 ASSERT_EQ(1, data.bucket_info(0).atom_size());
405
406 TestAtomReported atom = data.bucket_info(0).atom(0).test_atom_reported();
407 EXPECT_THAT(atom.repeated_int_field(), ElementsAreArray({3}));
408 EXPECT_THAT(atom.repeated_long_field(), ElementsAreArray({10002L}));
409 EXPECT_THAT(atom.repeated_float_field(), ElementsAreArray(floatArray));
410 EXPECT_THAT(atom.repeated_string_field(), ElementsAreArray({"str1"}));
411 EXPECT_THAT(atom.repeated_boolean_field(), ElementsAreArray({0}));
412 EXPECT_THAT(atom.repeated_enum_field(), ElementsAreArray(enumArray));
413 }
414 }
415 }
416
417 #else
418 GTEST_LOG_(INFO) << "This test does nothing.\n";
419 #endif
420
421 } // namespace statsd
422 } // namespace os
423 } // namespace android
424