Home | History | Annotate | Download | only in guardrail
      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