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
17 #include <com_android_os_statsd_flags.h>
18 #include <flag_macros.h>
19 #include <gtest/gtest.h>
20
21 #include <vector>
22
23 #include "gtest_matchers.h"
24 #include "src/metrics/parsing_utils/metrics_manager_util.h"
25 #include "src/shell/ShellSubscriber.h"
26 #include "src/stats_log.pb.h"
27 #include "statslog_statsdtest.h"
28 #include "tests/statsd_test_util.h"
29
30 #ifdef __ANDROID__
31
32 namespace std {
PrintTo(const tuple<int,size_t> & atomIdDimensionLimitTuple,ostream * os)33 void PrintTo(const tuple<int, size_t>& atomIdDimensionLimitTuple, ostream* os) {
34 *os << get<0>(atomIdDimensionLimitTuple) << "_" << get<1>(atomIdDimensionLimitTuple);
35 }
36 } // namespace std
37
38 namespace android {
39 namespace os {
40 namespace statsd {
41 namespace {
42
43 using namespace testing;
44 using PerSubscriptionStats = StatsdStatsReport_SubscriptionStats_PerSubscriptionStats;
45 using std::tuple;
46 using std::unordered_map;
47 using std::vector;
48
49 #define TEST_NS com::android::os::statsd::flags
50
51 class StatsdStatsTest_GetAtomDimensionKeySizeLimit_InMap
52 : public TestWithParam<tuple<int, size_t>> {};
53 INSTANTIATE_TEST_SUITE_P(StatsdStatsTest_GetAtomDimensionKeySizeLimit_InMap,
54 StatsdStatsTest_GetAtomDimensionKeySizeLimit_InMap,
55 Combine(Values(10022 /* BINDER_CALLS */, 10024 /* LOOPER_STATS */,
56 10010 /* CPU_TIME_PER_UID_FREQ */),
57 Values(-1, 0, 500, 800, 1000, 3000, 3300)),
58 PrintToStringParamName());
59
60 class StatsdStatsTest_GetAtomDimensionKeySizeLimit_NotInMap
61 : public StatsdStatsTest_GetAtomDimensionKeySizeLimit_InMap {};
62
63 INSTANTIATE_TEST_SUITE_P(StatsdStatsTest_GetAtomDimensionKeySizeLimit_NotInMap,
64 StatsdStatsTest_GetAtomDimensionKeySizeLimit_NotInMap,
65 Combine(Values(util::TEST_ATOM_REPORTED, util::SCREEN_STATE_CHANGED,
66 util::SUBSYSTEM_SLEEP_STATE),
67 Values(-1, 0, 500, 800, 1000, 3000, 3300)),
68 PrintToStringParamName());
69
70 } // anonymous namespace
71
TEST(StatsdStatsTest,TestValidConfigAdd)72 TEST(StatsdStatsTest, TestValidConfigAdd) {
73 StatsdStats stats;
74 ConfigKey key(0, 12345);
75 const int metricsCount = 10;
76 const int conditionsCount = 20;
77 const int matchersCount = 30;
78 const int alertsCount = 10;
79 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
80 nullopt /*valid config*/);
81
82 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
83 ASSERT_EQ(1, report.config_stats_size());
84 const auto& configReport = report.config_stats(0);
85 EXPECT_EQ(0, configReport.uid());
86 EXPECT_EQ(12345, configReport.id());
87 EXPECT_EQ(metricsCount, configReport.metric_count());
88 EXPECT_EQ(conditionsCount, configReport.condition_count());
89 EXPECT_EQ(matchersCount, configReport.matcher_count());
90 EXPECT_EQ(alertsCount, configReport.alert_count());
91 EXPECT_EQ(true, configReport.is_valid());
92 EXPECT_FALSE(configReport.has_invalid_config_reason());
93 EXPECT_FALSE(configReport.has_deletion_time_sec());
94 }
95
TEST(StatsdStatsTest,TestConfigMetadataProviderPromotionFailed)96 TEST(StatsdStatsTest, TestConfigMetadataProviderPromotionFailed) {
97 StatsdStats stats;
98 ConfigKey key(0, 12345);
99 stats.noteConfigReceived(key, /*metricsCount=*/0, /*conditionsCount=*/0, /*matchersCount=*/0,
100 /*alertCount=*/0, /*annotations=*/{}, nullopt /*valid config*/);
101
102 stats.noteConfigMetadataProviderPromotionFailed(key);
103
104 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
105 ASSERT_EQ(1, report.config_stats_size());
106 const auto& configReport = report.config_stats(0);
107 EXPECT_EQ(1, configReport.config_metadata_provider_promotion_failed());
108 }
109
TEST(StatsdStatsTest,TestInvalidConfigAdd)110 TEST(StatsdStatsTest, TestInvalidConfigAdd) {
111 StatsdStats stats;
112 ConfigKey key(0, 12345);
113 const int metricsCount = 10;
114 const int conditionsCount = 20;
115 const int matchersCount = 30;
116 const int alertsCount = 10;
117 optional<InvalidConfigReason> invalidConfigReason =
118 InvalidConfigReason(INVALID_CONFIG_REASON_UNKNOWN, 1);
119 invalidConfigReason->stateId = 2;
120 invalidConfigReason->alertId = 3;
121 invalidConfigReason->alarmId = 4;
122 invalidConfigReason->subscriptionId = 5;
123 invalidConfigReason->matcherIds.push_back(6);
124 invalidConfigReason->matcherIds.push_back(7);
125 invalidConfigReason->conditionIds.push_back(8);
126 invalidConfigReason->conditionIds.push_back(9);
127 invalidConfigReason->conditionIds.push_back(10);
128 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
129 invalidConfigReason /*bad config*/);
130
131 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
132 ASSERT_EQ(1, report.config_stats_size());
133 const auto& configReport = report.config_stats(0);
134 // The invalid config should be put into icebox with a deletion time.
135 EXPECT_TRUE(configReport.has_deletion_time_sec());
136 EXPECT_TRUE(configReport.has_invalid_config_reason());
137 EXPECT_EQ(configReport.invalid_config_reason().reason(), INVALID_CONFIG_REASON_UNKNOWN);
138 EXPECT_EQ(configReport.invalid_config_reason().metric_id(), 1);
139 EXPECT_EQ(configReport.invalid_config_reason().state_id(), 2);
140 EXPECT_EQ(configReport.invalid_config_reason().alert_id(), 3);
141 EXPECT_EQ(configReport.invalid_config_reason().alarm_id(), 4);
142 EXPECT_EQ(configReport.invalid_config_reason().subscription_id(), 5);
143 EXPECT_EQ(configReport.invalid_config_reason().matcher_id_size(), 2);
144 EXPECT_EQ(configReport.invalid_config_reason().matcher_id(0), 6);
145 EXPECT_EQ(configReport.invalid_config_reason().matcher_id(1), 7);
146 EXPECT_EQ(configReport.invalid_config_reason().condition_id_size(), 3);
147 EXPECT_EQ(configReport.invalid_config_reason().condition_id(0), 8);
148 EXPECT_EQ(configReport.invalid_config_reason().condition_id(1), 9);
149 EXPECT_EQ(configReport.invalid_config_reason().condition_id(2), 10);
150 }
151
TEST(StatsdStatsTest,TestInvalidConfigMissingMetricId)152 TEST(StatsdStatsTest, TestInvalidConfigMissingMetricId) {
153 StatsdStats stats;
154 ConfigKey key(0, 12345);
155 const int metricsCount = 10;
156 const int conditionsCount = 20;
157 const int matchersCount = 30;
158 const int alertsCount = 10;
159 optional<InvalidConfigReason> invalidConfigReason =
160 InvalidConfigReason(INVALID_CONFIG_REASON_SUBSCRIPTION_SUBSCRIBER_INFO_MISSING);
161 invalidConfigReason->stateId = 1;
162 invalidConfigReason->alertId = 2;
163 invalidConfigReason->alarmId = 3;
164 invalidConfigReason->subscriptionId = 4;
165 invalidConfigReason->matcherIds.push_back(5);
166 invalidConfigReason->conditionIds.push_back(6);
167 invalidConfigReason->conditionIds.push_back(7);
168 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
169 invalidConfigReason /*bad config*/);
170
171 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
172 ASSERT_EQ(1, report.config_stats_size());
173 const auto& configReport = report.config_stats(0);
174 // The invalid config should be put into icebox with a deletion time.
175 EXPECT_TRUE(configReport.has_deletion_time_sec());
176 EXPECT_TRUE(configReport.has_invalid_config_reason());
177 EXPECT_EQ(configReport.invalid_config_reason().reason(),
178 INVALID_CONFIG_REASON_SUBSCRIPTION_SUBSCRIBER_INFO_MISSING);
179 EXPECT_FALSE(configReport.invalid_config_reason().has_metric_id());
180 EXPECT_EQ(configReport.invalid_config_reason().state_id(), 1);
181 EXPECT_EQ(configReport.invalid_config_reason().alert_id(), 2);
182 EXPECT_EQ(configReport.invalid_config_reason().alarm_id(), 3);
183 EXPECT_EQ(configReport.invalid_config_reason().subscription_id(), 4);
184 EXPECT_EQ(configReport.invalid_config_reason().matcher_id_size(), 1);
185 EXPECT_EQ(configReport.invalid_config_reason().matcher_id(0), 5);
186 EXPECT_EQ(configReport.invalid_config_reason().condition_id_size(), 2);
187 EXPECT_EQ(configReport.invalid_config_reason().condition_id(0), 6);
188 EXPECT_EQ(configReport.invalid_config_reason().condition_id(1), 7);
189 }
190
TEST(StatsdStatsTest,TestInvalidConfigOnlyMetricId)191 TEST(StatsdStatsTest, TestInvalidConfigOnlyMetricId) {
192 StatsdStats stats;
193 ConfigKey key(0, 12345);
194 const int metricsCount = 10;
195 const int conditionsCount = 20;
196 const int matchersCount = 30;
197 const int alertsCount = 10;
198 optional<InvalidConfigReason> invalidConfigReason =
199 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_NOT_IN_PREV_CONFIG, 1);
200 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
201 invalidConfigReason /*bad config*/);
202
203 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
204 ASSERT_EQ(1, report.config_stats_size());
205 const auto& configReport = report.config_stats(0);
206 // The invalid config should be put into icebox with a deletion time.
207 EXPECT_TRUE(configReport.has_deletion_time_sec());
208 EXPECT_TRUE(configReport.has_invalid_config_reason());
209 EXPECT_EQ(configReport.invalid_config_reason().reason(),
210 INVALID_CONFIG_REASON_METRIC_NOT_IN_PREV_CONFIG);
211 EXPECT_EQ(configReport.invalid_config_reason().metric_id(), 1);
212 EXPECT_FALSE(configReport.invalid_config_reason().has_state_id());
213 EXPECT_FALSE(configReport.invalid_config_reason().has_alert_id());
214 EXPECT_FALSE(configReport.invalid_config_reason().has_alarm_id());
215 EXPECT_FALSE(configReport.invalid_config_reason().has_subscription_id());
216 EXPECT_EQ(configReport.invalid_config_reason().matcher_id_size(), 0);
217 EXPECT_EQ(configReport.invalid_config_reason().condition_id_size(), 0);
218 }
219
TEST(StatsdStatsTest,TestConfigRemove)220 TEST(StatsdStatsTest, TestConfigRemove) {
221 StatsdStats stats;
222 ConfigKey key(0, 12345);
223 const int metricsCount = 10;
224 const int conditionsCount = 20;
225 const int matchersCount = 30;
226 const int alertsCount = 10;
227 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
228 nullopt);
229
230 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
231 ASSERT_EQ(1, report.config_stats_size());
232 const auto& configReport = report.config_stats(0);
233 EXPECT_FALSE(configReport.has_deletion_time_sec());
234
235 stats.noteConfigRemoved(key);
236
237 report = getStatsdStatsReport(stats, /* reset stats */ false);
238 ASSERT_EQ(1, report.config_stats_size());
239 const auto& configReport2 = report.config_stats(0);
240 EXPECT_TRUE(configReport2.has_deletion_time_sec());
241 }
242
TEST(StatsdStatsTest,TestSubStats)243 TEST(StatsdStatsTest, TestSubStats) {
244 StatsdStats stats;
245 ConfigKey key(0, 12345);
246 stats.noteConfigReceived(key, 2, 3, 4, 5, {std::make_pair(123, 456)}, nullopt);
247
248 stats.noteMatcherMatched(key, StringToId("matcher1"));
249 stats.noteMatcherMatched(key, StringToId("matcher1"));
250 stats.noteMatcherMatched(key, StringToId("matcher2"));
251
252 stats.noteConditionDimensionSize(key, StringToId("condition1"), 250);
253 stats.noteConditionDimensionSize(key, StringToId("condition1"), 240);
254
255 stats.noteMetricDimensionSize(key, StringToId("metric1"), 201);
256 stats.noteMetricDimensionSize(key, StringToId("metric1"), 202);
257
258 stats.noteAnomalyDeclared(key, StringToId("alert1"));
259 stats.noteAnomalyDeclared(key, StringToId("alert1"));
260 stats.noteAnomalyDeclared(key, StringToId("alert2"));
261
262 // broadcast-> 2
263 stats.noteBroadcastSent(key);
264 stats.noteBroadcastSent(key);
265
266 // data drop -> 1
267 stats.noteDataDropped(key, 123);
268
269 // dump report -> 3
270 stats.noteMetricsReportSent(key, 0, 1);
271 stats.noteMetricsReportSent(key, 0, 2);
272 stats.noteMetricsReportSent(key, 0, 3);
273
274 // activation_time_sec -> 2
275 stats.noteActiveStatusChanged(key, true);
276 stats.noteActiveStatusChanged(key, true);
277
278 // deactivation_time_sec -> 1
279 stats.noteActiveStatusChanged(key, false);
280
281 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ true);
282 ASSERT_EQ(1, report.config_stats_size());
283 const auto& configReport = report.config_stats(0);
284 ASSERT_EQ(2, configReport.broadcast_sent_time_sec_size());
285 ASSERT_EQ(1, configReport.data_drop_time_sec_size());
286 ASSERT_EQ(1, configReport.data_drop_bytes_size());
287 EXPECT_EQ(123, configReport.data_drop_bytes(0));
288 ASSERT_EQ(3, configReport.dump_report_time_sec_size());
289 ASSERT_EQ(3, configReport.dump_report_data_size_size());
290 ASSERT_EQ(3, configReport.dump_report_number_size());
291 EXPECT_EQ(1, configReport.dump_report_number(0));
292 EXPECT_EQ(2, configReport.dump_report_number(1));
293 EXPECT_EQ(3, configReport.dump_report_number(2));
294 ASSERT_EQ(2, configReport.activation_time_sec_size());
295 ASSERT_EQ(1, configReport.deactivation_time_sec_size());
296 ASSERT_EQ(1, configReport.annotation_size());
297 EXPECT_EQ(123, configReport.annotation(0).field_int64());
298 EXPECT_EQ(456, configReport.annotation(0).field_int32());
299
300 ASSERT_EQ(2, configReport.matcher_stats_size());
301 // matcher1 is the first in the list
302 if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
303 EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
304 EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
305 EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(1).id());
306 } else {
307 // matcher1 is the second in the list.
308 EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
309 EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(0).id());
310
311 EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
312 EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
313 }
314
315 ASSERT_EQ(2, configReport.alert_stats_size());
316 bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
317 EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
318 EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
319 EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
320 EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
321
322 ASSERT_EQ(1, configReport.condition_stats_size());
323 EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
324 EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
325
326 ASSERT_EQ(1, configReport.metric_stats_size());
327 EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
328 EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
329
330 // after resetting the stats, some new events come
331 stats.noteMatcherMatched(key, StringToId("matcher99"));
332 stats.noteConditionDimensionSize(key, StringToId("condition99"), 300);
333 stats.noteMetricDimensionSize(key, StringToId("metric99tion99"), 270);
334 stats.noteAnomalyDeclared(key, StringToId("alert99"));
335
336 // now the config stats should only contain the stats about the new event.
337 report = getStatsdStatsReport(stats, /* reset stats */ false);
338 ASSERT_EQ(1, report.config_stats_size());
339 const auto& configReport2 = report.config_stats(0);
340 ASSERT_EQ(1, configReport2.matcher_stats_size());
341 EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
342 EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
343
344 ASSERT_EQ(1, configReport2.condition_stats_size());
345 EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
346 EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
347
348 ASSERT_EQ(1, configReport2.metric_stats_size());
349 EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
350 EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
351
352 ASSERT_EQ(1, configReport2.alert_stats_size());
353 EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
354 EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
355 }
356
TEST(StatsdStatsTest,TestAtomLog)357 TEST(StatsdStatsTest, TestAtomLog) {
358 StatsdStats stats;
359 time_t now = time(nullptr);
360 // old event, we get it from the stats buffer. should be ignored.
361 stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, 1000, false);
362
363 stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, now + 1, false);
364 stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, now + 2, false);
365 stats.noteAtomLogged(util::APP_CRASH_OCCURRED, now + 3, false);
366
367 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
368 ASSERT_EQ(2, report.atom_stats_size());
369 bool sensorAtomGood = false;
370 bool dropboxAtomGood = false;
371
372 for (const auto& atomStats : report.atom_stats()) {
373 if (atomStats.tag() == util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
374 sensorAtomGood = true;
375 }
376 if (atomStats.tag() == util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
377 dropboxAtomGood = true;
378 }
379 EXPECT_FALSE(atomStats.has_dropped_count());
380 EXPECT_FALSE(atomStats.has_skip_count());
381 }
382
383 EXPECT_TRUE(dropboxAtomGood);
384 EXPECT_TRUE(sensorAtomGood);
385 }
386
TEST(StatsdStatsTest,TestNonPlatformAtomLog)387 TEST(StatsdStatsTest, TestNonPlatformAtomLog) {
388 StatsdStats stats;
389 time_t now = time(nullptr);
390 int newAtom1 = StatsdStats::kMaxPushedAtomId + 1;
391 int newAtom2 = StatsdStats::kMaxPushedAtomId + 2;
392
393 stats.noteAtomLogged(newAtom1, now + 1, false);
394 stats.noteAtomLogged(newAtom1, now + 2, false);
395 stats.noteAtomLogged(newAtom2, now + 3, false);
396
397 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
398 ASSERT_EQ(2, report.atom_stats_size());
399 bool newAtom1Good = false;
400 bool newAtom2Good = false;
401
402 for (const auto& atomStats : report.atom_stats()) {
403 if (atomStats.tag() == newAtom1 && atomStats.count() == 2) {
404 newAtom1Good = true;
405 }
406 if (atomStats.tag() == newAtom2 && atomStats.count() == 1) {
407 newAtom2Good = true;
408 }
409 EXPECT_FALSE(atomStats.has_dropped_count());
410 EXPECT_FALSE(atomStats.has_skip_count());
411 }
412
413 EXPECT_TRUE(newAtom1Good);
414 EXPECT_TRUE(newAtom2Good);
415 }
416
TEST(StatsdStatsTest,TestPullAtomStats)417 TEST(StatsdStatsTest, TestPullAtomStats) {
418 StatsdStats stats;
419
420 stats.updateMinPullIntervalSec(util::DISK_SPACE, 3333L);
421 stats.updateMinPullIntervalSec(util::DISK_SPACE, 2222L);
422 stats.updateMinPullIntervalSec(util::DISK_SPACE, 4444L);
423
424 stats.notePull(util::DISK_SPACE);
425 stats.notePullTime(util::DISK_SPACE, 1111L);
426 stats.notePullDelay(util::DISK_SPACE, 1111L);
427 stats.notePull(util::DISK_SPACE);
428 stats.notePullTime(util::DISK_SPACE, 3333L);
429 stats.notePullDelay(util::DISK_SPACE, 3335L);
430 stats.notePull(util::DISK_SPACE);
431 stats.notePullFromCache(util::DISK_SPACE);
432 stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
433 stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, false);
434 stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
435 stats.notePullBinderCallFailed(util::DISK_SPACE);
436 stats.notePullUidProviderNotFound(util::DISK_SPACE);
437 stats.notePullerNotFound(util::DISK_SPACE);
438 stats.notePullerNotFound(util::DISK_SPACE);
439 stats.notePullTimeout(util::DISK_SPACE, 3000L, 6000L);
440 stats.notePullTimeout(util::DISK_SPACE, 4000L, 7000L);
441
442 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
443 ASSERT_EQ(1, report.pulled_atom_stats_size());
444
445 EXPECT_EQ(util::DISK_SPACE, report.pulled_atom_stats(0).atom_id());
446 EXPECT_EQ(3, report.pulled_atom_stats(0).total_pull());
447 EXPECT_EQ(1, report.pulled_atom_stats(0).total_pull_from_cache());
448 EXPECT_EQ(2222L, report.pulled_atom_stats(0).min_pull_interval_sec());
449 EXPECT_EQ(2222L, report.pulled_atom_stats(0).average_pull_time_nanos());
450 EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos());
451 EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos());
452 EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
453 EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
454 EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
455 EXPECT_EQ(1L, report.pulled_atom_stats(0).binder_call_failed());
456 EXPECT_EQ(1L, report.pulled_atom_stats(0).failed_uid_provider_not_found());
457 EXPECT_EQ(2L, report.pulled_atom_stats(0).puller_not_found());
458 ASSERT_EQ(2, report.pulled_atom_stats(0).pull_atom_metadata_size());
459 EXPECT_EQ(3000L, report.pulled_atom_stats(0).pull_atom_metadata(0).pull_timeout_uptime_millis());
460 EXPECT_EQ(4000L, report.pulled_atom_stats(0).pull_atom_metadata(1).pull_timeout_uptime_millis());
461 EXPECT_EQ(6000L, report.pulled_atom_stats(0).pull_atom_metadata(0)
462 .pull_timeout_elapsed_millis());
463 EXPECT_EQ(7000L, report.pulled_atom_stats(0).pull_atom_metadata(1)
464 .pull_timeout_elapsed_millis());
465 }
466
TEST(StatsdStatsTest,TestAtomMetricsStats)467 TEST(StatsdStatsTest, TestAtomMetricsStats) {
468 StatsdStats stats;
469 time_t now = time(nullptr);
470 // old event, we get it from the stats buffer. should be ignored.
471 stats.noteBucketDropped(10000000000LL);
472
473 stats.noteBucketBoundaryDelayNs(10000000000LL, -1L);
474 stats.noteBucketBoundaryDelayNs(10000000000LL, -10L);
475 stats.noteBucketBoundaryDelayNs(10000000000LL, 2L);
476
477 stats.noteBucketBoundaryDelayNs(10000000001LL, 1L);
478
479 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
480 ASSERT_EQ(2, report.atom_metric_stats().size());
481
482 auto atomStats = report.atom_metric_stats(0);
483 EXPECT_EQ(10000000000LL, atomStats.metric_id());
484 EXPECT_EQ(1L, atomStats.bucket_dropped());
485 EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns());
486 EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns());
487
488 auto atomStats2 = report.atom_metric_stats(1);
489 EXPECT_EQ(10000000001LL, atomStats2.metric_id());
490 EXPECT_EQ(0L, atomStats2.bucket_dropped());
491 EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns());
492 EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns());
493 }
494
TEST(StatsdStatsTest,TestRestrictedMetricsStats)495 TEST(StatsdStatsTest, TestRestrictedMetricsStats) {
496 StatsdStats stats;
497 const int64_t metricId = -1234556L;
498 ConfigKey key(0, 12345);
499 stats.noteConfigReceived(key, 2, 3, 4, 5, {}, nullopt);
500 stats.noteRestrictedMetricInsertError(key, metricId);
501 stats.noteRestrictedMetricTableCreationError(key, metricId);
502 stats.noteRestrictedMetricTableDeletionError(key, metricId);
503 stats.noteDeviceInfoTableCreationFailed(key);
504 stats.noteRestrictedMetricFlushLatency(key, metricId, 3000);
505 stats.noteRestrictedMetricFlushLatency(key, metricId, 3001);
506 stats.noteRestrictedMetricCategoryChanged(key, metricId);
507 stats.noteRestrictedConfigFlushLatency(key, 4000);
508 ConfigKey configKeyWithoutError(0, 666);
509 stats.noteConfigReceived(configKeyWithoutError, 2, 3, 4, 5, {}, nullopt);
510 stats.noteDbCorrupted(key);
511 stats.noteDbCorrupted(key);
512 stats.noteDbSizeExceeded(key);
513 stats.noteDbStatFailed(key);
514 stats.noteDbConfigInvalid(key);
515 stats.noteDbTooOld(key);
516 stats.noteDbDeletionConfigRemoved(key);
517 stats.noteDbDeletionConfigUpdated(key);
518 stats.noteRestrictedConfigDbSize(key, 999, 111);
519
520 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
521 ASSERT_EQ(2, report.config_stats().size());
522 ASSERT_EQ(0, report.config_stats(0).restricted_metric_stats().size());
523 ASSERT_EQ(1, report.config_stats(1).restricted_metric_stats().size());
524 EXPECT_EQ(1, report.config_stats(1).restricted_metric_stats(0).insert_error());
525 EXPECT_EQ(1, report.config_stats(1).restricted_metric_stats(0).table_creation_error());
526 EXPECT_EQ(1, report.config_stats(1).restricted_metric_stats(0).table_deletion_error());
527 EXPECT_EQ(1, report.config_stats(1).restricted_metric_stats(0).category_changed_count());
528 ASSERT_EQ(2, report.config_stats(1).restricted_metric_stats(0).flush_latency_ns().size());
529 EXPECT_EQ(3000, report.config_stats(1).restricted_metric_stats(0).flush_latency_ns(0));
530 EXPECT_EQ(3001, report.config_stats(1).restricted_metric_stats(0).flush_latency_ns(1));
531 ASSERT_EQ(1, report.config_stats(1).restricted_db_size_time_sec().size());
532 EXPECT_EQ(999, report.config_stats(1).restricted_db_size_time_sec(0));
533 ASSERT_EQ(1, report.config_stats(1).restricted_db_size_bytes().size());
534 EXPECT_EQ(111, report.config_stats(1).restricted_db_size_bytes(0));
535 ASSERT_EQ(1, report.config_stats(1).restricted_flush_latency().size());
536 EXPECT_EQ(4000, report.config_stats(1).restricted_flush_latency(0));
537 EXPECT_TRUE(report.config_stats(1).device_info_table_creation_failed());
538 EXPECT_EQ(metricId, report.config_stats(1).restricted_metric_stats(0).restricted_metric_id());
539 EXPECT_EQ(2, report.config_stats(1).restricted_db_corrupted_count());
540 EXPECT_EQ(1, report.config_stats(1).db_deletion_stat_failed());
541 EXPECT_EQ(1, report.config_stats(1).db_deletion_size_exceeded_limit());
542 EXPECT_EQ(1, report.config_stats(1).db_deletion_config_invalid());
543 EXPECT_EQ(1, report.config_stats(1).db_deletion_too_old());
544 EXPECT_EQ(1, report.config_stats(1).db_deletion_config_removed());
545 EXPECT_EQ(1, report.config_stats(1).db_deletion_config_updated());
546 }
547
TEST(StatsdStatsTest,TestRestrictedMetricsQueryStats)548 TEST(StatsdStatsTest, TestRestrictedMetricsQueryStats) {
549 StatsdStats stats;
550 const int32_t callingUid = 100;
551 ConfigKey configKey(0, 12345);
552 const string configPackage = "com.google.android.gm";
553 int64_t beforeNoteMetricSucceed = getWallClockNs();
554 stats.noteQueryRestrictedMetricSucceed(configKey.GetId(), configPackage, configKey.GetUid(),
555 callingUid, /*queryLatencyNs=*/5 * NS_PER_SEC);
556 int64_t afterNoteMetricSucceed = getWallClockNs();
557
558 const int64_t configIdWithError = 111;
559 stats.noteQueryRestrictedMetricFailed(configIdWithError, configPackage, std::nullopt,
560 callingUid, InvalidQueryReason(AMBIGUOUS_CONFIG_KEY));
561 stats.noteQueryRestrictedMetricFailed(configIdWithError, configPackage, std::nullopt,
562 callingUid, InvalidQueryReason(AMBIGUOUS_CONFIG_KEY),
563 "error_message");
564
565 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
566 ASSERT_EQ(3, report.restricted_metric_query_stats().size());
567 EXPECT_EQ(configKey.GetId(), report.restricted_metric_query_stats(0).config_id());
568 EXPECT_EQ(configKey.GetUid(), report.restricted_metric_query_stats(0).config_uid());
569 EXPECT_EQ(callingUid, report.restricted_metric_query_stats(0).calling_uid());
570 EXPECT_EQ(configPackage, report.restricted_metric_query_stats(0).config_package());
571 EXPECT_FALSE(report.restricted_metric_query_stats(0).has_query_error());
572 EXPECT_LT(beforeNoteMetricSucceed,
573 report.restricted_metric_query_stats(0).query_wall_time_ns());
574 EXPECT_GT(afterNoteMetricSucceed, report.restricted_metric_query_stats(0).query_wall_time_ns());
575 EXPECT_EQ(5 * NS_PER_SEC, report.restricted_metric_query_stats(0).query_latency_ns());
576 EXPECT_EQ(configIdWithError, report.restricted_metric_query_stats(1).config_id());
577 EXPECT_EQ(AMBIGUOUS_CONFIG_KEY, report.restricted_metric_query_stats(1).invalid_query_reason());
578 EXPECT_EQ(false, report.restricted_metric_query_stats(1).has_config_uid());
579 EXPECT_FALSE(report.restricted_metric_query_stats(1).has_query_error());
580 EXPECT_FALSE(report.restricted_metric_query_stats(1).has_query_latency_ns());
581 EXPECT_EQ("error_message", report.restricted_metric_query_stats(2).query_error());
582 EXPECT_FALSE(report.restricted_metric_query_stats(2).has_query_latency_ns());
583 EXPECT_NE(report.restricted_metric_query_stats(1).query_wall_time_ns(),
584 report.restricted_metric_query_stats(0).query_wall_time_ns());
585 }
586
TEST(StatsdStatsTest,TestAnomalyMonitor)587 TEST(StatsdStatsTest, TestAnomalyMonitor) {
588 StatsdStats stats;
589 stats.noteRegisteredAnomalyAlarmChanged();
590 stats.noteRegisteredAnomalyAlarmChanged();
591
592 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
593 EXPECT_EQ(2, report.anomaly_alarm_stats().alarms_registered());
594 }
595
TEST(StatsdStatsTest,TestTimestampThreshold)596 TEST(StatsdStatsTest, TestTimestampThreshold) {
597 StatsdStats stats;
598 vector<int32_t> timestamps;
599 for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
600 timestamps.push_back(i);
601 }
602 ConfigKey key(0, 12345);
603 stats.noteConfigReceived(key, 2, 3, 4, 5, {}, nullopt);
604
605 for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
606 stats.noteDataDropped(key, timestamps[i]);
607 stats.noteBroadcastSent(key, timestamps[i]);
608 stats.noteMetricsReportSent(key, 0, timestamps[i], i + 1);
609 stats.noteActiveStatusChanged(key, true, timestamps[i]);
610 stats.noteActiveStatusChanged(key, false, timestamps[i]);
611 }
612
613 int32_t newTimestamp = 10000;
614
615 // now it should trigger removing oldest timestamp
616 stats.noteDataDropped(key, 123, 10000);
617 stats.noteBroadcastSent(key, 10000);
618 stats.noteMetricsReportSent(key, 0, 10000, 21);
619 stats.noteActiveStatusChanged(key, true, 10000);
620 stats.noteActiveStatusChanged(key, false, 10000);
621
622 EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
623 const auto& configStats = stats.mConfigStats[key];
624
625 size_t maxCount = StatsdStats::kMaxTimestampCount;
626 ASSERT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
627 ASSERT_EQ(maxCount, configStats->data_drop_time_sec.size());
628 ASSERT_EQ(maxCount, configStats->dump_report_stats.size());
629 ASSERT_EQ(maxCount, configStats->activation_time_sec.size());
630 ASSERT_EQ(maxCount, configStats->deactivation_time_sec.size());
631
632 // the oldest timestamp is the second timestamp in history
633 EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
634 EXPECT_EQ(1, configStats->data_drop_bytes.front());
635 EXPECT_EQ(1, configStats->dump_report_stats.front().mDumpReportTimeSec);
636 EXPECT_EQ(1, configStats->activation_time_sec.front());
637 EXPECT_EQ(1, configStats->deactivation_time_sec.front());
638
639 // the last timestamp is the newest timestamp.
640 EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
641 EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
642 EXPECT_EQ(123, configStats->data_drop_bytes.back());
643 EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().mDumpReportTimeSec);
644 EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
645 EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
646 }
647
TEST(StatsdStatsTest,TestSystemServerCrash)648 TEST(StatsdStatsTest, TestSystemServerCrash) {
649 StatsdStats stats;
650 vector<int32_t> timestamps;
651 for (int i = 0; i < StatsdStats::kMaxSystemServerRestarts; i++) {
652 timestamps.push_back(i);
653 stats.noteSystemServerRestart(timestamps[i]);
654 }
655
656 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
657 const int maxCount = StatsdStats::kMaxSystemServerRestarts;
658 ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
659
660 stats.noteSystemServerRestart(StatsdStats::kMaxSystemServerRestarts + 1);
661
662 report = getStatsdStatsReport(stats, /* reset stats */ false);
663 ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
664 EXPECT_EQ(StatsdStats::kMaxSystemServerRestarts + 1, report.system_restart_sec(maxCount - 1));
665 }
666
TEST(StatsdStatsTest,TestActivationBroadcastGuardrailHit)667 TEST(StatsdStatsTest, TestActivationBroadcastGuardrailHit) {
668 StatsdStats stats;
669 int uid1 = 1;
670 int uid2 = 2;
671 stats.noteActivationBroadcastGuardrailHit(uid1, 10);
672 stats.noteActivationBroadcastGuardrailHit(uid1, 20);
673
674 // Test that we only keep 20 timestamps.
675 for (int i = 0; i < 100; i++) {
676 stats.noteActivationBroadcastGuardrailHit(uid2, i);
677 }
678
679 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
680 ASSERT_EQ(2, report.activation_guardrail_stats_size());
681 bool uid1Good = false;
682 bool uid2Good = false;
683 for (const auto& guardrailTimes : report.activation_guardrail_stats()) {
684 if (uid1 == guardrailTimes.uid()) {
685 uid1Good = true;
686 ASSERT_EQ(2, guardrailTimes.guardrail_met_sec_size());
687 EXPECT_EQ(10, guardrailTimes.guardrail_met_sec(0));
688 EXPECT_EQ(20, guardrailTimes.guardrail_met_sec(1));
689 } else if (uid2 == guardrailTimes.uid()) {
690 int maxCount = StatsdStats::kMaxTimestampCount;
691 uid2Good = true;
692 ASSERT_EQ(maxCount, guardrailTimes.guardrail_met_sec_size());
693 for (int i = 0; i < maxCount; i++) {
694 EXPECT_EQ(100 - maxCount + i, guardrailTimes.guardrail_met_sec(i));
695 }
696 } else {
697 FAIL() << "Unexpected uid.";
698 }
699 }
700 EXPECT_TRUE(uid1Good);
701 EXPECT_TRUE(uid2Good);
702 }
703
TEST(StatsdStatsTest,TestAtomErrorStats)704 TEST(StatsdStatsTest, TestAtomErrorStats) {
705 StatsdStats stats;
706
707 int pushAtomTag = 100;
708 int pullAtomTag = 1000;
709 int numErrors = 10;
710
711 for (int i = 0; i < numErrors; i++) {
712 // We must call noteAtomLogged as well because only those pushed atoms
713 // that have been logged will have stats printed about them in the
714 // proto.
715 stats.noteAtomLogged(pushAtomTag, /*timeSec=*/0, false);
716 stats.noteAtomError(pushAtomTag, /*pull=*/false);
717
718 stats.noteAtomError(pullAtomTag, /*pull=*/true);
719 }
720
721 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
722
723 // Check error count = numErrors for push atom
724 ASSERT_EQ(1, report.atom_stats_size());
725 const auto& pushedAtomStats = report.atom_stats(0);
726 EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
727 EXPECT_EQ(numErrors, pushedAtomStats.error_count());
728 EXPECT_FALSE(pushedAtomStats.has_dropped_count());
729 EXPECT_FALSE(pushedAtomStats.has_skip_count());
730
731 // Check error count = numErrors for pull atom
732 ASSERT_EQ(1, report.pulled_atom_stats_size());
733 const auto& pulledAtomStats = report.pulled_atom_stats(0);
734 EXPECT_EQ(pullAtomTag, pulledAtomStats.atom_id());
735 EXPECT_EQ(numErrors, pulledAtomStats.atom_error_count());
736 }
737
TEST(StatsdStatsTest,TestAtomDroppedStats)738 TEST(StatsdStatsTest, TestAtomDroppedStats) {
739 StatsdStats stats;
740
741 const int pushAtomTag = 100;
742 const int nonPlatformPushAtomTag = StatsdStats::kMaxPushedAtomId + 100;
743
744 const int numDropped = 10;
745 for (int i = 0; i < numDropped; i++) {
746 stats.noteAtomLogged(pushAtomTag, /*timeSec*/ 0, /*isSkipped*/ false);
747 stats.noteEventQueueOverflow(/*oldestEventTimestampNs*/ 0, pushAtomTag);
748 stats.noteAtomLogged(nonPlatformPushAtomTag, /*timeSec*/ 0, /*isSkipped*/ false);
749 stats.noteEventQueueOverflow(/*oldestEventTimestampNs*/ 0, nonPlatformPushAtomTag);
750 }
751
752 ASSERT_EQ(2, stats.mPushedAtomDropsStats.size());
753
754 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ true);
755
756 ASSERT_EQ(0, stats.mPushedAtomDropsStats.size());
757
758 // Check dropped_count = numDropped for push atoms
759 ASSERT_EQ(2, report.atom_stats_size());
760
761 const auto& pushedAtomStats = report.atom_stats(0);
762 EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
763 EXPECT_EQ(numDropped, pushedAtomStats.count());
764 EXPECT_EQ(numDropped, pushedAtomStats.dropped_count());
765 EXPECT_FALSE(pushedAtomStats.has_error_count());
766 EXPECT_FALSE(pushedAtomStats.has_skip_count());
767
768 const auto& nonPlatformPushedAtomStats = report.atom_stats(1);
769 EXPECT_EQ(nonPlatformPushAtomTag, nonPlatformPushedAtomStats.tag());
770 EXPECT_EQ(numDropped, nonPlatformPushedAtomStats.count());
771 EXPECT_EQ(numDropped, nonPlatformPushedAtomStats.dropped_count());
772 EXPECT_FALSE(nonPlatformPushedAtomStats.has_error_count());
773 EXPECT_FALSE(nonPlatformPushedAtomStats.has_skip_count());
774 }
775
TEST(StatsdStatsTest,TestQueueStats)776 TEST(StatsdStatsTest, TestQueueStats) {
777 StatsdStats stats;
778
779 stats.noteEventQueueSize(100, 1000);
780 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ true);
781
782 ASSERT_EQ(100, report.event_queue_stats().max_size_observed());
783 ASSERT_EQ(1000, report.event_queue_stats().max_size_observed_elapsed_nanos());
784 }
785
TEST(StatsdStatsTest,TestAtomLoggedAndDroppedStats)786 TEST(StatsdStatsTest, TestAtomLoggedAndDroppedStats) {
787 StatsdStats stats;
788
789 const int pushAtomTag = 100;
790 const int nonPlatformPushAtomTag = StatsdStats::kMaxPushedAtomId + 100;
791
792 const int numLogged = 10;
793 for (int i = 0; i < numLogged; i++) {
794 stats.noteAtomLogged(pushAtomTag, /*timeSec*/ 0, false);
795 stats.noteAtomLogged(nonPlatformPushAtomTag, /*timeSec*/ 0, false);
796 }
797
798 const int numDropped = 10;
799 for (int i = 0; i < numDropped; i++) {
800 stats.noteAtomLogged(pushAtomTag, /*timeSec*/ 0, /*isSkipped*/ false);
801 stats.noteEventQueueOverflow(/*oldestEventTimestampNs*/ 0, pushAtomTag);
802 stats.noteAtomLogged(nonPlatformPushAtomTag, /*timeSec*/ 0, /*isSkipped*/ false);
803 stats.noteEventQueueOverflow(/*oldestEventTimestampNs*/ 0, nonPlatformPushAtomTag);
804 }
805
806 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
807
808 // Check dropped_count = numDropped for push atoms
809 ASSERT_EQ(2, report.atom_stats_size());
810
811 const auto& pushedAtomStats = report.atom_stats(0);
812 EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
813 EXPECT_EQ(numLogged + numDropped, pushedAtomStats.count());
814 EXPECT_EQ(numDropped, pushedAtomStats.dropped_count());
815 EXPECT_FALSE(pushedAtomStats.has_error_count());
816 EXPECT_FALSE(pushedAtomStats.has_skip_count());
817
818 const auto& nonPlatformPushedAtomStats = report.atom_stats(1);
819 EXPECT_EQ(nonPlatformPushAtomTag, nonPlatformPushedAtomStats.tag());
820 EXPECT_EQ(numLogged + numDropped, nonPlatformPushedAtomStats.count());
821 EXPECT_EQ(numDropped, nonPlatformPushedAtomStats.dropped_count());
822 EXPECT_FALSE(nonPlatformPushedAtomStats.has_error_count());
823 EXPECT_FALSE(nonPlatformPushedAtomStats.has_skip_count());
824 }
825
TEST(StatsdStatsTest,TestAtomSkippedStats)826 TEST(StatsdStatsTest, TestAtomSkippedStats) {
827 StatsdStats stats;
828
829 const int pushAtomTag = 100;
830 const int nonPlatformPushAtomTag = StatsdStats::kMaxPushedAtomId + 100;
831 const int numSkipped = 10;
832
833 for (int i = 0; i < numSkipped; i++) {
834 stats.noteAtomLogged(pushAtomTag, /*timeSec=*/0, /*isSkipped*/ true);
835 stats.noteAtomLogged(nonPlatformPushAtomTag, /*timeSec=*/0, /*isSkipped*/ true);
836 }
837
838 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
839
840 // Check skip_count = numSkipped for push atoms
841 ASSERT_EQ(2, report.atom_stats_size());
842
843 const auto& pushedAtomStats = report.atom_stats(0);
844 EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
845 EXPECT_EQ(numSkipped, pushedAtomStats.count());
846 EXPECT_EQ(numSkipped, pushedAtomStats.skip_count());
847 EXPECT_FALSE(pushedAtomStats.has_error_count());
848
849 const auto& nonPlatformPushedAtomStats = report.atom_stats(1);
850 EXPECT_EQ(nonPlatformPushAtomTag, nonPlatformPushedAtomStats.tag());
851 EXPECT_EQ(numSkipped, nonPlatformPushedAtomStats.count());
852 EXPECT_EQ(numSkipped, nonPlatformPushedAtomStats.skip_count());
853 EXPECT_FALSE(nonPlatformPushedAtomStats.has_error_count());
854 }
855
TEST(StatsdStatsTest,TestAtomLoggedAndDroppedAndSkippedStats)856 TEST(StatsdStatsTest, TestAtomLoggedAndDroppedAndSkippedStats) {
857 StatsdStats stats;
858
859 const int pushAtomTag = 100;
860 const int nonPlatformPushAtomTag = StatsdStats::kMaxPushedAtomId + 100;
861
862 const int numLogged = 10;
863 for (int i = 0; i < numLogged; i++) {
864 stats.noteAtomLogged(pushAtomTag, /*timeSec*/ 0, false);
865 stats.noteAtomLogged(nonPlatformPushAtomTag, /*timeSec*/ 0, false);
866 }
867
868 const int numDropped = 10;
869 for (int i = 0; i < numDropped; i++) {
870 stats.noteAtomLogged(pushAtomTag, /*timeSec*/ 0, /*isSkipped*/ true);
871 stats.noteEventQueueOverflow(/*oldestEventTimestampNs*/ 0, pushAtomTag);
872 stats.noteAtomLogged(nonPlatformPushAtomTag, /*timeSec*/ 0, /*isSkipped*/ true);
873 stats.noteEventQueueOverflow(/*oldestEventTimestampNs*/ 0, nonPlatformPushAtomTag);
874 }
875
876 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
877
878 // Check dropped_count = numDropped for push atoms
879 ASSERT_EQ(2, report.atom_stats_size());
880
881 const auto& pushedAtomStats = report.atom_stats(0);
882 EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
883 EXPECT_EQ(numLogged + numDropped, pushedAtomStats.count());
884 EXPECT_EQ(numDropped, pushedAtomStats.dropped_count());
885 EXPECT_EQ(numDropped, pushedAtomStats.skip_count());
886 EXPECT_FALSE(pushedAtomStats.has_error_count());
887
888 const auto& nonPlatformPushedAtomStats = report.atom_stats(1);
889 EXPECT_EQ(nonPlatformPushAtomTag, nonPlatformPushedAtomStats.tag());
890 EXPECT_EQ(numLogged + numDropped, nonPlatformPushedAtomStats.count());
891 EXPECT_EQ(numDropped, nonPlatformPushedAtomStats.dropped_count());
892 EXPECT_EQ(numDropped, nonPlatformPushedAtomStats.skip_count());
893 EXPECT_FALSE(nonPlatformPushedAtomStats.has_error_count());
894 }
895
TEST(StatsdStatsTest,TestShardOffsetProvider)896 TEST(StatsdStatsTest, TestShardOffsetProvider) {
897 StatsdStats stats;
898 ShardOffsetProvider::getInstance().setShardOffset(15);
899
900 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
901 EXPECT_EQ(report.shard_offset(), 15);
902 }
903
TEST(StatsdStatsTest,TestHasHitDimensionGuardrail)904 TEST(StatsdStatsTest, TestHasHitDimensionGuardrail) {
905 StatsdStats stats;
906 int metricId1 = 1;
907 int metricId2 = 2;
908 int metricId3 = 3;
909
910 stats.noteBucketCount(metricId2);
911 stats.noteHardDimensionLimitReached(metricId3);
912
913 // No AtomMetricStats.
914 EXPECT_FALSE(stats.hasHitDimensionGuardrail(metricId1));
915
916 // Has AtomMetricStats but hasn't hit dimension guardrail.
917 EXPECT_FALSE(stats.hasHitDimensionGuardrail(metricId2));
918
919 // Has hit dimension guardrail.
920 EXPECT_TRUE(stats.hasHitDimensionGuardrail(metricId3));
921 }
922
TEST(StatsdStatsTest,TestSubscriptionStarted)923 TEST(StatsdStatsTest, TestSubscriptionStarted) {
924 StatsdStats stats;
925
926 stats.noteSubscriptionStarted(/* id */ 1, /* pushedCount */ 3, /* pulledCount */ 1);
927
928 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
929
930 auto subscriptionStats = report.subscription_stats();
931 EXPECT_EQ(subscriptionStats.pull_thread_wakeup_count(), 0);
932 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), 1);
933 auto perSubscriptionStats = subscriptionStats.per_subscription_stats(0);
934 EXPECT_EQ(perSubscriptionStats.pushed_atom_count(), 3);
935 EXPECT_EQ(perSubscriptionStats.pulled_atom_count(), 1);
936 EXPECT_GT(perSubscriptionStats.start_time_sec(), 0);
937 EXPECT_FALSE(perSubscriptionStats.has_end_time_sec());
938 EXPECT_EQ(perSubscriptionStats.flush_count(), 0);
939 }
940
TEST(StatsdStatsTest,TestSubscriptionFlushed)941 TEST(StatsdStatsTest, TestSubscriptionFlushed) {
942 StatsdStats stats;
943
944 stats.noteSubscriptionStarted(/* id */ 1, /* pushedCount */ 3, /* pulledCount */ 1);
945 stats.noteSubscriptionFlushed(/* id */ 1);
946
947 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
948
949 auto subscriptionStats = report.subscription_stats();
950 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), 1);
951 auto perSubscriptionStats = subscriptionStats.per_subscription_stats(0);
952 EXPECT_EQ(perSubscriptionStats.flush_count(), 1);
953 }
954
TEST(StatsdStatsTest,TestSubscriptionEnded)955 TEST(StatsdStatsTest, TestSubscriptionEnded) {
956 StatsdStats stats;
957
958 stats.noteSubscriptionStarted(/* id */ 1, /* pushedCount */ 3, /* pulledCount */ 1);
959 stats.noteSubscriptionEnded(/* id */ 1);
960
961 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
962
963 auto subscriptionStats = report.subscription_stats();
964 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), 1);
965 EXPECT_GT(subscriptionStats.per_subscription_stats(0).end_time_sec(), 0);
966 }
967
TEST(StatsdStatsTest,TestSubscriptionAtomPulled)968 TEST(StatsdStatsTest, TestSubscriptionAtomPulled) {
969 StatsdStats stats;
970
971 stats.noteSubscriptionAtomPulled(/* atomId */ 10'001);
972
973 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
974
975 ASSERT_EQ(report.pulled_atom_stats_size(), 1);
976 auto pulledAtomStats = report.pulled_atom_stats(0);
977 EXPECT_EQ(pulledAtomStats.subscription_pull_count(), 1);
978 }
979
TEST(StatsdStatsTest,TestSubscriptionPullThreadWakeup)980 TEST(StatsdStatsTest, TestSubscriptionPullThreadWakeup) {
981 StatsdStats stats;
982
983 stats.noteSubscriptionPullThreadWakeup();
984
985 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
986
987 auto subscriptionStats = report.subscription_stats();
988 EXPECT_EQ(subscriptionStats.pull_thread_wakeup_count(), 1);
989 }
990
TEST(StatsdStatsTest,TestSubscriptionStartedMaxActiveSubscriptions)991 TEST(StatsdStatsTest, TestSubscriptionStartedMaxActiveSubscriptions) {
992 StatsdStats stats;
993
994 const int maxSubs = ShellSubscriber::getMaxSubscriptions();
995
996 // Start more than max # of allowed subscriptions.
997 // maxSub + 1th subscriptions should not have been added.
998 for (int id = 1; id <= maxSubs + 1; id++) {
999 stats.noteSubscriptionStarted(id, /* pushedCount */ 3, /* pulledCount */ 1);
1000 }
1001
1002 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1003
1004 auto subscriptionStats = report.subscription_stats();
1005 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), maxSubs);
1006 EXPECT_THAT(subscriptionStats.per_subscription_stats(),
1007 Not(Contains(Property(&PerSubscriptionStats::id, Eq(maxSubs + 1)))));
1008 }
1009
TEST(StatsdStatsTest,TestSubscriptionStartedRemoveFinishedSubscription)1010 TEST(StatsdStatsTest, TestSubscriptionStartedRemoveFinishedSubscription) {
1011 StatsdStats stats;
1012
1013 const int maxSubs = ShellSubscriber::getMaxSubscriptions();
1014
1015 // Start max # of allowed subscriptions
1016 for (int id = 1; id <= maxSubs; id++) {
1017 stats.noteSubscriptionStarted(id, /* pushedCount */ 3, /* pulledCount */ 1);
1018 }
1019
1020 // End subscription with id 5.
1021 stats.noteSubscriptionEnded(/* id */ 5);
1022
1023 // Add one more subscription after we've added max # of subscriptions.
1024 // Subscription wth id 5 should be removed and the new subscription added here should be
1025 // accepted.
1026 stats.noteSubscriptionStarted(maxSubs + 1, /* pushedCount */ 3, /* pulledCount */ 1);
1027
1028 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1029
1030 auto subscriptionStats = report.subscription_stats();
1031 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), maxSubs);
1032 EXPECT_THAT(subscriptionStats.per_subscription_stats(),
1033 Not(Contains(Property(&PerSubscriptionStats::id, Eq(5)))));
1034 EXPECT_THAT(subscriptionStats.per_subscription_stats(),
1035 Contains(Property(&PerSubscriptionStats::id, Eq(maxSubs + 1))));
1036 }
1037
TEST(StatsdStatsTest,TestEnforceDimensionKeySizeLimit)1038 TEST(StatsdStatsTest, TestEnforceDimensionKeySizeLimit) {
1039 EXPECT_EQ(StatsdStats::clampDimensionKeySizeLimit(-1),
1040 StatsdStats::kDimensionKeySizeHardLimitMin);
1041 EXPECT_EQ(StatsdStats::clampDimensionKeySizeLimit(0),
1042 StatsdStats::kDimensionKeySizeHardLimitMin);
1043 EXPECT_EQ(StatsdStats::clampDimensionKeySizeLimit(500),
1044 StatsdStats::kDimensionKeySizeHardLimitMin);
1045 EXPECT_EQ(StatsdStats::clampDimensionKeySizeLimit(1000), 1000);
1046 EXPECT_EQ(StatsdStats::clampDimensionKeySizeLimit(3500),
1047 StatsdStats::kDimensionKeySizeHardLimitMax);
1048 }
1049
TEST(StatsdStatsTest,TestSocketLossStats)1050 TEST(StatsdStatsTest, TestSocketLossStats) {
1051 StatsdStats stats;
1052
1053 const int maxLossEvents = StatsdStats::kMaxSocketLossStatsSize;
1054
1055 // Note maxLossEvents + 1
1056 for (int eventId = 0; eventId <= maxLossEvents; eventId++) {
1057 SocketLossInfo info;
1058
1059 info.uid = eventId;
1060 info.firstLossTsNanos = 10 * eventId;
1061 info.lastLossTsNanos = 10 * eventId + 1;
1062
1063 info.atomIds.push_back(eventId * 10);
1064 info.errors.push_back(eventId * 20);
1065 info.counts.push_back(eventId * 30);
1066
1067 stats.noteAtomSocketLoss(info);
1068 }
1069
1070 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1071
1072 auto socketLossStats = report.socket_loss_stats();
1073 ASSERT_EQ(socketLossStats.loss_stats_per_uid().size(), maxLossEvents);
1074
1075 for (int i = 0; i < socketLossStats.loss_stats_per_uid().size(); i++) {
1076 const auto& info = report.socket_loss_stats().loss_stats_per_uid(i);
1077
1078 // due to the very first one with id 0 is popped out from the list ids (index) start from 1
1079 const int index = i + 1;
1080
1081 ASSERT_EQ(info.uid(), index);
1082 ASSERT_EQ(info.first_timestamp_nanos(), 10 * index);
1083 ASSERT_EQ(info.last_timestamp_nanos(), 10 * index + 1);
1084
1085 ASSERT_EQ(info.atom_id_loss_stats().size(), 1);
1086
1087 ASSERT_EQ(info.atom_id_loss_stats(0).atom_id(), index * 10);
1088 ASSERT_EQ(info.atom_id_loss_stats(0).error(), index * 20);
1089 ASSERT_EQ(info.atom_id_loss_stats(0).count(), index * 30);
1090 }
1091 }
1092
TEST(StatsdStatsTest,TestSocketLossStatsOverflowCounter)1093 TEST(StatsdStatsTest, TestSocketLossStatsOverflowCounter) {
1094 StatsdStats stats;
1095
1096 const int uidsCount = 5;
1097 const int lossEventCount = 5;
1098
1099 for (int uid = 0; uid < uidsCount; uid++) {
1100 for (int eventId = 0; eventId < lossEventCount; eventId++) {
1101 SocketLossInfo info;
1102
1103 info.uid = uid;
1104 info.firstLossTsNanos = 10 * eventId;
1105 info.lastLossTsNanos = 10 * eventId + 1;
1106 // the counter value will be accumulated
1107 info.overflowCounter = 1;
1108
1109 info.atomIds.push_back(eventId * 10);
1110 info.errors.push_back(eventId * 20);
1111 info.counts.push_back(eventId * 30);
1112
1113 stats.noteAtomSocketLoss(info);
1114 }
1115 }
1116 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1117
1118 auto socketLossStatsOverflowCounters =
1119 report.socket_loss_stats().loss_stats_overflow_counters();
1120 ASSERT_EQ(socketLossStatsOverflowCounters.size(), uidsCount);
1121
1122 for (int i = 0; i < socketLossStatsOverflowCounters.size(); i++) {
1123 const auto& counters = report.socket_loss_stats().loss_stats_overflow_counters(i);
1124
1125 ASSERT_EQ(counters.uid(), i);
1126 ASSERT_EQ(counters.count(), lossEventCount);
1127 }
1128 }
1129
TEST(StatsdStatsTest,TestSocketBatchReadStats)1130 TEST(StatsdStatsTest, TestSocketBatchReadStats) {
1131 unordered_map<int32_t, int32_t> empty;
1132 unordered_map<int32_t, int32_t> m1199 = {{1, 1}, {2, 1190}, {3, 8}}; // only 2 should show up
1133 unordered_map<int32_t, int32_t> m1200 = {{1, 1}, {2, 4}, {3, 8}}; // none should show up
1134 unordered_map<int32_t, int32_t> m120000 = {{1, 1000}, {2, 2000}, {3, 800}}; // all show up
1135 StatsdStats stats;
1136 stats.noteBatchSocketRead(1, 0, 0, 0, 0, empty); // bin 1
1137 stats.noteBatchSocketRead(2, 0, 0, 0, 0, empty); // bin 2
1138 stats.noteBatchSocketRead(2, 0, 0, 0, 0, empty); // bin 2
1139 stats.noteBatchSocketRead(4, 0, 0, 0, 0, empty); // bin 4
1140 stats.noteBatchSocketRead(5, 0, 0, 0, 0, empty); // bin 5
1141 stats.noteBatchSocketRead(9, 0, 0, 0, 0, empty); // bin 5
1142 stats.noteBatchSocketRead(9, 0, 0, 0, 0, empty); // bin 5
1143 stats.noteBatchSocketRead(10, 0, 0, 0, 0, empty); // bin 6
1144 stats.noteBatchSocketRead(19, 0, 0, 0, 0, empty); // bin 6
1145 stats.noteBatchSocketRead(30, 0, 0, 0, 0, empty); // bin 8
1146 stats.noteBatchSocketRead(32, 0, 0, 0, 0, empty); // bin 8
1147 stats.noteBatchSocketRead(39, 0, 0, 0, 0, empty); // bin 8
1148 stats.noteBatchSocketRead(90, 0, 0, 0, 0, empty); // bin 14
1149 stats.noteBatchSocketRead(99, 0, 0, 0, 0, empty); // bin 14
1150 stats.noteBatchSocketRead(100, 0, 0, 0, 0, empty); // bin 15
1151 stats.noteBatchSocketRead(100, 0, 0, 0, 0, empty); // bin 15
1152 stats.noteBatchSocketRead(199, 0, 0, 0, 0, empty); // bin 15
1153 stats.noteBatchSocketRead(200, 0, 0, 0, 0, empty); // bin 16
1154 stats.noteBatchSocketRead(299, 0, 0, 0, 0, empty); // bin 16
1155 stats.noteBatchSocketRead(999, 0, 0, 0, 0, empty); // bin 23
1156 stats.noteBatchSocketRead(1000, 0, 0, 0, 0, empty); // bin 24
1157 stats.noteBatchSocketRead(1199, 1, 2, 3, 4, m1199); // bin 24
1158 stats.noteBatchSocketRead(1200, 5, 6, 7, 8, m1200); // bin 25
1159 stats.noteBatchSocketRead(1800, 0, 0, 0, 0, empty); // bin 28
1160 stats.noteBatchSocketRead(1999, 0, 0, 0, 0, empty); // bin 28
1161 stats.noteBatchSocketRead(2000, 0, 0, 0, 0, empty); // bin 29
1162 stats.noteBatchSocketRead(120000, 10, INT64_MAX, 50, INT64_MAX, m120000); // bin 29
1163
1164 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1165 EXPECT_THAT(report.socket_read_stats().batched_read_size(),
1166 ElementsAre(0, 1, 2, 0, 1, 3, 2, 0, 3, 0, 0, 0, 0, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 1,
1167 2, 1, 0, 0, 2, 2));
1168
1169 // Check the large batch stats
1170 ASSERT_EQ(report.socket_read_stats().large_batch_read_stats_size(), 7);
1171 auto largeBatchStats = report.socket_read_stats().large_batch_read_stats(1); // 1199
1172 EXPECT_EQ(largeBatchStats.total_atoms_read(), 1199);
1173 EXPECT_EQ(largeBatchStats.last_read_time_elapsed_ns(), 1);
1174 EXPECT_EQ(largeBatchStats.curr_read_time_elapsed_ns(), 2);
1175 EXPECT_EQ(largeBatchStats.min_atom_time_elapsed_ns(), 3);
1176 EXPECT_EQ(largeBatchStats.max_atom_time_elapsed_ns(), 4);
1177 ASSERT_EQ(largeBatchStats.atom_stats_size(), 1);
1178 EXPECT_EQ(largeBatchStats.atom_stats(0).atom_id(), 2);
1179 EXPECT_EQ(largeBatchStats.atom_stats(0).count(), 1190);
1180
1181 largeBatchStats = report.socket_read_stats().large_batch_read_stats(2); // 1200
1182 EXPECT_EQ(largeBatchStats.total_atoms_read(), 1200);
1183 EXPECT_EQ(largeBatchStats.last_read_time_elapsed_ns(), 5);
1184 EXPECT_EQ(largeBatchStats.curr_read_time_elapsed_ns(), 6);
1185 EXPECT_EQ(largeBatchStats.min_atom_time_elapsed_ns(), 7);
1186 EXPECT_EQ(largeBatchStats.max_atom_time_elapsed_ns(), 8);
1187 ASSERT_EQ(largeBatchStats.atom_stats_size(), 0);
1188
1189 largeBatchStats = report.socket_read_stats().large_batch_read_stats(6); // 120000
1190 EXPECT_EQ(largeBatchStats.total_atoms_read(), 120000);
1191 EXPECT_EQ(largeBatchStats.last_read_time_elapsed_ns(), 10);
1192 EXPECT_EQ(largeBatchStats.curr_read_time_elapsed_ns(), INT64_MAX);
1193 EXPECT_EQ(largeBatchStats.min_atom_time_elapsed_ns(), 50);
1194 EXPECT_EQ(largeBatchStats.max_atom_time_elapsed_ns(), INT64_MAX);
1195 ASSERT_EQ(largeBatchStats.atom_stats_size(), 3);
1196 EXPECT_EQ(largeBatchStats.atom_stats(0).atom_id(), 3);
1197 EXPECT_EQ(largeBatchStats.atom_stats(0).count(), 800);
1198 EXPECT_EQ(largeBatchStats.atom_stats(1).atom_id(), 2);
1199 EXPECT_EQ(largeBatchStats.atom_stats(1).count(), 2000);
1200 EXPECT_EQ(largeBatchStats.atom_stats(2).atom_id(), 1);
1201 EXPECT_EQ(largeBatchStats.atom_stats(2).count(), 1000);
1202
1203 stats.reset();
1204 report = getStatsdStatsReport(stats, /* reset stats */ false);
1205 EXPECT_THAT(report.socket_read_stats().batched_read_size(),
1206 AllOf(SizeIs(StatsdStats::kNumBinsInSocketBatchReadHistogram), Each(0)));
1207 ASSERT_EQ(report.socket_read_stats().large_batch_read_stats_size(), 0);
1208 }
1209
TEST_P(StatsdStatsTest_GetAtomDimensionKeySizeLimit_InMap,TestGetAtomDimensionKeySizeLimits)1210 TEST_P(StatsdStatsTest_GetAtomDimensionKeySizeLimit_InMap, TestGetAtomDimensionKeySizeLimits) {
1211 const auto& [atomId, defaultHardLimit] = GetParam();
1212 EXPECT_EQ(StatsdStats::getAtomDimensionKeySizeLimits(atomId, defaultHardLimit),
1213 StatsdStats::kAtomDimensionKeySizeLimitMap.at(atomId));
1214 }
1215
TEST_P(StatsdStatsTest_GetAtomDimensionKeySizeLimit_NotInMap,TestGetAtomDimensionKeySizeLimits)1216 TEST_P(StatsdStatsTest_GetAtomDimensionKeySizeLimit_NotInMap, TestGetAtomDimensionKeySizeLimits) {
1217 const auto& [atomId, defaultHardLimit] = GetParam();
1218 EXPECT_EQ(
1219 StatsdStats::getAtomDimensionKeySizeLimits(atomId, defaultHardLimit),
1220 (std::pair<size_t, size_t>(StatsdStats::kDimensionKeySizeSoftLimit, defaultHardLimit)));
1221 }
1222
buildCounterStats(CounterType counter,int32_t count)1223 CounterStats buildCounterStats(CounterType counter, int32_t count) {
1224 CounterStats msg;
1225 msg.set_counter_type(counter);
1226 msg.set_count(count);
1227 return msg;
1228 }
1229
TEST(StatsdStatsTest,TestErrorStatsReport)1230 TEST(StatsdStatsTest, TestErrorStatsReport) {
1231 StatsdStats stats;
1232 stats.noteIllegalState(COUNTER_TYPE_UNKNOWN);
1233 stats.noteIllegalState(COUNTER_TYPE_UNKNOWN);
1234 stats.noteIllegalState(COUNTER_TYPE_ERROR_ATOM_FILTER_SKIPPED);
1235 stats.noteIllegalState(COUNTER_TYPE_ERROR_ATOM_FILTER_SKIPPED);
1236 auto report = getStatsdStatsReport(stats, /* reset stats */ false);
1237
1238 EXPECT_TRUE(report.has_error_stats());
1239
1240 vector<CounterStats> expectedCounterStats{
1241 buildCounterStats(COUNTER_TYPE_UNKNOWN, 2),
1242 buildCounterStats(COUNTER_TYPE_ERROR_ATOM_FILTER_SKIPPED, 2)};
1243 EXPECT_THAT(report.error_stats().counters(),
1244 UnorderedPointwise(EqCounterStats(), expectedCounterStats));
1245 }
1246
TEST(StatsdStatsTest,TestErrorStatsReportReset)1247 TEST(StatsdStatsTest, TestErrorStatsReportReset) {
1248 StatsdStats stats;
1249 stats.noteIllegalState(COUNTER_TYPE_UNKNOWN);
1250 stats.noteIllegalState(COUNTER_TYPE_UNKNOWN);
1251 stats.noteIllegalState(COUNTER_TYPE_ERROR_ATOM_FILTER_SKIPPED);
1252 stats.noteIllegalState(COUNTER_TYPE_ERROR_ATOM_FILTER_SKIPPED);
1253 auto report = getStatsdStatsReport(stats, /* reset stats */ true);
1254
1255 EXPECT_TRUE(stats.mErrorStats.empty());
1256 }
1257
buildAtomStats(int32_t atomId,int32_t count)1258 AtomStats buildAtomStats(int32_t atomId, int32_t count) {
1259 AtomStats msg;
1260 msg.set_tag(atomId);
1261 msg.set_count(count);
1262 return msg;
1263 }
1264
buildAtomStats(int32_t atomId,int32_t count,int32_t peakRate)1265 AtomStats buildAtomStats(int32_t atomId, int32_t count, int32_t peakRate) {
1266 AtomStats msg;
1267 msg.set_tag(atomId);
1268 msg.set_count(count);
1269 msg.set_peak_rate(peakRate);
1270 return msg;
1271 }
1272
TEST_WITH_FLAGS(StatsdStatsTest,TestLoggingRateReport,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (TEST_NS,enable_logging_rate_stats_collection)))1273 TEST_WITH_FLAGS(StatsdStatsTest, TestLoggingRateReport,
1274 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_NS,
1275 enable_logging_rate_stats_collection))) {
1276 StatsdStats stats;
1277
1278 const int32_t platformAtom = StatsdStats::kMaxPushedAtomId - 1;
1279 const int32_t nonPlatformAtom = StatsdStats::kMaxPushedAtomId + 1;
1280
1281 const int64_t kTimeWindow = 100'000'000; // 100ms
1282
1283 // test validates that peak logging rate reporting is preserved
1284 // across report dump & variable logging rates across time windows
1285 // example rates for 4 time windows are 1, 2, 1000, 1
1286 // expectation is 1000 should be reported as peak rate starting from third
1287 // time window
1288
1289 const int32_t samplePeakRate = 1000;
1290
1291 int64_t ts = 0;
1292
1293 stats.noteAtomLogged(platformAtom, ts, false);
1294 stats.noteAtomLogged(nonPlatformAtom, ts, false);
1295 {
1296 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1297 vector<AtomStats> expectedAtomStats{buildAtomStats(platformAtom, 1, 1),
1298 buildAtomStats(nonPlatformAtom, 1, 1)};
1299 EXPECT_THAT(report.atom_stats(), UnorderedPointwise(EqAtomStats(), expectedAtomStats));
1300 }
1301
1302 ts += kTimeWindow;
1303 stats.noteAtomLogged(platformAtom, ts, false);
1304 stats.noteAtomLogged(nonPlatformAtom, ts, false);
1305 stats.noteAtomLogged(platformAtom, ts + 1, false);
1306 stats.noteAtomLogged(nonPlatformAtom, ts + 1, false);
1307
1308 {
1309 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1310 vector<AtomStats> expectedAtomStats{buildAtomStats(platformAtom, 3, 2),
1311 buildAtomStats(nonPlatformAtom, 3, 2)};
1312 EXPECT_THAT(report.atom_stats(), UnorderedPointwise(EqAtomStats(), expectedAtomStats));
1313 }
1314
1315 ts += kTimeWindow;
1316 for (int i = 0; i < samplePeakRate; i++) {
1317 stats.noteAtomLogged(platformAtom, ts + i, false);
1318 stats.noteAtomLogged(nonPlatformAtom, ts + i, false);
1319 }
1320
1321 {
1322 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1323 vector<AtomStats> expectedAtomStats{
1324 buildAtomStats(platformAtom, 3 + samplePeakRate, samplePeakRate),
1325 buildAtomStats(nonPlatformAtom, 3 + samplePeakRate, samplePeakRate)};
1326 EXPECT_THAT(report.atom_stats(), UnorderedPointwise(EqAtomStats(), expectedAtomStats));
1327 }
1328
1329 ts += kTimeWindow;
1330 stats.noteAtomLogged(platformAtom, ts, false);
1331 stats.noteAtomLogged(nonPlatformAtom, ts, false);
1332
1333 {
1334 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1335 vector<AtomStats> expectedAtomStats{
1336 buildAtomStats(platformAtom, 4 + samplePeakRate, samplePeakRate),
1337 buildAtomStats(nonPlatformAtom, 4 + samplePeakRate, samplePeakRate)};
1338 EXPECT_THAT(report.atom_stats(), UnorderedPointwise(EqAtomStats(), expectedAtomStats));
1339 }
1340 }
1341
TEST_WITH_FLAGS(StatsdStatsTest,TestLoggingRateReportReset,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (TEST_NS,enable_logging_rate_stats_collection)))1342 TEST_WITH_FLAGS(StatsdStatsTest, TestLoggingRateReportReset,
1343 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_NS,
1344 enable_logging_rate_stats_collection))) {
1345 StatsdStats stats;
1346
1347 const int32_t platformAtom = StatsdStats::kMaxPushedAtomId - 1;
1348 const int32_t nonPlatformAtom = StatsdStats::kMaxPushedAtomId + 1;
1349
1350 int64_t ts = 0;
1351
1352 const int64_t kTimeWindow = 100'000'000; // 100ms
1353
1354 stats.noteAtomLogged(platformAtom, ts, false);
1355 stats.noteAtomLogged(nonPlatformAtom, ts, false);
1356
1357 stats.noteAtomLogged(platformAtom, ts + kTimeWindow, false);
1358 stats.noteAtomLogged(nonPlatformAtom, ts + kTimeWindow, false);
1359
1360 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ true);
1361 EXPECT_TRUE(stats.mLoggingRateStats.mRateInfo.empty());
1362 }
1363
TEST_WITH_FLAGS(StatsdStatsTest,TestLoggingRateReportOnlyTopN,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (TEST_NS,enable_logging_rate_stats_collection)))1364 TEST_WITH_FLAGS(StatsdStatsTest, TestLoggingRateReportOnlyTopN,
1365 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_NS,
1366 enable_logging_rate_stats_collection))) {
1367 StatsdStats stats;
1368
1369 const int platformAtomsToLog = 100;
1370 const int nonPlatformAtomsToLog = 100;
1371
1372 const int32_t platformAtomStartId = 2;
1373 const int32_t nonPlatformAtomStartId = StatsdStats::kMaxPushedAtomId + 1;
1374 const int32_t expectedStats = StatsdStats::kMaxLoggingRateStatsToReport;
1375
1376 int64_t ts = 0;
1377
1378 vector<AtomStats> expectedAtomStats;
1379
1380 for (int i = 0; i < platformAtomsToLog; i++) {
1381 const int loggingRateForAtom = (i + 1) * 10; // max rate = 1000
1382 const int atomId = platformAtomStartId + i;
1383 for (int j = 0; j < loggingRateForAtom; j++) {
1384 stats.noteAtomLogged(atomId, ts, false);
1385 }
1386 if (i < (platformAtomsToLog - (expectedStats / 2))) {
1387 // going to be skipped due to only top 50 frequencies are populated
1388 expectedAtomStats.push_back(buildAtomStats(atomId, loggingRateForAtom));
1389 } else {
1390 expectedAtomStats.push_back(
1391 buildAtomStats(atomId, loggingRateForAtom, loggingRateForAtom));
1392 }
1393 }
1394
1395 for (int i = 0; i < nonPlatformAtomsToLog; i++) {
1396 const int loggingRateForAtom = (i + 1) * 10; // max rate = 1000
1397 const int atomId = nonPlatformAtomStartId + i;
1398 for (int j = 0; j < loggingRateForAtom; j++) {
1399 stats.noteAtomLogged(atomId, ts, false);
1400 }
1401 if (i < (nonPlatformAtomsToLog - (expectedStats / 2))) {
1402 // going to be skipped due to only top 50 frequencies are populated
1403 expectedAtomStats.push_back(buildAtomStats(atomId, loggingRateForAtom));
1404 } else {
1405 expectedAtomStats.push_back(
1406 buildAtomStats(atomId, loggingRateForAtom, loggingRateForAtom));
1407 }
1408 }
1409
1410 StatsdStatsReport report = getStatsdStatsReport(stats, /* reset stats */ false);
1411 EXPECT_THAT(report.atom_stats(), UnorderedPointwise(EqAtomStats(), expectedAtomStats));
1412 }
1413
TEST_WITH_FLAGS(StatsdStatsTest,TestLoggingRate,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (TEST_NS,enable_logging_rate_stats_collection)))1414 TEST_WITH_FLAGS(StatsdStatsTest, TestLoggingRate,
1415 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_NS,
1416 enable_logging_rate_stats_collection))) {
1417 const int64_t kTimeWindow = 100'000'000; // 100ms
1418
1419 LoggingRate loggingRate(/*maxStatsNum*/ 1000, kTimeWindow);
1420
1421 const int platformAtomsToLog = 10;
1422 const int nonPlatformAtomsToLog = 10;
1423
1424 const int32_t platformAtomStartId = 2;
1425 const int32_t nonPlatformAtomStartId = StatsdStats::kMaxPushedAtomId + 1;
1426 const int32_t expectedStats = 20;
1427
1428 int64_t ts = 0;
1429
1430 for (int i = 0; i < platformAtomsToLog; i++) {
1431 const int loggingRateForAtom = (i + 1) * 10; // max rate = 100
1432 for (int j = 0; j < loggingRateForAtom; j++) {
1433 loggingRate.noteLogEvent(platformAtomStartId + i, ts + i);
1434 }
1435 }
1436
1437 for (int i = 0; i < nonPlatformAtomsToLog; i++) {
1438 const int loggingRateForAtom = (i + 1) * 10; // max rate = 100
1439 for (int j = 0; j < loggingRateForAtom; j++) {
1440 loggingRate.noteLogEvent(nonPlatformAtomStartId + i, ts + i);
1441 }
1442 }
1443
1444 auto result = loggingRate.getMaxRates(expectedStats);
1445 EXPECT_EQ(expectedStats, result.size());
1446
1447 // reported rates should be sorted from greatest to least
1448 for (int i = 1; i < expectedStats; i++) {
1449 EXPECT_GE(result[i - 1].second, result[i].second);
1450 }
1451
1452 EXPECT_EQ(100, result[0].second);
1453 EXPECT_EQ(100, result[1].second);
1454 }
1455
1456 } // namespace statsd
1457 } // namespace os
1458 } // namespace android
1459 #else
1460 GTEST_LOG_(INFO) << "This test does nothing.\n";
1461 #endif
1462