Add logging to record whenever the 10 second guardrail for sending active configs changed broadcast is met, so that we know when the broadcast would not have been sent. Add activation time for configs that are active when the device boots. This will help determine whether or not statsd thinks configs are active and will help debug issues like b/133809948 Bug: 133809948 Test: bit statsd_test:* Test: manually rebooted to make sure activation time was logged Change-Id: Ifa72202bc52485e4953e49d78dffea685cc3d1e7
495 lines
19 KiB
C++
495 lines
19 KiB
C++
// Copyright (C) 2017 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "src/guardrail/StatsdStats.h"
|
|
#include "statslog.h"
|
|
#include "tests/statsd_test_util.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <vector>
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
namespace android {
|
|
namespace os {
|
|
namespace statsd {
|
|
|
|
using std::vector;
|
|
|
|
TEST(StatsdStatsTest, TestValidConfigAdd) {
|
|
StatsdStats stats;
|
|
ConfigKey key(0, 12345);
|
|
const int metricsCount = 10;
|
|
const int conditionsCount = 20;
|
|
const int matchersCount = 30;
|
|
const int alertsCount = 10;
|
|
stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
|
|
true /*valid config*/);
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false /*reset stats*/);
|
|
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
EXPECT_EQ(1, report.config_stats_size());
|
|
const auto& configReport = report.config_stats(0);
|
|
EXPECT_EQ(0, configReport.uid());
|
|
EXPECT_EQ(12345, configReport.id());
|
|
EXPECT_EQ(metricsCount, configReport.metric_count());
|
|
EXPECT_EQ(conditionsCount, configReport.condition_count());
|
|
EXPECT_EQ(matchersCount, configReport.matcher_count());
|
|
EXPECT_EQ(alertsCount, configReport.alert_count());
|
|
EXPECT_EQ(true, configReport.is_valid());
|
|
EXPECT_FALSE(configReport.has_deletion_time_sec());
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestInvalidConfigAdd) {
|
|
StatsdStats stats;
|
|
ConfigKey key(0, 12345);
|
|
const int metricsCount = 10;
|
|
const int conditionsCount = 20;
|
|
const int matchersCount = 30;
|
|
const int alertsCount = 10;
|
|
stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
|
|
false /*bad config*/);
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
EXPECT_EQ(1, report.config_stats_size());
|
|
const auto& configReport = report.config_stats(0);
|
|
// The invalid config should be put into icebox with a deletion time.
|
|
EXPECT_TRUE(configReport.has_deletion_time_sec());
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestConfigRemove) {
|
|
StatsdStats stats;
|
|
ConfigKey key(0, 12345);
|
|
const int metricsCount = 10;
|
|
const int conditionsCount = 20;
|
|
const int matchersCount = 30;
|
|
const int alertsCount = 10;
|
|
stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
|
|
true);
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
EXPECT_EQ(1, report.config_stats_size());
|
|
const auto& configReport = report.config_stats(0);
|
|
EXPECT_FALSE(configReport.has_deletion_time_sec());
|
|
|
|
stats.noteConfigRemoved(key);
|
|
stats.dumpStats(&output, false);
|
|
good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
EXPECT_EQ(1, report.config_stats_size());
|
|
const auto& configReport2 = report.config_stats(0);
|
|
EXPECT_TRUE(configReport2.has_deletion_time_sec());
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestSubStats) {
|
|
StatsdStats stats;
|
|
ConfigKey key(0, 12345);
|
|
stats.noteConfigReceived(key, 2, 3, 4, 5, {std::make_pair(123, 456)}, true);
|
|
|
|
stats.noteMatcherMatched(key, StringToId("matcher1"));
|
|
stats.noteMatcherMatched(key, StringToId("matcher1"));
|
|
stats.noteMatcherMatched(key, StringToId("matcher2"));
|
|
|
|
stats.noteConditionDimensionSize(key, StringToId("condition1"), 250);
|
|
stats.noteConditionDimensionSize(key, StringToId("condition1"), 240);
|
|
|
|
stats.noteMetricDimensionSize(key, StringToId("metric1"), 201);
|
|
stats.noteMetricDimensionSize(key, StringToId("metric1"), 202);
|
|
|
|
stats.noteAnomalyDeclared(key, StringToId("alert1"));
|
|
stats.noteAnomalyDeclared(key, StringToId("alert1"));
|
|
stats.noteAnomalyDeclared(key, StringToId("alert2"));
|
|
|
|
// broadcast-> 2
|
|
stats.noteBroadcastSent(key);
|
|
stats.noteBroadcastSent(key);
|
|
|
|
// data drop -> 1
|
|
stats.noteDataDropped(key, 123);
|
|
|
|
// dump report -> 3
|
|
stats.noteMetricsReportSent(key, 0);
|
|
stats.noteMetricsReportSent(key, 0);
|
|
stats.noteMetricsReportSent(key, 0);
|
|
|
|
// activation_time_sec -> 2
|
|
stats.noteActiveStatusChanged(key, true);
|
|
stats.noteActiveStatusChanged(key, true);
|
|
|
|
// deactivation_time_sec -> 1
|
|
stats.noteActiveStatusChanged(key, false);
|
|
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, true); // Dump and reset stats
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
EXPECT_EQ(1, report.config_stats_size());
|
|
const auto& configReport = report.config_stats(0);
|
|
EXPECT_EQ(2, configReport.broadcast_sent_time_sec_size());
|
|
EXPECT_EQ(1, configReport.data_drop_time_sec_size());
|
|
EXPECT_EQ(1, configReport.data_drop_bytes_size());
|
|
EXPECT_EQ(123, configReport.data_drop_bytes(0));
|
|
EXPECT_EQ(3, configReport.dump_report_time_sec_size());
|
|
EXPECT_EQ(3, configReport.dump_report_data_size_size());
|
|
EXPECT_EQ(2, configReport.activation_time_sec_size());
|
|
EXPECT_EQ(1, configReport.deactivation_time_sec_size());
|
|
EXPECT_EQ(1, configReport.annotation_size());
|
|
EXPECT_EQ(123, configReport.annotation(0).field_int64());
|
|
EXPECT_EQ(456, configReport.annotation(0).field_int32());
|
|
|
|
EXPECT_EQ(2, configReport.matcher_stats_size());
|
|
// matcher1 is the first in the list
|
|
if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
|
|
EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
|
|
EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
|
|
EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(1).id());
|
|
} else {
|
|
// matcher1 is the second in the list.
|
|
EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
|
|
EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(0).id());
|
|
|
|
EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
|
|
EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
|
|
}
|
|
|
|
EXPECT_EQ(2, configReport.alert_stats_size());
|
|
bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
|
|
EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
|
|
EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
|
|
EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
|
|
EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
|
|
|
|
EXPECT_EQ(1, configReport.condition_stats_size());
|
|
EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
|
|
EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
|
|
|
|
EXPECT_EQ(1, configReport.metric_stats_size());
|
|
EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
|
|
EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
|
|
|
|
// after resetting the stats, some new events come
|
|
stats.noteMatcherMatched(key, StringToId("matcher99"));
|
|
stats.noteConditionDimensionSize(key, StringToId("condition99"), 300);
|
|
stats.noteMetricDimensionSize(key, StringToId("metric99tion99"), 270);
|
|
stats.noteAnomalyDeclared(key, StringToId("alert99"));
|
|
|
|
// now the config stats should only contain the stats about the new event.
|
|
stats.dumpStats(&output, false);
|
|
good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
EXPECT_EQ(1, report.config_stats_size());
|
|
const auto& configReport2 = report.config_stats(0);
|
|
EXPECT_EQ(1, configReport2.matcher_stats_size());
|
|
EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
|
|
EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
|
|
|
|
EXPECT_EQ(1, configReport2.condition_stats_size());
|
|
EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
|
|
EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
|
|
|
|
EXPECT_EQ(1, configReport2.metric_stats_size());
|
|
EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
|
|
EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
|
|
|
|
EXPECT_EQ(1, configReport2.alert_stats_size());
|
|
EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
|
|
EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestAtomLog) {
|
|
StatsdStats stats;
|
|
time_t now = time(nullptr);
|
|
// old event, we get it from the stats buffer. should be ignored.
|
|
stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, 1000);
|
|
|
|
stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 1);
|
|
stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 2);
|
|
stats.noteAtomLogged(android::util::APP_CRASH_OCCURRED, now + 3);
|
|
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
|
|
EXPECT_EQ(2, report.atom_stats_size());
|
|
bool sensorAtomGood = false;
|
|
bool dropboxAtomGood = false;
|
|
|
|
for (const auto& atomStats : report.atom_stats()) {
|
|
if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
|
|
sensorAtomGood = true;
|
|
}
|
|
if (atomStats.tag() == android::util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
|
|
dropboxAtomGood = true;
|
|
}
|
|
}
|
|
|
|
EXPECT_TRUE(dropboxAtomGood);
|
|
EXPECT_TRUE(sensorAtomGood);
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestNonPlatformAtomLog) {
|
|
StatsdStats stats;
|
|
time_t now = time(nullptr);
|
|
int newAtom1 = android::util::kMaxPushedAtomId + 1;
|
|
int newAtom2 = android::util::kMaxPushedAtomId + 2;
|
|
|
|
stats.noteAtomLogged(newAtom1, now + 1);
|
|
stats.noteAtomLogged(newAtom1, now + 2);
|
|
stats.noteAtomLogged(newAtom2, now + 3);
|
|
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
|
|
EXPECT_EQ(2, report.atom_stats_size());
|
|
bool newAtom1Good = false;
|
|
bool newAtom2Good = false;
|
|
|
|
for (const auto& atomStats : report.atom_stats()) {
|
|
if (atomStats.tag() == newAtom1 && atomStats.count() == 2) {
|
|
newAtom1Good = true;
|
|
}
|
|
if (atomStats.tag() == newAtom2 && atomStats.count() == 1) {
|
|
newAtom2Good = true;
|
|
}
|
|
}
|
|
|
|
EXPECT_TRUE(newAtom1Good);
|
|
EXPECT_TRUE(newAtom2Good);
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestPullAtomStats) {
|
|
StatsdStats stats;
|
|
|
|
stats.updateMinPullIntervalSec(android::util::DISK_SPACE, 3333L);
|
|
stats.updateMinPullIntervalSec(android::util::DISK_SPACE, 2222L);
|
|
stats.updateMinPullIntervalSec(android::util::DISK_SPACE, 4444L);
|
|
|
|
stats.notePull(android::util::DISK_SPACE);
|
|
stats.notePullTime(android::util::DISK_SPACE, 1111L);
|
|
stats.notePullDelay(android::util::DISK_SPACE, 1111L);
|
|
stats.notePull(android::util::DISK_SPACE);
|
|
stats.notePullTime(android::util::DISK_SPACE, 3333L);
|
|
stats.notePullDelay(android::util::DISK_SPACE, 3335L);
|
|
stats.notePull(android::util::DISK_SPACE);
|
|
stats.notePullFromCache(android::util::DISK_SPACE);
|
|
stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true);
|
|
stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, false);
|
|
stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true);
|
|
|
|
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
|
|
EXPECT_EQ(1, report.pulled_atom_stats_size());
|
|
|
|
EXPECT_EQ(android::util::DISK_SPACE, report.pulled_atom_stats(0).atom_id());
|
|
EXPECT_EQ(3, report.pulled_atom_stats(0).total_pull());
|
|
EXPECT_EQ(1, report.pulled_atom_stats(0).total_pull_from_cache());
|
|
EXPECT_EQ(2222L, report.pulled_atom_stats(0).min_pull_interval_sec());
|
|
EXPECT_EQ(2222L, report.pulled_atom_stats(0).average_pull_time_nanos());
|
|
EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos());
|
|
EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos());
|
|
EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
|
|
EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
|
|
EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestAtomMetricsStats) {
|
|
StatsdStats stats;
|
|
time_t now = time(nullptr);
|
|
// old event, we get it from the stats buffer. should be ignored.
|
|
stats.noteBucketDropped(1000L);
|
|
|
|
stats.noteBucketBoundaryDelayNs(1000L, -1L);
|
|
stats.noteBucketBoundaryDelayNs(1000L, -10L);
|
|
stats.noteBucketBoundaryDelayNs(1000L, 2L);
|
|
|
|
stats.noteBucketBoundaryDelayNs(1001L, 1L);
|
|
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
|
|
EXPECT_EQ(2, report.atom_metric_stats().size());
|
|
|
|
auto atomStats = report.atom_metric_stats(0);
|
|
EXPECT_EQ(1000L, atomStats.metric_id());
|
|
EXPECT_EQ(1L, atomStats.bucket_dropped());
|
|
EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns());
|
|
EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns());
|
|
|
|
auto atomStats2 = report.atom_metric_stats(1);
|
|
EXPECT_EQ(1001L, atomStats2.metric_id());
|
|
EXPECT_EQ(0L, atomStats2.bucket_dropped());
|
|
EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns());
|
|
EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns());
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestAnomalyMonitor) {
|
|
StatsdStats stats;
|
|
stats.noteRegisteredAnomalyAlarmChanged();
|
|
stats.noteRegisteredAnomalyAlarmChanged();
|
|
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
StatsdStatsReport report;
|
|
bool good = report.ParseFromArray(&output[0], output.size());
|
|
EXPECT_TRUE(good);
|
|
|
|
EXPECT_EQ(2, report.anomaly_alarm_stats().alarms_registered());
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestTimestampThreshold) {
|
|
StatsdStats stats;
|
|
vector<int32_t> timestamps;
|
|
for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
|
|
timestamps.push_back(i);
|
|
}
|
|
ConfigKey key(0, 12345);
|
|
stats.noteConfigReceived(key, 2, 3, 4, 5, {}, true);
|
|
|
|
for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
|
|
stats.noteDataDropped(key, timestamps[i]);
|
|
stats.noteBroadcastSent(key, timestamps[i]);
|
|
stats.noteMetricsReportSent(key, 0, timestamps[i]);
|
|
stats.noteActiveStatusChanged(key, true, timestamps[i]);
|
|
stats.noteActiveStatusChanged(key, false, timestamps[i]);
|
|
}
|
|
|
|
int32_t newTimestamp = 10000;
|
|
|
|
// now it should trigger removing oldest timestamp
|
|
stats.noteDataDropped(key, 123, 10000);
|
|
stats.noteBroadcastSent(key, 10000);
|
|
stats.noteMetricsReportSent(key, 0, 10000);
|
|
stats.noteActiveStatusChanged(key, true, 10000);
|
|
stats.noteActiveStatusChanged(key, false, 10000);
|
|
|
|
EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
|
|
const auto& configStats = stats.mConfigStats[key];
|
|
|
|
size_t maxCount = StatsdStats::kMaxTimestampCount;
|
|
EXPECT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
|
|
EXPECT_EQ(maxCount, configStats->data_drop_time_sec.size());
|
|
EXPECT_EQ(maxCount, configStats->dump_report_stats.size());
|
|
EXPECT_EQ(maxCount, configStats->activation_time_sec.size());
|
|
EXPECT_EQ(maxCount, configStats->deactivation_time_sec.size());
|
|
|
|
// the oldest timestamp is the second timestamp in history
|
|
EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
|
|
EXPECT_EQ(1, configStats->data_drop_bytes.front());
|
|
EXPECT_EQ(1, configStats->dump_report_stats.front().first);
|
|
EXPECT_EQ(1, configStats->activation_time_sec.front());
|
|
EXPECT_EQ(1, configStats->deactivation_time_sec.front());
|
|
|
|
// the last timestamp is the newest timestamp.
|
|
EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
|
|
EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
|
|
EXPECT_EQ(123, configStats->data_drop_bytes.back());
|
|
EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
|
|
EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
|
|
EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestSystemServerCrash) {
|
|
StatsdStats stats;
|
|
vector<int32_t> timestamps;
|
|
for (int i = 0; i < StatsdStats::kMaxSystemServerRestarts; i++) {
|
|
timestamps.push_back(i);
|
|
stats.noteSystemServerRestart(timestamps[i]);
|
|
}
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
StatsdStatsReport report;
|
|
EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
|
|
const int maxCount = StatsdStats::kMaxSystemServerRestarts;
|
|
EXPECT_EQ(maxCount, (int)report.system_restart_sec_size());
|
|
|
|
stats.noteSystemServerRestart(StatsdStats::kMaxSystemServerRestarts + 1);
|
|
output.clear();
|
|
stats.dumpStats(&output, false);
|
|
EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
|
|
EXPECT_EQ(maxCount, (int)report.system_restart_sec_size());
|
|
EXPECT_EQ(StatsdStats::kMaxSystemServerRestarts + 1, report.system_restart_sec(maxCount - 1));
|
|
}
|
|
|
|
TEST(StatsdStatsTest, TestActivationBroadcastGuardrailHit) {
|
|
StatsdStats stats;
|
|
int uid1 = 1;
|
|
int uid2 = 2;
|
|
stats.noteActivationBroadcastGuardrailHit(uid1, 10);
|
|
stats.noteActivationBroadcastGuardrailHit(uid1, 20);
|
|
|
|
// Test that we only keep 20 timestamps.
|
|
for (int i = 0; i < 100; i++) {
|
|
stats.noteActivationBroadcastGuardrailHit(uid2, i);
|
|
}
|
|
|
|
vector<uint8_t> output;
|
|
stats.dumpStats(&output, false);
|
|
StatsdStatsReport report;
|
|
EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
|
|
|
|
EXPECT_EQ(2, report.activation_guardrail_stats_size());
|
|
bool uid1Good = false;
|
|
bool uid2Good = false;
|
|
for (const auto& guardrailTimes : report.activation_guardrail_stats()) {
|
|
if (uid1 == guardrailTimes.uid()) {
|
|
uid1Good = true;
|
|
EXPECT_EQ(2, guardrailTimes.guardrail_met_sec_size());
|
|
EXPECT_EQ(10, guardrailTimes.guardrail_met_sec(0));
|
|
EXPECT_EQ(20, guardrailTimes.guardrail_met_sec(1));
|
|
} else if (uid2 == guardrailTimes.uid()) {
|
|
int maxCount = StatsdStats::kMaxTimestampCount;
|
|
uid2Good = true;
|
|
EXPECT_EQ(maxCount, guardrailTimes.guardrail_met_sec_size());
|
|
for (int i = 0; i < maxCount; i++) {
|
|
EXPECT_EQ(100 - maxCount + i, guardrailTimes.guardrail_met_sec(i));
|
|
}
|
|
} else {
|
|
FAIL() << "Unexpected uid.";
|
|
}
|
|
}
|
|
EXPECT_TRUE(uid1Good);
|
|
EXPECT_TRUE(uid2Good);
|
|
}
|
|
|
|
} // namespace statsd
|
|
} // namespace os
|
|
} // namespace android
|
|
#else
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif
|