1 // Copyright (C) 2017 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/guardrail/StatsdStats.h"
16 #include "statslog.h"
17 #include "tests/statsd_test_util.h"
18
19 #include <gtest/gtest.h>
20 #include <vector>
21
22 #ifdef __ANDROID__
23
24 namespace android {
25 namespace os {
26 namespace statsd {
27
28 using std::vector;
29
TEST(StatsdStatsTest,TestValidConfigAdd)30 TEST(StatsdStatsTest, TestValidConfigAdd) {
31 StatsdStats stats;
32 ConfigKey key(0, 12345);
33 const int metricsCount = 10;
34 const int conditionsCount = 20;
35 const int matchersCount = 30;
36 const int alertsCount = 10;
37 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
38 true /*valid config*/);
39 vector<uint8_t> output;
40 stats.dumpStats(&output, false /*reset stats*/);
41
42 StatsdStatsReport report;
43 bool good = report.ParseFromArray(&output[0], output.size());
44 EXPECT_TRUE(good);
45 EXPECT_EQ(1, report.config_stats_size());
46 const auto& configReport = report.config_stats(0);
47 EXPECT_EQ(0, configReport.uid());
48 EXPECT_EQ(12345, configReport.id());
49 EXPECT_EQ(metricsCount, configReport.metric_count());
50 EXPECT_EQ(conditionsCount, configReport.condition_count());
51 EXPECT_EQ(matchersCount, configReport.matcher_count());
52 EXPECT_EQ(alertsCount, configReport.alert_count());
53 EXPECT_EQ(true, configReport.is_valid());
54 EXPECT_FALSE(configReport.has_deletion_time_sec());
55 }
56
TEST(StatsdStatsTest,TestInvalidConfigAdd)57 TEST(StatsdStatsTest, TestInvalidConfigAdd) {
58 StatsdStats stats;
59 ConfigKey key(0, 12345);
60 const int metricsCount = 10;
61 const int conditionsCount = 20;
62 const int matchersCount = 30;
63 const int alertsCount = 10;
64 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
65 false /*bad config*/);
66 vector<uint8_t> output;
67 stats.dumpStats(&output, false);
68
69 StatsdStatsReport report;
70 bool good = report.ParseFromArray(&output[0], output.size());
71 EXPECT_TRUE(good);
72 EXPECT_EQ(1, report.config_stats_size());
73 const auto& configReport = report.config_stats(0);
74 // The invalid config should be put into icebox with a deletion time.
75 EXPECT_TRUE(configReport.has_deletion_time_sec());
76 }
77
TEST(StatsdStatsTest,TestConfigRemove)78 TEST(StatsdStatsTest, TestConfigRemove) {
79 StatsdStats stats;
80 ConfigKey key(0, 12345);
81 const int metricsCount = 10;
82 const int conditionsCount = 20;
83 const int matchersCount = 30;
84 const int alertsCount = 10;
85 stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
86 true);
87 vector<uint8_t> output;
88 stats.dumpStats(&output, false);
89 StatsdStatsReport report;
90 bool good = report.ParseFromArray(&output[0], output.size());
91 EXPECT_TRUE(good);
92 EXPECT_EQ(1, report.config_stats_size());
93 const auto& configReport = report.config_stats(0);
94 EXPECT_FALSE(configReport.has_deletion_time_sec());
95
96 stats.noteConfigRemoved(key);
97 stats.dumpStats(&output, false);
98 good = report.ParseFromArray(&output[0], output.size());
99 EXPECT_TRUE(good);
100 EXPECT_EQ(1, report.config_stats_size());
101 const auto& configReport2 = report.config_stats(0);
102 EXPECT_TRUE(configReport2.has_deletion_time_sec());
103 }
104
TEST(StatsdStatsTest,TestSubStats)105 TEST(StatsdStatsTest, TestSubStats) {
106 StatsdStats stats;
107 ConfigKey key(0, 12345);
108 stats.noteConfigReceived(key, 2, 3, 4, 5, {std::make_pair(123, 456)}, true);
109
110 stats.noteMatcherMatched(key, StringToId("matcher1"));
111 stats.noteMatcherMatched(key, StringToId("matcher1"));
112 stats.noteMatcherMatched(key, StringToId("matcher2"));
113
114 stats.noteConditionDimensionSize(key, StringToId("condition1"), 250);
115 stats.noteConditionDimensionSize(key, StringToId("condition1"), 240);
116
117 stats.noteMetricDimensionSize(key, StringToId("metric1"), 201);
118 stats.noteMetricDimensionSize(key, StringToId("metric1"), 202);
119
120 stats.noteAnomalyDeclared(key, StringToId("alert1"));
121 stats.noteAnomalyDeclared(key, StringToId("alert1"));
122 stats.noteAnomalyDeclared(key, StringToId("alert2"));
123
124 // broadcast-> 2
125 stats.noteBroadcastSent(key);
126 stats.noteBroadcastSent(key);
127
128 // data drop -> 1
129 stats.noteDataDropped(key);
130
131 // dump report -> 3
132 stats.noteMetricsReportSent(key, 0);
133 stats.noteMetricsReportSent(key, 0);
134 stats.noteMetricsReportSent(key, 0);
135
136 vector<uint8_t> output;
137 stats.dumpStats(&output, true); // Dump and reset stats
138 StatsdStatsReport report;
139 bool good = report.ParseFromArray(&output[0], output.size());
140 EXPECT_TRUE(good);
141 EXPECT_EQ(1, report.config_stats_size());
142 const auto& configReport = report.config_stats(0);
143 EXPECT_EQ(2, configReport.broadcast_sent_time_sec_size());
144 EXPECT_EQ(1, configReport.data_drop_time_sec_size());
145 EXPECT_EQ(3, configReport.dump_report_time_sec_size());
146 EXPECT_EQ(3, configReport.dump_report_data_size_size());
147 EXPECT_EQ(1, configReport.annotation_size());
148 EXPECT_EQ(123, configReport.annotation(0).field_int64());
149 EXPECT_EQ(456, configReport.annotation(0).field_int32());
150
151 EXPECT_EQ(2, configReport.matcher_stats_size());
152 // matcher1 is the first in the list
153 if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
154 EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
155 EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
156 EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(1).id());
157 } else {
158 // matcher1 is the second in the list.
159 EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
160 EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(0).id());
161
162 EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
163 EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
164 }
165
166 EXPECT_EQ(2, configReport.alert_stats_size());
167 bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
168 EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
169 EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
170 EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
171 EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
172
173 EXPECT_EQ(1, configReport.condition_stats_size());
174 EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
175 EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
176
177 EXPECT_EQ(1, configReport.metric_stats_size());
178 EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
179 EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
180
181 // after resetting the stats, some new events come
182 stats.noteMatcherMatched(key, StringToId("matcher99"));
183 stats.noteConditionDimensionSize(key, StringToId("condition99"), 300);
184 stats.noteMetricDimensionSize(key, StringToId("metric99tion99"), 270);
185 stats.noteAnomalyDeclared(key, StringToId("alert99"));
186
187 // now the config stats should only contain the stats about the new event.
188 stats.dumpStats(&output, false);
189 good = report.ParseFromArray(&output[0], output.size());
190 EXPECT_TRUE(good);
191 EXPECT_EQ(1, report.config_stats_size());
192 const auto& configReport2 = report.config_stats(0);
193 EXPECT_EQ(1, configReport2.matcher_stats_size());
194 EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
195 EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
196
197 EXPECT_EQ(1, configReport2.condition_stats_size());
198 EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
199 EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
200
201 EXPECT_EQ(1, configReport2.metric_stats_size());
202 EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
203 EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
204
205 EXPECT_EQ(1, configReport2.alert_stats_size());
206 EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
207 EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
208 }
209
TEST(StatsdStatsTest,TestAtomLog)210 TEST(StatsdStatsTest, TestAtomLog) {
211 StatsdStats stats;
212 time_t now = time(nullptr);
213 // old event, we get it from the stats buffer. should be ignored.
214 stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, 1000);
215
216 stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 1);
217 stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 2);
218 stats.noteAtomLogged(android::util::APP_CRASH_OCCURRED, now + 3);
219 // pulled event, should ignore
220 stats.noteAtomLogged(android::util::WIFI_BYTES_TRANSFER, now + 4);
221
222 vector<uint8_t> output;
223 stats.dumpStats(&output, false);
224 StatsdStatsReport report;
225 bool good = report.ParseFromArray(&output[0], output.size());
226 EXPECT_TRUE(good);
227
228 EXPECT_EQ(2, report.atom_stats_size());
229 bool sensorAtomGood = false;
230 bool dropboxAtomGood = false;
231
232 for (const auto& atomStats : report.atom_stats()) {
233 if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
234 sensorAtomGood = true;
235 }
236 if (atomStats.tag() == android::util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
237 dropboxAtomGood = true;
238 }
239 }
240
241 EXPECT_TRUE(dropboxAtomGood);
242 EXPECT_TRUE(sensorAtomGood);
243 }
244
245
TEST(StatsdStatsTest,TestAnomalyMonitor)246 TEST(StatsdStatsTest, TestAnomalyMonitor) {
247 StatsdStats stats;
248 stats.noteRegisteredAnomalyAlarmChanged();
249 stats.noteRegisteredAnomalyAlarmChanged();
250
251 vector<uint8_t> output;
252 stats.dumpStats(&output, false);
253 StatsdStatsReport report;
254 bool good = report.ParseFromArray(&output[0], output.size());
255 EXPECT_TRUE(good);
256
257 EXPECT_EQ(2, report.anomaly_alarm_stats().alarms_registered());
258 }
259
TEST(StatsdStatsTest,TestTimestampThreshold)260 TEST(StatsdStatsTest, TestTimestampThreshold) {
261 StatsdStats stats;
262 vector<int32_t> timestamps;
263 for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
264 timestamps.push_back(i);
265 }
266 ConfigKey key(0, 12345);
267 stats.noteConfigReceived(key, 2, 3, 4, 5, {}, true);
268
269 for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
270 stats.noteDataDropped(key, timestamps[i]);
271 stats.noteBroadcastSent(key, timestamps[i]);
272 stats.noteMetricsReportSent(key, 0, timestamps[i]);
273 }
274
275 int32_t newTimestamp = 10000;
276
277 // now it should trigger removing oldest timestamp
278 stats.noteDataDropped(key, 10000);
279 stats.noteBroadcastSent(key, 10000);
280 stats.noteMetricsReportSent(key, 0, 10000);
281
282 EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
283 const auto& configStats = stats.mConfigStats[key];
284
285 size_t maxCount = StatsdStats::kMaxTimestampCount;
286 EXPECT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
287 EXPECT_EQ(maxCount, configStats->data_drop_time_sec.size());
288 EXPECT_EQ(maxCount, configStats->dump_report_stats.size());
289
290 // the oldest timestamp is the second timestamp in history
291 EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
292 EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
293 EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
294
295 // the last timestamp is the newest timestamp.
296 EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
297 EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
298 EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
299 }
300
TEST(StatsdStatsTest,TestSystemServerCrash)301 TEST(StatsdStatsTest, TestSystemServerCrash) {
302 StatsdStats stats;
303 vector<int32_t> timestamps;
304 for (int i = 0; i < StatsdStats::kMaxSystemServerRestarts; i++) {
305 timestamps.push_back(i);
306 stats.noteSystemServerRestart(timestamps[i]);
307 }
308 vector<uint8_t> output;
309 stats.dumpStats(&output, false);
310 StatsdStatsReport report;
311 EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
312 const int maxCount = StatsdStats::kMaxSystemServerRestarts;
313 EXPECT_EQ(maxCount, (int)report.system_restart_sec_size());
314
315 stats.noteSystemServerRestart(StatsdStats::kMaxSystemServerRestarts + 1);
316 output.clear();
317 stats.dumpStats(&output, false);
318 EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
319 EXPECT_EQ(maxCount, (int)report.system_restart_sec_size());
320 EXPECT_EQ(StatsdStats::kMaxSystemServerRestarts + 1, report.system_restart_sec(maxCount - 1));
321 }
322
323 } // namespace statsd
324 } // namespace os
325 } // namespace android
326 #else
327 GTEST_LOG_(INFO) << "This test does nothing.\n";
328 #endif
329