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 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 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 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 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 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 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 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 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