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 "src/guardrail/StatsdStats.h"
16 #include "statslog_statsdtest.h"
17 #include "tests/statsd_test_util.h"
18
19 #include <gtest/gtest.h>
20 #include <vector>
21
22 #ifdef __ANDROID__
23
24 namespace android {
25 namespace os {
26 namespace statsd {
27
28 using std::vector;
29
TEST(StatsdStatsTest,TestValidConfigAdd)30 TEST(StatsdStatsTest, TestValidConfigAdd) {
31 StatsdStats stats;
32 ConfigKey key(0, 12345);
33 const int metricsCount = 10;
34 const int conditionsCount = 20;
35 const int matchersCount = 30;
36 const int alertsCount = 10;
37 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
38 true /*valid config*/);
39 vector<uint8_t> output;
40 stats.dumpStats(&output, false /*reset stats*/);
41
42 StatsdStatsReport report;
43 bool good = report.ParseFromArray(&output[0], output.size());
44 EXPECT_TRUE(good);
45 ASSERT_EQ(1, report.config_stats_size());
46 const auto& configReport = report.config_stats(0);
47 EXPECT_EQ(0, configReport.uid());
48 EXPECT_EQ(12345, configReport.id());
49 EXPECT_EQ(metricsCount, configReport.metric_count());
50 EXPECT_EQ(conditionsCount, configReport.condition_count());
51 EXPECT_EQ(matchersCount, configReport.matcher_count());
52 EXPECT_EQ(alertsCount, configReport.alert_count());
53 EXPECT_EQ(true, configReport.is_valid());
54 EXPECT_FALSE(configReport.has_deletion_time_sec());
55 }
56
TEST(StatsdStatsTest,TestInvalidConfigAdd)57 TEST(StatsdStatsTest, TestInvalidConfigAdd) {
58 StatsdStats stats;
59 ConfigKey key(0, 12345);
60 const int metricsCount = 10;
61 const int conditionsCount = 20;
62 const int matchersCount = 30;
63 const int alertsCount = 10;
64 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
65 false /*bad config*/);
66 vector<uint8_t> output;
67 stats.dumpStats(&output, false);
68
69 StatsdStatsReport report;
70 bool good = report.ParseFromArray(&output[0], output.size());
71 EXPECT_TRUE(good);
72 ASSERT_EQ(1, report.config_stats_size());
73 const auto& configReport = report.config_stats(0);
74 // The invalid config should be put into icebox with a deletion time.
75 EXPECT_TRUE(configReport.has_deletion_time_sec());
76 }
77
TEST(StatsdStatsTest,TestConfigRemove)78 TEST(StatsdStatsTest, TestConfigRemove) {
79 StatsdStats stats;
80 ConfigKey key(0, 12345);
81 const int metricsCount = 10;
82 const int conditionsCount = 20;
83 const int matchersCount = 30;
84 const int alertsCount = 10;
85 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
86 true);
87 vector<uint8_t> output;
88 stats.dumpStats(&output, false);
89 StatsdStatsReport report;
90 bool good = report.ParseFromArray(&output[0], output.size());
91 EXPECT_TRUE(good);
92 ASSERT_EQ(1, report.config_stats_size());
93 const auto& configReport = report.config_stats(0);
94 EXPECT_FALSE(configReport.has_deletion_time_sec());
95
96 stats.noteConfigRemoved(key);
97 stats.dumpStats(&output, false);
98 good = report.ParseFromArray(&output[0], output.size());
99 EXPECT_TRUE(good);
100 ASSERT_EQ(1, report.config_stats_size());
101 const auto& configReport2 = report.config_stats(0);
102 EXPECT_TRUE(configReport2.has_deletion_time_sec());
103 }
104
TEST(StatsdStatsTest,TestSubStats)105 TEST(StatsdStatsTest, TestSubStats) {
106 StatsdStats stats;
107 ConfigKey key(0, 12345);
108 stats.noteConfigReceived(key, 2, 3, 4, 5, {std::make_pair(123, 456)}, true);
109
110 stats.noteMatcherMatched(key, StringToId("matcher1"));
111 stats.noteMatcherMatched(key, StringToId("matcher1"));
112 stats.noteMatcherMatched(key, StringToId("matcher2"));
113
114 stats.noteConditionDimensionSize(key, StringToId("condition1"), 250);
115 stats.noteConditionDimensionSize(key, StringToId("condition1"), 240);
116
117 stats.noteMetricDimensionSize(key, StringToId("metric1"), 201);
118 stats.noteMetricDimensionSize(key, StringToId("metric1"), 202);
119
120 stats.noteAnomalyDeclared(key, StringToId("alert1"));
121 stats.noteAnomalyDeclared(key, StringToId("alert1"));
122 stats.noteAnomalyDeclared(key, StringToId("alert2"));
123
124 // broadcast-> 2
125 stats.noteBroadcastSent(key);
126 stats.noteBroadcastSent(key);
127
128 // data drop -> 1
129 stats.noteDataDropped(key, 123);
130
131 // dump report -> 3
132 stats.noteMetricsReportSent(key, 0);
133 stats.noteMetricsReportSent(key, 0);
134 stats.noteMetricsReportSent(key, 0);
135
136 // activation_time_sec -> 2
137 stats.noteActiveStatusChanged(key, true);
138 stats.noteActiveStatusChanged(key, true);
139
140 // deactivation_time_sec -> 1
141 stats.noteActiveStatusChanged(key, false);
142
143 vector<uint8_t> output;
144 stats.dumpStats(&output, true); // Dump and reset stats
145 StatsdStatsReport report;
146 bool good = report.ParseFromArray(&output[0], output.size());
147 EXPECT_TRUE(good);
148 ASSERT_EQ(1, report.config_stats_size());
149 const auto& configReport = report.config_stats(0);
150 ASSERT_EQ(2, configReport.broadcast_sent_time_sec_size());
151 ASSERT_EQ(1, configReport.data_drop_time_sec_size());
152 ASSERT_EQ(1, configReport.data_drop_bytes_size());
153 EXPECT_EQ(123, configReport.data_drop_bytes(0));
154 ASSERT_EQ(3, configReport.dump_report_time_sec_size());
155 ASSERT_EQ(3, configReport.dump_report_data_size_size());
156 ASSERT_EQ(2, configReport.activation_time_sec_size());
157 ASSERT_EQ(1, configReport.deactivation_time_sec_size());
158 ASSERT_EQ(1, configReport.annotation_size());
159 EXPECT_EQ(123, configReport.annotation(0).field_int64());
160 EXPECT_EQ(456, configReport.annotation(0).field_int32());
161
162 ASSERT_EQ(2, configReport.matcher_stats_size());
163 // matcher1 is the first in the list
164 if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
165 EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
166 EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
167 EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(1).id());
168 } else {
169 // matcher1 is the second in the list.
170 EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
171 EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(0).id());
172
173 EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
174 EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
175 }
176
177 ASSERT_EQ(2, configReport.alert_stats_size());
178 bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
179 EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
180 EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
181 EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
182 EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
183
184 ASSERT_EQ(1, configReport.condition_stats_size());
185 EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
186 EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
187
188 ASSERT_EQ(1, configReport.metric_stats_size());
189 EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
190 EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
191
192 // after resetting the stats, some new events come
193 stats.noteMatcherMatched(key, StringToId("matcher99"));
194 stats.noteConditionDimensionSize(key, StringToId("condition99"), 300);
195 stats.noteMetricDimensionSize(key, StringToId("metric99tion99"), 270);
196 stats.noteAnomalyDeclared(key, StringToId("alert99"));
197
198 // now the config stats should only contain the stats about the new event.
199 stats.dumpStats(&output, false);
200 good = report.ParseFromArray(&output[0], output.size());
201 EXPECT_TRUE(good);
202 ASSERT_EQ(1, report.config_stats_size());
203 const auto& configReport2 = report.config_stats(0);
204 ASSERT_EQ(1, configReport2.matcher_stats_size());
205 EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
206 EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
207
208 ASSERT_EQ(1, configReport2.condition_stats_size());
209 EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
210 EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
211
212 ASSERT_EQ(1, configReport2.metric_stats_size());
213 EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
214 EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
215
216 ASSERT_EQ(1, configReport2.alert_stats_size());
217 EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
218 EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
219 }
220
TEST(StatsdStatsTest,TestAtomLog)221 TEST(StatsdStatsTest, TestAtomLog) {
222 StatsdStats stats;
223 time_t now = time(nullptr);
224 // old event, we get it from the stats buffer. should be ignored.
225 stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, 1000);
226
227 stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, now + 1);
228 stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, now + 2);
229 stats.noteAtomLogged(util::APP_CRASH_OCCURRED, now + 3);
230
231 vector<uint8_t> output;
232 stats.dumpStats(&output, false);
233 StatsdStatsReport report;
234 bool good = report.ParseFromArray(&output[0], output.size());
235 EXPECT_TRUE(good);
236
237 ASSERT_EQ(2, report.atom_stats_size());
238 bool sensorAtomGood = false;
239 bool dropboxAtomGood = false;
240
241 for (const auto& atomStats : report.atom_stats()) {
242 if (atomStats.tag() == util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
243 sensorAtomGood = true;
244 }
245 if (atomStats.tag() == util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
246 dropboxAtomGood = true;
247 }
248 }
249
250 EXPECT_TRUE(dropboxAtomGood);
251 EXPECT_TRUE(sensorAtomGood);
252 }
253
TEST(StatsdStatsTest,TestNonPlatformAtomLog)254 TEST(StatsdStatsTest, TestNonPlatformAtomLog) {
255 StatsdStats stats;
256 time_t now = time(nullptr);
257 int newAtom1 = StatsdStats::kMaxPushedAtomId + 1;
258 int newAtom2 = StatsdStats::kMaxPushedAtomId + 2;
259
260 stats.noteAtomLogged(newAtom1, now + 1);
261 stats.noteAtomLogged(newAtom1, now + 2);
262 stats.noteAtomLogged(newAtom2, now + 3);
263
264 vector<uint8_t> output;
265 stats.dumpStats(&output, false);
266 StatsdStatsReport report;
267 bool good = report.ParseFromArray(&output[0], output.size());
268 EXPECT_TRUE(good);
269
270 ASSERT_EQ(2, report.atom_stats_size());
271 bool newAtom1Good = false;
272 bool newAtom2Good = false;
273
274 for (const auto& atomStats : report.atom_stats()) {
275 if (atomStats.tag() == newAtom1 && atomStats.count() == 2) {
276 newAtom1Good = true;
277 }
278 if (atomStats.tag() == newAtom2 && atomStats.count() == 1) {
279 newAtom2Good = true;
280 }
281 }
282
283 EXPECT_TRUE(newAtom1Good);
284 EXPECT_TRUE(newAtom2Good);
285 }
286
TEST(StatsdStatsTest,TestPullAtomStats)287 TEST(StatsdStatsTest, TestPullAtomStats) {
288 StatsdStats stats;
289
290 stats.updateMinPullIntervalSec(util::DISK_SPACE, 3333L);
291 stats.updateMinPullIntervalSec(util::DISK_SPACE, 2222L);
292 stats.updateMinPullIntervalSec(util::DISK_SPACE, 4444L);
293
294 stats.notePull(util::DISK_SPACE);
295 stats.notePullTime(util::DISK_SPACE, 1111L);
296 stats.notePullDelay(util::DISK_SPACE, 1111L);
297 stats.notePull(util::DISK_SPACE);
298 stats.notePullTime(util::DISK_SPACE, 3333L);
299 stats.notePullDelay(util::DISK_SPACE, 3335L);
300 stats.notePull(util::DISK_SPACE);
301 stats.notePullFromCache(util::DISK_SPACE);
302 stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
303 stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, false);
304 stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
305 stats.notePullBinderCallFailed(util::DISK_SPACE);
306 stats.notePullUidProviderNotFound(util::DISK_SPACE);
307 stats.notePullerNotFound(util::DISK_SPACE);
308 stats.notePullerNotFound(util::DISK_SPACE);
309 stats.notePullTimeout(util::DISK_SPACE, 3000L, 6000L);
310 stats.notePullTimeout(util::DISK_SPACE, 4000L, 7000L);
311
312 vector<uint8_t> output;
313 stats.dumpStats(&output, false);
314 StatsdStatsReport report;
315 bool good = report.ParseFromArray(&output[0], output.size());
316 EXPECT_TRUE(good);
317
318 ASSERT_EQ(1, report.pulled_atom_stats_size());
319
320 EXPECT_EQ(util::DISK_SPACE, report.pulled_atom_stats(0).atom_id());
321 EXPECT_EQ(3, report.pulled_atom_stats(0).total_pull());
322 EXPECT_EQ(1, report.pulled_atom_stats(0).total_pull_from_cache());
323 EXPECT_EQ(2222L, report.pulled_atom_stats(0).min_pull_interval_sec());
324 EXPECT_EQ(2222L, report.pulled_atom_stats(0).average_pull_time_nanos());
325 EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos());
326 EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos());
327 EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
328 EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
329 EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
330 EXPECT_EQ(1L, report.pulled_atom_stats(0).binder_call_failed());
331 EXPECT_EQ(1L, report.pulled_atom_stats(0).failed_uid_provider_not_found());
332 EXPECT_EQ(2L, report.pulled_atom_stats(0).puller_not_found());
333 ASSERT_EQ(2, report.pulled_atom_stats(0).pull_atom_metadata_size());
334 EXPECT_EQ(3000L, report.pulled_atom_stats(0).pull_atom_metadata(0).pull_timeout_uptime_millis());
335 EXPECT_EQ(4000L, report.pulled_atom_stats(0).pull_atom_metadata(1).pull_timeout_uptime_millis());
336 EXPECT_EQ(6000L, report.pulled_atom_stats(0).pull_atom_metadata(0)
337 .pull_timeout_elapsed_millis());
338 EXPECT_EQ(7000L, report.pulled_atom_stats(0).pull_atom_metadata(1)
339 .pull_timeout_elapsed_millis());
340 }
341
TEST(StatsdStatsTest,TestAtomMetricsStats)342 TEST(StatsdStatsTest, TestAtomMetricsStats) {
343 StatsdStats stats;
344 time_t now = time(nullptr);
345 // old event, we get it from the stats buffer. should be ignored.
346 stats.noteBucketDropped(1000L);
347
348 stats.noteBucketBoundaryDelayNs(1000L, -1L);
349 stats.noteBucketBoundaryDelayNs(1000L, -10L);
350 stats.noteBucketBoundaryDelayNs(1000L, 2L);
351
352 stats.noteBucketBoundaryDelayNs(1001L, 1L);
353
354 vector<uint8_t> output;
355 stats.dumpStats(&output, false);
356 StatsdStatsReport report;
357 bool good = report.ParseFromArray(&output[0], output.size());
358 EXPECT_TRUE(good);
359
360 ASSERT_EQ(2, report.atom_metric_stats().size());
361
362 auto atomStats = report.atom_metric_stats(0);
363 EXPECT_EQ(1000L, atomStats.metric_id());
364 EXPECT_EQ(1L, atomStats.bucket_dropped());
365 EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns());
366 EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns());
367
368 auto atomStats2 = report.atom_metric_stats(1);
369 EXPECT_EQ(1001L, atomStats2.metric_id());
370 EXPECT_EQ(0L, atomStats2.bucket_dropped());
371 EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns());
372 EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns());
373 }
374
TEST(StatsdStatsTest,TestAnomalyMonitor)375 TEST(StatsdStatsTest, TestAnomalyMonitor) {
376 StatsdStats stats;
377 stats.noteRegisteredAnomalyAlarmChanged();
378 stats.noteRegisteredAnomalyAlarmChanged();
379
380 vector<uint8_t> output;
381 stats.dumpStats(&output, false);
382 StatsdStatsReport report;
383 bool good = report.ParseFromArray(&output[0], output.size());
384 EXPECT_TRUE(good);
385
386 EXPECT_EQ(2, report.anomaly_alarm_stats().alarms_registered());
387 }
388
TEST(StatsdStatsTest,TestTimestampThreshold)389 TEST(StatsdStatsTest, TestTimestampThreshold) {
390 StatsdStats stats;
391 vector<int32_t> timestamps;
392 for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
393 timestamps.push_back(i);
394 }
395 ConfigKey key(0, 12345);
396 stats.noteConfigReceived(key, 2, 3, 4, 5, {}, true);
397
398 for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
399 stats.noteDataDropped(key, timestamps[i]);
400 stats.noteBroadcastSent(key, timestamps[i]);
401 stats.noteMetricsReportSent(key, 0, timestamps[i]);
402 stats.noteActiveStatusChanged(key, true, timestamps[i]);
403 stats.noteActiveStatusChanged(key, false, timestamps[i]);
404 }
405
406 int32_t newTimestamp = 10000;
407
408 // now it should trigger removing oldest timestamp
409 stats.noteDataDropped(key, 123, 10000);
410 stats.noteBroadcastSent(key, 10000);
411 stats.noteMetricsReportSent(key, 0, 10000);
412 stats.noteActiveStatusChanged(key, true, 10000);
413 stats.noteActiveStatusChanged(key, false, 10000);
414
415 EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
416 const auto& configStats = stats.mConfigStats[key];
417
418 size_t maxCount = StatsdStats::kMaxTimestampCount;
419 ASSERT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
420 ASSERT_EQ(maxCount, configStats->data_drop_time_sec.size());
421 ASSERT_EQ(maxCount, configStats->dump_report_stats.size());
422 ASSERT_EQ(maxCount, configStats->activation_time_sec.size());
423 ASSERT_EQ(maxCount, configStats->deactivation_time_sec.size());
424
425 // the oldest timestamp is the second timestamp in history
426 EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
427 EXPECT_EQ(1, configStats->data_drop_bytes.front());
428 EXPECT_EQ(1, configStats->dump_report_stats.front().first);
429 EXPECT_EQ(1, configStats->activation_time_sec.front());
430 EXPECT_EQ(1, configStats->deactivation_time_sec.front());
431
432 // the last timestamp is the newest timestamp.
433 EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
434 EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
435 EXPECT_EQ(123, configStats->data_drop_bytes.back());
436 EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
437 EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
438 EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
439 }
440
TEST(StatsdStatsTest,TestSystemServerCrash)441 TEST(StatsdStatsTest, TestSystemServerCrash) {
442 StatsdStats stats;
443 vector<int32_t> timestamps;
444 for (int i = 0; i < StatsdStats::kMaxSystemServerRestarts; i++) {
445 timestamps.push_back(i);
446 stats.noteSystemServerRestart(timestamps[i]);
447 }
448 vector<uint8_t> output;
449 stats.dumpStats(&output, false);
450 StatsdStatsReport report;
451 EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
452 const int maxCount = StatsdStats::kMaxSystemServerRestarts;
453 ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
454
455 stats.noteSystemServerRestart(StatsdStats::kMaxSystemServerRestarts + 1);
456 output.clear();
457 stats.dumpStats(&output, false);
458 EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
459 ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
460 EXPECT_EQ(StatsdStats::kMaxSystemServerRestarts + 1, report.system_restart_sec(maxCount - 1));
461 }
462
TEST(StatsdStatsTest,TestActivationBroadcastGuardrailHit)463 TEST(StatsdStatsTest, TestActivationBroadcastGuardrailHit) {
464 StatsdStats stats;
465 int uid1 = 1;
466 int uid2 = 2;
467 stats.noteActivationBroadcastGuardrailHit(uid1, 10);
468 stats.noteActivationBroadcastGuardrailHit(uid1, 20);
469
470 // Test that we only keep 20 timestamps.
471 for (int i = 0; i < 100; i++) {
472 stats.noteActivationBroadcastGuardrailHit(uid2, i);
473 }
474
475 vector<uint8_t> output;
476 stats.dumpStats(&output, false);
477 StatsdStatsReport report;
478 EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
479
480 ASSERT_EQ(2, report.activation_guardrail_stats_size());
481 bool uid1Good = false;
482 bool uid2Good = false;
483 for (const auto& guardrailTimes : report.activation_guardrail_stats()) {
484 if (uid1 == guardrailTimes.uid()) {
485 uid1Good = true;
486 ASSERT_EQ(2, guardrailTimes.guardrail_met_sec_size());
487 EXPECT_EQ(10, guardrailTimes.guardrail_met_sec(0));
488 EXPECT_EQ(20, guardrailTimes.guardrail_met_sec(1));
489 } else if (uid2 == guardrailTimes.uid()) {
490 int maxCount = StatsdStats::kMaxTimestampCount;
491 uid2Good = true;
492 ASSERT_EQ(maxCount, guardrailTimes.guardrail_met_sec_size());
493 for (int i = 0; i < maxCount; i++) {
494 EXPECT_EQ(100 - maxCount + i, guardrailTimes.guardrail_met_sec(i));
495 }
496 } else {
497 FAIL() << "Unexpected uid.";
498 }
499 }
500 EXPECT_TRUE(uid1Good);
501 EXPECT_TRUE(uid2Good);
502 }
503
TEST(StatsdStatsTest,TestAtomErrorStats)504 TEST(StatsdStatsTest, TestAtomErrorStats) {
505 StatsdStats stats;
506
507 int pushAtomTag = 100;
508 int pullAtomTag = 1000;
509 int numErrors = 10;
510
511 for (int i = 0; i < numErrors; i++) {
512 // We must call noteAtomLogged as well because only those pushed atoms
513 // that have been logged will have stats printed about them in the
514 // proto.
515 stats.noteAtomLogged(pushAtomTag, /*timeSec=*/0);
516 stats.noteAtomError(pushAtomTag, /*pull=*/false);
517
518 stats.noteAtomError(pullAtomTag, /*pull=*/true);
519 }
520
521 vector<uint8_t> output;
522 stats.dumpStats(&output, false);
523 StatsdStatsReport report;
524 EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
525
526 // Check error count = numErrors for push atom
527 ASSERT_EQ(1, report.atom_stats_size());
528 const auto& pushedAtomStats = report.atom_stats(0);
529 EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
530 EXPECT_EQ(numErrors, pushedAtomStats.error_count());
531
532 // Check error count = numErrors for pull atom
533 ASSERT_EQ(1, report.pulled_atom_stats_size());
534 const auto& pulledAtomStats = report.pulled_atom_stats(0);
535 EXPECT_EQ(pullAtomTag, pulledAtomStats.atom_id());
536 EXPECT_EQ(numErrors, pulledAtomStats.atom_error_count());
537 }
538
539 } // namespace statsd
540 } // namespace os
541 } // namespace android
542 #else
543 GTEST_LOG_(INFO) << "This test does nothing.\n";
544 #endif
545