• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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