blob: 0861812584ae04cb630a56f841df728e4a55590e [file] [log] [blame]
// Copyright (C) 2020 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/metrics/parsing_utils/config_update_utils.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
#include <set>
#include <unordered_map>
#include <vector>
#include "src/condition/CombinationConditionTracker.h"
#include "src/condition/SimpleConditionTracker.h"
#include "src/matchers/CombinationAtomMatchingTracker.h"
#include "src/metrics/CountMetricProducer.h"
#include "src/metrics/DurationMetricProducer.h"
#include "src/metrics/GaugeMetricProducer.h"
#include "src/metrics/KllMetricProducer.h"
#include "src/metrics/NumericValueMetricProducer.h"
#include "src/metrics/parsing_utils/metrics_manager_util.h"
#include "src/statsd_config.pb.h"
#include "tests/statsd_test_util.h"
using namespace testing;
using android::sp;
using android::os::statsd::Predicate;
using std::map;
using std::nullopt;
using std::optional;
using std::set;
using std::unordered_map;
using std::vector;
#ifdef __ANDROID__
namespace android {
namespace os {
namespace statsd {
namespace {
const int configId = 456;
const ConfigKey key(123, configId);
const int64_t timeBaseNs = 1000 * NS_PER_SEC;
sp<UidMap> uidMap = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> periodicAlarmMonitor = new AlarmMonitor(
/*minDiffToUpdateRegisteredAlarmTimeSec=*/0,
[](const shared_ptr<IStatsCompanionService>&, int64_t) {},
[](const shared_ptr<IStatsCompanionService>&) {});
sp<ConfigMetadataProvider> configMetadataProvider;
unordered_map<int, vector<int>> allTagIdsToMatchersMap;
vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers;
unordered_map<int64_t, int> oldAtomMatchingTrackerMap;
vector<sp<ConditionTracker>> oldConditionTrackers;
unordered_map<int64_t, int> oldConditionTrackerMap;
vector<sp<MetricProducer>> oldMetricProducers;
unordered_map<int64_t, int> oldMetricProducerMap;
vector<sp<AnomalyTracker>> oldAnomalyTrackers;
unordered_map<int64_t, int> oldAlertTrackerMap;
vector<sp<AlarmTracker>> oldAlarmTrackers;
unordered_map<int, vector<int>> tmpConditionToMetricMap;
unordered_map<int, vector<int>> tmpTrackerToMetricMap;
unordered_map<int, vector<int>> tmpTrackerToConditionMap;
unordered_map<int, vector<int>> tmpActivationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> tmpDeactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
map<int64_t, uint64_t> oldStateHashes;
set<int64_t> noReportMetricIds;
bool initConfig(const StatsdConfig& config) {
// initStatsdConfig returns nullopt if config is valid
return !initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, timeBaseNs, configMetadataProvider, allTagIdsToMatchersMap,
oldAtomMatchingTrackers, oldAtomMatchingTrackerMap, oldConditionTrackers,
oldConditionTrackerMap, oldMetricProducers, oldMetricProducerMap,
oldAnomalyTrackers, oldAlarmTrackers, tmpConditionToMetricMap,
tmpTrackerToMetricMap, tmpTrackerToConditionMap,
tmpActivationAtomTrackerToMetricMap, tmpDeactivationAtomTrackerToMetricMap,
oldAlertTrackerMap, metricsWithActivation, oldStateHashes, noReportMetricIds)
.has_value();
}
vector<int> filterMatcherIndexesById(const vector<sp<AtomMatchingTracker>>& atomMatchingTrackers,
const vector<int64_t>& ids) {
vector<int> result;
for (auto& id : ids) {
for (int i = 0; i < atomMatchingTrackers.size(); i++) {
if (atomMatchingTrackers[i]->getId() == id) {
result.push_back(i);
}
}
}
return result;
}
class ConfigUpdateTest : public ::testing::Test {
public:
void SetUp() override {
allTagIdsToMatchersMap.clear();
oldAtomMatchingTrackers.clear();
oldAtomMatchingTrackerMap.clear();
oldConditionTrackers.clear();
oldConditionTrackerMap.clear();
oldMetricProducers.clear();
oldMetricProducerMap.clear();
oldAnomalyTrackers.clear();
oldAlarmTrackers.clear();
tmpConditionToMetricMap.clear();
tmpTrackerToMetricMap.clear();
tmpTrackerToConditionMap.clear();
tmpActivationAtomTrackerToMetricMap.clear();
tmpDeactivationAtomTrackerToMetricMap.clear();
oldAlertTrackerMap.clear();
metricsWithActivation.clear();
oldStateHashes.clear();
noReportMetricIds.clear();
StateManager::getInstance().clear();
}
};
struct DimLimitTestCase {
int oldLimit;
int newLimit;
int actualLimit;
friend void PrintTo(const DimLimitTestCase& testCase, ostream* os) {
*os << testCase.oldLimit << "To" << testCase.newLimit;
}
};
class ConfigUpdateDimLimitTest : public ConfigUpdateTest,
public WithParamInterface<DimLimitTestCase> {};
const vector<DimLimitTestCase> dimLimitTestCases = {
{900, 900, 900}, {1000, 850, 850}, {1100, 1500, 1500},
{800, 799, 800}, {3000, 3001, 3000}, {800, 0, 800},
};
INSTANTIATE_TEST_SUITE_P(DimLimit, ConfigUpdateDimLimitTest, ValuesIn(dimLimitTestCases),
PrintToStringParamName());
} // anonymous namespace
TEST_F(ConfigUpdateTest, TestSimpleMatcherPreserve) {
StatsdConfig config;
AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
int64_t matcherId = matcher.id();
*config.add_atom_matcher() = matcher;
// Create an initial config.
EXPECT_TRUE(initConfig(config));
vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(1, false);
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
newAtomMatchingTrackerMap[matcherId] = 0;
EXPECT_EQ(determineMatcherUpdateStatus(config, 0, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestSimpleMatcherReplace) {
StatsdConfig config;
AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
*config.add_atom_matcher() = matcher;
EXPECT_TRUE(initConfig(config));
StatsdConfig newConfig;
// Same id, different atom, so should be replaced.
AtomMatcher newMatcher = CreateSimpleAtomMatcher("TEST", /*atom=*/11);
int64_t matcherId = newMatcher.id();
EXPECT_EQ(matcherId, matcher.id());
*newConfig.add_atom_matcher() = newMatcher;
vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(1, false);
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
newAtomMatchingTrackerMap[matcherId] = 0;
EXPECT_EQ(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestSimpleMatcherNew) {
StatsdConfig config;
AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
*config.add_atom_matcher() = matcher;
EXPECT_TRUE(initConfig(config));
StatsdConfig newConfig;
// Different id, so should be a new matcher.
AtomMatcher newMatcher = CreateSimpleAtomMatcher("DIFFERENT_NAME", /*atom=*/10);
int64_t matcherId = newMatcher.id();
EXPECT_NE(matcherId, matcher.id());
*newConfig.add_atom_matcher() = newMatcher;
vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(1, false);
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
newAtomMatchingTrackerMap[matcherId] = 0;
EXPECT_EQ(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(matchersToUpdate[0], UPDATE_NEW);
}
TEST_F(ConfigUpdateTest, TestCombinationMatcherPreserve) {
StatsdConfig config;
AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
*config.add_atom_matcher() = matcher2;
int64_t matcher2Id = matcher2.id();
AtomMatcher matcher3;
matcher3.set_id(StringToId("TEST3"));
AtomMatcher_Combination* combination = matcher3.mutable_combination();
combination->set_operation(LogicalOperation::OR);
combination->add_matcher(matcher1Id);
combination->add_matcher(matcher2Id);
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
EXPECT_TRUE(initConfig(config));
StatsdConfig newConfig;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
// Same matchers, different order, all should be preserved.
*newConfig.add_atom_matcher() = matcher2;
newAtomMatchingTrackerMap[matcher2Id] = 0;
*newConfig.add_atom_matcher() = matcher3;
newAtomMatchingTrackerMap[matcher3Id] = 1;
*newConfig.add_atom_matcher() = matcher1;
newAtomMatchingTrackerMap[matcher1Id] = 2;
vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(3, false);
// Only update the combination. It should recurse the two child matchers and preserve all 3.
EXPECT_EQ(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE);
EXPECT_EQ(matchersToUpdate[1], UPDATE_PRESERVE);
EXPECT_EQ(matchersToUpdate[2], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestCombinationMatcherReplace) {
StatsdConfig config;
AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
*config.add_atom_matcher() = matcher2;
int64_t matcher2Id = matcher2.id();
AtomMatcher matcher3;
matcher3.set_id(StringToId("TEST3"));
AtomMatcher_Combination* combination = matcher3.mutable_combination();
combination->set_operation(LogicalOperation::OR);
combination->add_matcher(matcher1Id);
combination->add_matcher(matcher2Id);
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
EXPECT_TRUE(initConfig(config));
// Change the logical operation of the combination matcher, causing a replacement.
matcher3.mutable_combination()->set_operation(LogicalOperation::AND);
StatsdConfig newConfig;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
*newConfig.add_atom_matcher() = matcher2;
newAtomMatchingTrackerMap[matcher2Id] = 0;
*newConfig.add_atom_matcher() = matcher3;
newAtomMatchingTrackerMap[matcher3Id] = 1;
*newConfig.add_atom_matcher() = matcher1;
newAtomMatchingTrackerMap[matcher1Id] = 2;
vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(3, false);
// Only update the combination. The simple matchers should not be evaluated.
EXPECT_EQ(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(matchersToUpdate[0], UPDATE_UNKNOWN);
EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE);
EXPECT_EQ(matchersToUpdate[2], UPDATE_UNKNOWN);
}
TEST_F(ConfigUpdateTest, TestCombinationMatcherDepsChange) {
StatsdConfig config;
AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
*config.add_atom_matcher() = matcher2;
int64_t matcher2Id = matcher2.id();
AtomMatcher matcher3;
matcher3.set_id(StringToId("TEST3"));
AtomMatcher_Combination* combination = matcher3.mutable_combination();
combination->set_operation(LogicalOperation::OR);
combination->add_matcher(matcher1Id);
combination->add_matcher(matcher2Id);
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
EXPECT_TRUE(initConfig(config));
// Change a dependency of matcher 3.
matcher2.mutable_simple_atom_matcher()->set_atom_id(12);
StatsdConfig newConfig;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
*newConfig.add_atom_matcher() = matcher2;
newAtomMatchingTrackerMap[matcher2Id] = 0;
*newConfig.add_atom_matcher() = matcher3;
newAtomMatchingTrackerMap[matcher3Id] = 1;
*newConfig.add_atom_matcher() = matcher1;
newAtomMatchingTrackerMap[matcher1Id] = 2;
vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(3, false);
// Only update the combination.
EXPECT_EQ(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker),
nullopt);
// Matcher 2 and matcher3 must be reevaluated. Matcher 1 might, but does not need to be.
EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestUpdateMatchers) {
StatsdConfig config;
// Will be preserved.
AtomMatcher simple1 = CreateSimpleAtomMatcher("SIMPLE1", /*atom=*/10);
int64_t simple1Id = simple1.id();
*config.add_atom_matcher() = simple1;
// Will be replaced.
AtomMatcher simple2 = CreateSimpleAtomMatcher("SIMPLE2", /*atom=*/11);
*config.add_atom_matcher() = simple2;
int64_t simple2Id = simple2.id();
// Will be removed.
AtomMatcher simple3 = CreateSimpleAtomMatcher("SIMPLE3", /*atom=*/12);
*config.add_atom_matcher() = simple3;
int64_t simple3Id = simple3.id();
// Will be preserved.
AtomMatcher combination1;
combination1.set_id(StringToId("combination1"));
AtomMatcher_Combination* combination = combination1.mutable_combination();
combination->set_operation(LogicalOperation::NOT);
combination->add_matcher(simple1Id);
int64_t combination1Id = combination1.id();
*config.add_atom_matcher() = combination1;
// Will be replaced since it depends on simple2.
AtomMatcher combination2;
combination2.set_id(StringToId("combination2"));
combination = combination2.mutable_combination();
combination->set_operation(LogicalOperation::AND);
combination->add_matcher(simple1Id);
combination->add_matcher(simple2Id);
int64_t combination2Id = combination2.id();
*config.add_atom_matcher() = combination2;
EXPECT_TRUE(initConfig(config));
// Change simple2, causing simple2 and combination2 to be replaced.
simple2.mutable_simple_atom_matcher()->set_atom_id(111);
// 2 new matchers: simple4 and combination3:
AtomMatcher simple4 = CreateSimpleAtomMatcher("SIMPLE4", /*atom=*/13);
int64_t simple4Id = simple4.id();
AtomMatcher combination3;
combination3.set_id(StringToId("combination3"));
combination = combination3.mutable_combination();
combination->set_operation(LogicalOperation::AND);
combination->add_matcher(simple4Id);
combination->add_matcher(simple2Id);
int64_t combination3Id = combination3.id();
StatsdConfig newConfig;
*newConfig.add_atom_matcher() = combination3;
*newConfig.add_atom_matcher() = simple2;
*newConfig.add_atom_matcher() = combination2;
*newConfig.add_atom_matcher() = simple1;
*newConfig.add_atom_matcher() = simple4;
*newConfig.add_atom_matcher() = combination1;
unordered_map<int, vector<int>> newTagIds;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
set<int64_t> replacedMatchers;
EXPECT_EQ(updateAtomMatchingTrackers(newConfig, uidMap, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newTagIds,
newAtomMatchingTrackerMap, newAtomMatchingTrackers,
replacedMatchers),
nullopt);
ASSERT_EQ(newTagIds.size(), 3);
EXPECT_EQ(newTagIds.count(10), 1);
EXPECT_EQ(newTagIds.count(111), 1);
EXPECT_EQ(newTagIds.count(13), 1);
EXPECT_EQ(newTagIds[10].size(), 3); // simple1, combination1, combination2
EXPECT_THAT(newTagIds[10], UnorderedElementsAreArray(filterMatcherIndexesById(
newAtomMatchingTrackers,
{simple1.id(), combination1.id(), combination2.id()})));
EXPECT_EQ(newTagIds[111].size(), 3); // simple2, combination2, combination3
EXPECT_THAT(newTagIds[111], UnorderedElementsAreArray(filterMatcherIndexesById(
newAtomMatchingTrackers,
{simple2.id(), combination2.id(), combination3.id()})));
EXPECT_EQ(newTagIds[13].size(), 2); // simple4, combination3
EXPECT_THAT(newTagIds[13],
UnorderedElementsAreArray(filterMatcherIndexesById(
newAtomMatchingTrackers, {simple4.id(), combination3.id()})));
ASSERT_EQ(newAtomMatchingTrackerMap.size(), 6);
EXPECT_EQ(newAtomMatchingTrackerMap.at(combination3Id), 0);
EXPECT_EQ(newAtomMatchingTrackerMap.at(simple2Id), 1);
EXPECT_EQ(newAtomMatchingTrackerMap.at(combination2Id), 2);
EXPECT_EQ(newAtomMatchingTrackerMap.at(simple1Id), 3);
EXPECT_EQ(newAtomMatchingTrackerMap.at(simple4Id), 4);
EXPECT_EQ(newAtomMatchingTrackerMap.at(combination1Id), 5);
ASSERT_EQ(newAtomMatchingTrackers.size(), 6);
// Make sure all atom matchers are initialized:
for (const sp<AtomMatchingTracker>& tracker : newAtomMatchingTrackers) {
EXPECT_TRUE(tracker->mInitialized);
}
// Make sure preserved atom matchers are the same.
EXPECT_EQ(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(simple1Id)],
newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(simple1Id)]);
EXPECT_EQ(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(combination1Id)],
newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(combination1Id)]);
// Make sure replaced matchers are different.
EXPECT_NE(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(simple2Id)],
newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(simple2Id)]);
EXPECT_NE(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(combination2Id)],
newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(combination2Id)]);
// Validation, make sure the matchers have the proper ids. Could do more checks here.
EXPECT_EQ(newAtomMatchingTrackers[0]->getId(), combination3Id);
EXPECT_EQ(newAtomMatchingTrackers[1]->getId(), simple2Id);
EXPECT_EQ(newAtomMatchingTrackers[2]->getId(), combination2Id);
EXPECT_EQ(newAtomMatchingTrackers[3]->getId(), simple1Id);
EXPECT_EQ(newAtomMatchingTrackers[4]->getId(), simple4Id);
EXPECT_EQ(newAtomMatchingTrackers[5]->getId(), combination1Id);
// Verify child indices of Combination Matchers are correct.
CombinationAtomMatchingTracker* combinationTracker1 =
static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[5].get());
vector<int>* childMatchers = &combinationTracker1->mChildren;
EXPECT_EQ(childMatchers->size(), 1);
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end());
CombinationAtomMatchingTracker* combinationTracker2 =
static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[2].get());
childMatchers = &combinationTracker2->mChildren;
EXPECT_EQ(childMatchers->size(), 2);
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end());
CombinationAtomMatchingTracker* combinationTracker3 =
static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[0].get());
childMatchers = &combinationTracker3->mChildren;
EXPECT_EQ(childMatchers->size(), 2);
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 4), childMatchers->end());
// Expect replacedMatchers to have simple2 and combination2
ASSERT_EQ(replacedMatchers.size(), 2);
EXPECT_NE(replacedMatchers.find(simple2Id), replacedMatchers.end());
EXPECT_NE(replacedMatchers.find(combination2Id), replacedMatchers.end());
}
TEST_F(ConfigUpdateTest, TestSimpleConditionPreserve) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
// Create an initial config.
EXPECT_TRUE(initConfig(config));
set<int64_t> replacedMatchers;
vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(1, false);
unordered_map<int64_t, int> newConditionTrackerMap;
newConditionTrackerMap[predicate.id()] = 0;
EXPECT_EQ(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
oldConditionTrackers, newConditionTrackerMap,
replacedMatchers, conditionsToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestSimpleConditionReplace) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
EXPECT_TRUE(initConfig(config));
// Modify the predicate.
config.mutable_predicate(0)->mutable_simple_predicate()->set_count_nesting(true);
set<int64_t> replacedMatchers;
vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(1, false);
unordered_map<int64_t, int> newConditionTrackerMap;
newConditionTrackerMap[predicate.id()] = 0;
EXPECT_EQ(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
oldConditionTrackers, newConditionTrackerMap,
replacedMatchers, conditionsToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestSimpleConditionDepsChange) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
int64_t startMatcherId = startMatcher.id();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
EXPECT_TRUE(initConfig(config));
// Start matcher was replaced.
set<int64_t> replacedMatchers;
replacedMatchers.insert(startMatcherId);
vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(1, false);
unordered_map<int64_t, int> newConditionTrackerMap;
newConditionTrackerMap[predicate.id()] = 0;
EXPECT_EQ(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
oldConditionTrackers, newConditionTrackerMap,
replacedMatchers, conditionsToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestCombinationConditionPreserve) {
StatsdConfig config;
AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = screenOnMatcher;
AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = screenOffMatcher;
Predicate simple1 = CreateScreenIsOnPredicate();
*config.add_predicate() = simple1;
Predicate simple2 = CreateScreenIsOffPredicate();
*config.add_predicate() = simple2;
Predicate combination1;
combination1.set_id(StringToId("COMBINATION1"));
Predicate_Combination* combinationInternal = combination1.mutable_combination();
combinationInternal->set_operation(LogicalOperation::NAND);
combinationInternal->add_predicate(simple1.id());
combinationInternal->add_predicate(simple2.id());
*config.add_predicate() = combination1;
EXPECT_TRUE(initConfig(config));
// Same predicates, different order
StatsdConfig newConfig;
unordered_map<int64_t, int> newConditionTrackerMap;
*newConfig.add_predicate() = combination1;
newConditionTrackerMap[combination1.id()] = 0;
*newConfig.add_predicate() = simple2;
newConditionTrackerMap[simple2.id()] = 1;
*newConfig.add_predicate() = simple1;
newConditionTrackerMap[simple1.id()] = 2;
set<int64_t> replacedMatchers;
vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(3, false);
// Only update the combination. It should recurse the two child predicates and preserve all 3.
EXPECT_EQ(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
oldConditionTrackers, newConditionTrackerMap,
replacedMatchers, conditionsToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE);
EXPECT_EQ(conditionsToUpdate[1], UPDATE_PRESERVE);
EXPECT_EQ(conditionsToUpdate[2], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestCombinationConditionReplace) {
StatsdConfig config;
AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = screenOnMatcher;
AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = screenOffMatcher;
Predicate simple1 = CreateScreenIsOnPredicate();
*config.add_predicate() = simple1;
Predicate simple2 = CreateScreenIsOffPredicate();
*config.add_predicate() = simple2;
Predicate combination1;
combination1.set_id(StringToId("COMBINATION1"));
Predicate_Combination* combinationInternal = combination1.mutable_combination();
combinationInternal->set_operation(LogicalOperation::NAND);
combinationInternal->add_predicate(simple1.id());
combinationInternal->add_predicate(simple2.id());
*config.add_predicate() = combination1;
EXPECT_TRUE(initConfig(config));
// Changing the logical operation changes the predicate definition, so it should be replaced.
combination1.mutable_combination()->set_operation(LogicalOperation::OR);
StatsdConfig newConfig;
unordered_map<int64_t, int> newConditionTrackerMap;
*newConfig.add_predicate() = combination1;
newConditionTrackerMap[combination1.id()] = 0;
*newConfig.add_predicate() = simple2;
newConditionTrackerMap[simple2.id()] = 1;
*newConfig.add_predicate() = simple1;
newConditionTrackerMap[simple1.id()] = 2;
set<int64_t> replacedMatchers;
vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(3, false);
// Only update the combination. The simple conditions should not be evaluated.
EXPECT_EQ(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
oldConditionTrackers, newConditionTrackerMap,
replacedMatchers, conditionsToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
EXPECT_EQ(conditionsToUpdate[1], UPDATE_UNKNOWN);
EXPECT_EQ(conditionsToUpdate[2], UPDATE_UNKNOWN);
}
TEST_F(ConfigUpdateTest, TestCombinationConditionDepsChange) {
StatsdConfig config;
AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = screenOnMatcher;
AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = screenOffMatcher;
Predicate simple1 = CreateScreenIsOnPredicate();
*config.add_predicate() = simple1;
Predicate simple2 = CreateScreenIsOffPredicate();
*config.add_predicate() = simple2;
Predicate combination1;
combination1.set_id(StringToId("COMBINATION1"));
Predicate_Combination* combinationInternal = combination1.mutable_combination();
combinationInternal->set_operation(LogicalOperation::NAND);
combinationInternal->add_predicate(simple1.id());
combinationInternal->add_predicate(simple2.id());
*config.add_predicate() = combination1;
EXPECT_TRUE(initConfig(config));
simple2.mutable_simple_predicate()->set_count_nesting(false);
StatsdConfig newConfig;
unordered_map<int64_t, int> newConditionTrackerMap;
*newConfig.add_predicate() = combination1;
newConditionTrackerMap[combination1.id()] = 0;
*newConfig.add_predicate() = simple2;
newConditionTrackerMap[simple2.id()] = 1;
*newConfig.add_predicate() = simple1;
newConditionTrackerMap[simple1.id()] = 2;
set<int64_t> replacedMatchers;
vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
vector<uint8_t> cycleTracker(3, false);
// Only update the combination. Simple2 and combination1 must be evaluated.
EXPECT_EQ(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
oldConditionTrackers, newConditionTrackerMap,
replacedMatchers, conditionsToUpdate, cycleTracker),
nullopt);
EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
EXPECT_EQ(conditionsToUpdate[1], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestUpdateConditions) {
StatsdConfig config;
// Add atom matchers. These are mostly needed for initStatsdConfig
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher();
int64_t matcher5Id = matcher5.id();
*config.add_atom_matcher() = matcher5;
AtomMatcher matcher6 = CreateBatterySaverModeStopAtomMatcher();
int64_t matcher6Id = matcher6.id();
*config.add_atom_matcher() = matcher6;
// Add the predicates.
// Will be preserved.
Predicate simple1 = CreateScreenIsOnPredicate();
int64_t simple1Id = simple1.id();
*config.add_predicate() = simple1;
// Will be preserved.
Predicate simple2 = CreateScheduledJobPredicate();
int64_t simple2Id = simple2.id();
*config.add_predicate() = simple2;
// Will be replaced.
Predicate simple3 = CreateBatterySaverModePredicate();
int64_t simple3Id = simple3.id();
*config.add_predicate() = simple3;
// Will be preserved
Predicate combination1;
combination1.set_id(StringToId("COMBINATION1"));
combination1.mutable_combination()->set_operation(LogicalOperation::AND);
combination1.mutable_combination()->add_predicate(simple1Id);
combination1.mutable_combination()->add_predicate(simple2Id);
int64_t combination1Id = combination1.id();
*config.add_predicate() = combination1;
// Will be replaced since simple3 will be replaced.
Predicate combination2;
combination2.set_id(StringToId("COMBINATION2"));
combination2.mutable_combination()->set_operation(LogicalOperation::OR);
combination2.mutable_combination()->add_predicate(simple1Id);
combination2.mutable_combination()->add_predicate(simple3Id);
int64_t combination2Id = combination2.id();
*config.add_predicate() = combination2;
// Will be removed.
Predicate combination3;
combination3.set_id(StringToId("COMBINATION3"));
combination3.mutable_combination()->set_operation(LogicalOperation::NOT);
combination3.mutable_combination()->add_predicate(simple2Id);
int64_t combination3Id = combination3.id();
*config.add_predicate() = combination3;
EXPECT_TRUE(initConfig(config));
// Mark marcher 5 as replaced. Causes simple3, and therefore combination2 to be replaced.
set<int64_t> replacedMatchers;
replacedMatchers.insert(matcher6Id);
// Change the condition of simple1 to false.
ASSERT_EQ(oldConditionTrackers[0]->getConditionId(), simple1Id);
LogEvent event(/*uid=*/0, /*pid=*/0); // Empty event is fine since there are no dimensions.
// Mark the stop matcher as matched, condition should be false.
vector<MatchingState> eventMatcherValues(6, MatchingState::kNotMatched);
eventMatcherValues[1] = MatchingState::kMatched;
vector<ConditionState> tmpConditionCache(6, ConditionState::kNotEvaluated);
vector<uint8_t> conditionChangeCache(6, false);
oldConditionTrackers[0]->evaluateCondition(event, eventMatcherValues, oldConditionTrackers,
tmpConditionCache, conditionChangeCache);
EXPECT_EQ(tmpConditionCache[0], ConditionState::kFalse);
EXPECT_EQ(conditionChangeCache[0], true);
// New combination predicate. Should have an initial condition of true since it is NOT(simple1).
Predicate combination4;
combination4.set_id(StringToId("COMBINATION4"));
combination4.mutable_combination()->set_operation(LogicalOperation::NOT);
combination4.mutable_combination()->add_predicate(simple1Id);
int64_t combination4Id = combination4.id();
*config.add_predicate() = combination4;
// Map the matchers in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher6Index = 0;
newAtomMatchingTrackerMap[matcher6Id] = 0;
const int matcher5Index = 1;
newAtomMatchingTrackerMap[matcher5Id] = 1;
const int matcher4Index = 2;
newAtomMatchingTrackerMap[matcher4Id] = 2;
const int matcher3Index = 3;
newAtomMatchingTrackerMap[matcher3Id] = 3;
const int matcher2Index = 4;
newAtomMatchingTrackerMap[matcher2Id] = 4;
const int matcher1Index = 5;
newAtomMatchingTrackerMap[matcher1Id] = 5;
StatsdConfig newConfig;
*newConfig.add_predicate() = simple3;
const int simple3Index = 0;
*newConfig.add_predicate() = combination2;
const int combination2Index = 1;
*newConfig.add_predicate() = combination4;
const int combination4Index = 2;
*newConfig.add_predicate() = simple2;
const int simple2Index = 3;
*newConfig.add_predicate() = combination1;
const int combination1Index = 4;
*newConfig.add_predicate() = simple1;
const int simple1Index = 5;
unordered_map<int64_t, int> newConditionTrackerMap;
vector<sp<ConditionTracker>> newConditionTrackers;
unordered_map<int, vector<int>> trackerToConditionMap;
vector<ConditionState> conditionCache;
set<int64_t> replacedConditions;
EXPECT_EQ(updateConditions(key, newConfig, newAtomMatchingTrackerMap, replacedMatchers,
oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap,
newConditionTrackers, trackerToConditionMap, conditionCache,
replacedConditions),
nullopt);
unordered_map<int64_t, int> expectedConditionTrackerMap = {
{simple1Id, simple1Index}, {simple2Id, simple2Index},
{simple3Id, simple3Index}, {combination1Id, combination1Index},
{combination2Id, combination2Index}, {combination4Id, combination4Index},
};
EXPECT_THAT(newConditionTrackerMap, ContainerEq(expectedConditionTrackerMap));
ASSERT_EQ(newConditionTrackers.size(), 6);
// Make sure all conditions are initialized:
for (const sp<ConditionTracker>& tracker : newConditionTrackers) {
EXPECT_TRUE(tracker->mInitialized);
}
// Make sure preserved conditions are the same.
EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple1Id)],
newConditionTrackers[newConditionTrackerMap.at(simple1Id)]);
EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple2Id)],
newConditionTrackers[newConditionTrackerMap.at(simple2Id)]);
EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(combination1Id)],
newConditionTrackers[newConditionTrackerMap.at(combination1Id)]);
// Make sure replaced conditions are different and included in replacedConditions.
EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(simple3Id)],
newConditionTrackers[newConditionTrackerMap.at(simple3Id)]);
EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(combination2Id)],
newConditionTrackers[newConditionTrackerMap.at(combination2Id)]);
EXPECT_THAT(replacedConditions, ContainerEq(set({simple3Id, combination2Id})));
// Verify the trackerToConditionMap
ASSERT_EQ(trackerToConditionMap.size(), 6);
const vector<int>& matcher1Conditions = trackerToConditionMap[matcher1Index];
EXPECT_THAT(matcher1Conditions, UnorderedElementsAre(simple1Index, combination1Index,
combination2Index, combination4Index));
const vector<int>& matcher2Conditions = trackerToConditionMap[matcher2Index];
EXPECT_THAT(matcher2Conditions, UnorderedElementsAre(simple1Index, combination1Index,
combination2Index, combination4Index));
const vector<int>& matcher3Conditions = trackerToConditionMap[matcher3Index];
EXPECT_THAT(matcher3Conditions, UnorderedElementsAre(simple2Index, combination1Index));
const vector<int>& matcher4Conditions = trackerToConditionMap[matcher4Index];
EXPECT_THAT(matcher4Conditions, UnorderedElementsAre(simple2Index, combination1Index));
const vector<int>& matcher5Conditions = trackerToConditionMap[matcher5Index];
EXPECT_THAT(matcher5Conditions, UnorderedElementsAre(simple3Index, combination2Index));
const vector<int>& matcher6Conditions = trackerToConditionMap[matcher6Index];
EXPECT_THAT(matcher6Conditions, UnorderedElementsAre(simple3Index, combination2Index));
// Verify the conditionCache. Specifically, simple1 is false and combination4 is true.
ASSERT_EQ(conditionCache.size(), 6);
EXPECT_EQ(conditionCache[simple1Index], ConditionState::kFalse);
EXPECT_EQ(conditionCache[simple2Index], ConditionState::kUnknown);
EXPECT_EQ(conditionCache[simple3Index], ConditionState::kUnknown);
EXPECT_EQ(conditionCache[combination1Index], ConditionState::kUnknown);
EXPECT_EQ(conditionCache[combination2Index], ConditionState::kUnknown);
EXPECT_EQ(conditionCache[combination4Index], ConditionState::kTrue);
// Verify tracker indices/ids are correct.
EXPECT_EQ(newConditionTrackers[simple1Index]->getConditionId(), simple1Id);
EXPECT_EQ(newConditionTrackers[simple1Index]->mIndex, simple1Index);
EXPECT_TRUE(newConditionTrackers[simple1Index]->IsSimpleCondition());
EXPECT_EQ(newConditionTrackers[simple2Index]->getConditionId(), simple2Id);
EXPECT_EQ(newConditionTrackers[simple2Index]->mIndex, simple2Index);
EXPECT_TRUE(newConditionTrackers[simple2Index]->IsSimpleCondition());
EXPECT_EQ(newConditionTrackers[simple3Index]->getConditionId(), simple3Id);
EXPECT_EQ(newConditionTrackers[simple3Index]->mIndex, simple3Index);
EXPECT_TRUE(newConditionTrackers[simple3Index]->IsSimpleCondition());
EXPECT_EQ(newConditionTrackers[combination1Index]->getConditionId(), combination1Id);
EXPECT_EQ(newConditionTrackers[combination1Index]->mIndex, combination1Index);
EXPECT_FALSE(newConditionTrackers[combination1Index]->IsSimpleCondition());
EXPECT_EQ(newConditionTrackers[combination2Index]->getConditionId(), combination2Id);
EXPECT_EQ(newConditionTrackers[combination2Index]->mIndex, combination2Index);
EXPECT_FALSE(newConditionTrackers[combination2Index]->IsSimpleCondition());
EXPECT_EQ(newConditionTrackers[combination4Index]->getConditionId(), combination4Id);
EXPECT_EQ(newConditionTrackers[combination4Index]->mIndex, combination4Index);
EXPECT_FALSE(newConditionTrackers[combination4Index]->IsSimpleCondition());
// Verify preserved trackers have indices updated.
SimpleConditionTracker* simpleTracker1 =
static_cast<SimpleConditionTracker*>(newConditionTrackers[simple1Index].get());
EXPECT_EQ(simpleTracker1->mStartLogMatcherIndex, matcher1Index);
EXPECT_EQ(simpleTracker1->mStopLogMatcherIndex, matcher2Index);
EXPECT_EQ(simpleTracker1->mStopAllLogMatcherIndex, -1);
SimpleConditionTracker* simpleTracker2 =
static_cast<SimpleConditionTracker*>(newConditionTrackers[simple2Index].get());
EXPECT_EQ(simpleTracker2->mStartLogMatcherIndex, matcher3Index);
EXPECT_EQ(simpleTracker2->mStopLogMatcherIndex, matcher4Index);
EXPECT_EQ(simpleTracker2->mStopAllLogMatcherIndex, -1);
CombinationConditionTracker* combinationTracker1 = static_cast<CombinationConditionTracker*>(
newConditionTrackers[combination1Index].get());
EXPECT_THAT(combinationTracker1->mChildren, UnorderedElementsAre(simple1Index, simple2Index));
EXPECT_THAT(combinationTracker1->mUnSlicedChildren,
UnorderedElementsAre(simple1Index, simple2Index));
EXPECT_THAT(combinationTracker1->mSlicedChildren, IsEmpty());
}
TEST_F(ConfigUpdateTest, TestUpdateStates) {
StatsdConfig config;
// Add states.
// Will be replaced because we add a state map.
State state1 = CreateScreenState();
int64_t state1Id = state1.id();
*config.add_state() = state1;
// Will be preserved.
State state2 = CreateUidProcessState();
int64_t state2Id = state2.id();
*config.add_state() = state2;
// Will be replaced since the atom changes from overlay to screen.
State state3 = CreateOverlayState();
int64_t state3Id = state3.id();
*config.add_state() = state3;
EXPECT_TRUE(initConfig(config));
// Change definitions of state1 and state3.
int64_t screenOnId = 0x4321, screenOffId = 0x1234;
*state1.mutable_map() = CreateScreenStateSimpleOnOffMap(screenOnId, screenOffId);
state3.set_atom_id(util::SCREEN_STATE_CHANGED);
StatsdConfig newConfig;
*newConfig.add_state() = state3;
*newConfig.add_state() = state1;
*newConfig.add_state() = state2;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
map<int64_t, uint64_t> newStateProtoHashes;
set<int64_t> replacedStates;
EXPECT_EQ(updateStates(newConfig, oldStateHashes, stateAtomIdMap, allStateGroupMaps,
newStateProtoHashes, replacedStates),
nullopt);
EXPECT_THAT(replacedStates, ContainerEq(set({state1Id, state3Id})));
unordered_map<int64_t, int> expectedStateAtomIdMap = {
{state1Id, util::SCREEN_STATE_CHANGED},
{state2Id, util::UID_PROCESS_STATE_CHANGED},
{state3Id, util::SCREEN_STATE_CHANGED}};
EXPECT_THAT(stateAtomIdMap, ContainerEq(expectedStateAtomIdMap));
unordered_map<int64_t, unordered_map<int, int64_t>> expectedStateGroupMaps = {
{state1Id,
{{android::view::DisplayStateEnum::DISPLAY_STATE_OFF, screenOffId},
{android::view::DisplayStateEnum::DISPLAY_STATE_ON, screenOnId}}}};
EXPECT_THAT(allStateGroupMaps, ContainerEq(expectedStateGroupMaps));
}
TEST_F(ConfigUpdateTest, TestEventMetricPreserve) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
EventMetric* metric = config.add_event_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestEventMetricActivationAdded) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
EventMetric* metric = config.add_event_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
// Create an initial config.
EXPECT_TRUE(initConfig(config));
// Add a metric activation, which should change the proto, causing replacement.
MetricActivation* activation = config.add_metric_activation();
activation->set_metric_id(12345);
EventActivation* eventActivation = activation->add_event_activation();
eventActivation->set_atom_matcher_id(startMatcher.id());
eventActivation->set_ttl_seconds(5);
unordered_map<int64_t, int> metricToActivationMap = {{12345, 0}};
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestEventMetricWhatChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
EventMetric* metric = config.add_event_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestEventMetricConditionChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
EventMetric* metric = config.add_event_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestMetricConditionLinkDepsChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
Predicate linkPredicate = CreateScreenIsOffPredicate();
*config.add_predicate() = linkPredicate;
EventMetric* metric = config.add_event_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
// Doesn't make sense as a real metric definition, but suffices as a separate predicate
// From the one in the condition.
MetricConditionLink* link = metric->add_links();
link->set_condition(linkPredicate.id());
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{linkPredicate.id()},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestEventMetricActivationDepsChange) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
EventMetric* metric = config.add_event_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
MetricActivation* activation = config.add_metric_activation();
activation->set_metric_id(12345);
EventActivation* eventActivation = activation->add_event_activation();
eventActivation->set_atom_matcher_id(startMatcher.id());
eventActivation->set_ttl_seconds(5);
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap = {{12345, 0}};
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {startMatcher.id()}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestCountMetricPreserve) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
State sliceState = CreateScreenState();
*config.add_state() = sliceState;
CountMetric* metric = config.add_count_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
metric->add_slice_by_state(sliceState.id());
metric->set_bucket(ONE_HOUR);
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestCountMetricDefinitionChange) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
CountMetric* metric = config.add_count_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
metric->set_bucket(ONE_HOUR);
// Create an initial config.
EXPECT_TRUE(initConfig(config));
// Change bucket size, which should change the proto, causing replacement.
metric->set_bucket(TEN_MINUTES);
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestCountMetricWhatChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
CountMetric* metric = config.add_count_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
metric->set_bucket(ONE_HOUR);
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestCountMetricConditionChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
CountMetric* metric = config.add_count_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->set_condition(predicate.id());
metric->set_bucket(ONE_HOUR);
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestCountMetricStateChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
State sliceState = CreateScreenState();
*config.add_state() = sliceState;
CountMetric* metric = config.add_count_metric();
metric->set_id(12345);
metric->set_what(whatMatcher.id());
metric->add_slice_by_state(sliceState.id());
metric->set_bucket(ONE_HOUR);
// Create an initial config.
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{sliceState.id()}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestGaugeMetricPreserve) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
*config.add_gauge_metric() = createGaugeMetric(
"GAUGE1", whatMatcher.id(), GaugeMetric::RANDOM_ONE_SAMPLE, predicate.id(), nullopt);
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestGaugeMetricDefinitionChange) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_gauge_metric() = createGaugeMetric(
"GAUGE1", whatMatcher.id(), GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, nullopt);
EXPECT_TRUE(initConfig(config));
// Change split bucket on app upgrade, which should change the proto, causing replacement.
config.mutable_gauge_metric(0)->set_split_bucket_for_app_upgrade(false);
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestGaugeMetricWhatChanged) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_gauge_metric() = createGaugeMetric(
"GAUGE1", whatMatcher.id(), GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, nullopt);
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestGaugeMetricConditionChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
*config.add_gauge_metric() = createGaugeMetric(
"GAUGE1", whatMatcher.id(), GaugeMetric::RANDOM_ONE_SAMPLE, predicate.id(), nullopt);
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestGaugeMetricTriggerEventChanged) {
StatsdConfig config;
AtomMatcher triggerEvent = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = triggerEvent;
AtomMatcher whatMatcher = CreateTemperatureAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_gauge_metric() = createGaugeMetric(
"GAUGE1", whatMatcher.id(), GaugeMetric::FIRST_N_SAMPLES, nullopt, triggerEvent.id());
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {triggerEvent.id()}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestDurationMetricPreserve) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
Predicate what = CreateScreenIsOnPredicate();
*config.add_predicate() = what;
Predicate condition = CreateScreenIsOffPredicate();
*config.add_predicate() = condition;
State sliceState = CreateScreenState();
*config.add_state() = sliceState;
*config.add_duration_metric() =
createDurationMetric("DURATION1", what.id(), condition.id(), {sliceState.id()});
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestDurationMetricDefinitionChange) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
Predicate what = CreateScreenIsOnPredicate();
*config.add_predicate() = what;
*config.add_duration_metric() = createDurationMetric("DURATION1", what.id(), nullopt, {});
EXPECT_TRUE(initConfig(config));
config.mutable_duration_metric(0)->set_aggregation_type(DurationMetric::MAX_SPARSE);
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap, /*replacedMatchers*/ {},
/*replacedConditions=*/{}, /*replacedStates=*/{},
metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestDurationMetricWhatChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
Predicate what = CreateScreenIsOnPredicate();
*config.add_predicate() = what;
*config.add_duration_metric() = createDurationMetric("DURATION1", what.id(), nullopt, {});
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{what.id()},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestDurationMetricConditionChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
Predicate what = CreateScreenIsOnPredicate();
*config.add_predicate() = what;
Predicate condition = CreateScreenIsOffPredicate();
*config.add_predicate() = condition;
*config.add_duration_metric() = createDurationMetric("DURATION", what.id(), condition.id(), {});
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{condition.id()},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestDurationMetricStateChange) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
Predicate what = CreateScreenIsOnPredicate();
*config.add_predicate() = what;
State sliceState = CreateScreenState();
*config.add_state() = sliceState;
*config.add_duration_metric() =
createDurationMetric("DURATION1", what.id(), nullopt, {sliceState.id()});
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{sliceState.id()}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestValueMetricPreserve) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateTemperatureAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
State sliceState = CreateScreenState();
*config.add_state() = sliceState;
*config.add_value_metric() =
createValueMetric("VALUE1", whatMatcher, 2, predicate.id(), {sliceState.id()});
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestValueMetricDefinitionChange) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_value_metric() = createValueMetric("VALUE1", whatMatcher, 2, nullopt, {});
EXPECT_TRUE(initConfig(config));
// Change skip zero diff output, which should change the proto, causing replacement.
config.mutable_value_metric(0)->set_skip_zero_diff_output(true);
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestValueMetricWhatChanged) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateTemperatureAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_value_metric() = createValueMetric("VALUE1", whatMatcher, 2, nullopt, {});
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestValueMetricConditionChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateTemperatureAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
*config.add_value_metric() = createValueMetric("VALUE1", whatMatcher, 2, predicate.id(), {});
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestValueMetricStateChanged) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
State sliceState = CreateScreenState();
*config.add_state() = sliceState;
*config.add_value_metric() =
createValueMetric("VALUE1", whatMatcher, 2, nullopt, {sliceState.id()});
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{sliceState.id()}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestKllMetricPreserve) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateAppStartOccurredAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
*config.add_kll_metric() =
createKllMetric("KLL1", whatMatcher, /*valueField=*/12, predicate.id());
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate{UPDATE_UNKNOWN};
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestKllMetricDefinitionChange) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_kll_metric() = createKllMetric("KLL1", whatMatcher, /*valueField=*/12, nullopt);
EXPECT_TRUE(initConfig(config));
// Change split bucket setting for app upgrades, which should change the proto, causing
// replacement.
config.mutable_kll_metric(0)->set_split_bucket_for_app_upgrade(false);
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate{UPDATE_UNKNOWN};
EXPECT_EQ(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestKllMetricWhatChanged) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateAppStartOccurredAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_kll_metric() = createKllMetric("KLL1", whatMatcher, /*valueField=*/12, nullopt);
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate{UPDATE_UNKNOWN};
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestKllMetricConditionChanged) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = startMatcher;
AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
*config.add_atom_matcher() = stopMatcher;
AtomMatcher whatMatcher = CreateAppStartOccurredAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
Predicate predicate = CreateScreenIsOnPredicate();
*config.add_predicate() = predicate;
*config.add_kll_metric() =
createKllMetric("KLL1", whatMatcher, /*valueField=*/12, predicate.id());
EXPECT_TRUE(initConfig(config));
unordered_map<int64_t, int> metricToActivationMap;
vector<UpdateStatus> metricsToUpdate{UPDATE_UNKNOWN};
EXPECT_EQ(determineAllMetricUpdateStatuses(
config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
/*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
/*replacedStates=*/{}, metricsToUpdate),
nullopt);
EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestUpdateEventMetrics) {
StatsdConfig config;
// Add atom matchers/predicates. These are mostly needed for initStatsdConfig
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher();
int64_t matcher5Id = matcher5.id();
*config.add_atom_matcher() = matcher5;
Predicate predicate1 = CreateScreenIsOnPredicate();
int64_t predicate1Id = predicate1.id();
*config.add_predicate() = predicate1;
Predicate predicate2 = CreateScheduledJobPredicate();
int64_t predicate2Id = predicate2.id();
*config.add_predicate() = predicate2;
// Add a few event metrics.
// Will be preserved.
EventMetric event1 = createEventMetric("EVENT1", matcher1Id, predicate2Id);
int64_t event1Id = event1.id();
*config.add_event_metric() = event1;
// Will be replaced.
EventMetric event2 = createEventMetric("EVENT2", matcher2Id, nullopt);
int64_t event2Id = event2.id();
*config.add_event_metric() = event2;
// Will be replaced.
EventMetric event3 = createEventMetric("EVENT3", matcher3Id, nullopt);
int64_t event3Id = event3.id();
*config.add_event_metric() = event3;
MetricActivation event3Activation;
event3Activation.set_metric_id(event3Id);
EventActivation* eventActivation = event3Activation.add_event_activation();
eventActivation->set_atom_matcher_id(matcher5Id);
eventActivation->set_ttl_seconds(5);
*config.add_metric_activation() = event3Activation;
// Will be replaced.
EventMetric event4 = createEventMetric("EVENT4", matcher4Id, predicate1Id);
int64_t event4Id = event4.id();
*config.add_event_metric() = event4;
// Will be deleted.
EventMetric event5 = createEventMetric("EVENT5", matcher5Id, nullopt);
int64_t event5Id = event5.id();
*config.add_event_metric() = event5;
EXPECT_TRUE(initConfig(config));
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard;
EXPECT_EQ(oldConditionWizard->getStrongCount(), oldMetricProducers.size() + 1);
// Add a condition to event2, causing it to be replaced.
event2.set_condition(predicate1Id);
// Mark matcher 5 as replaced. Causes event3 to be replaced.
set<int64_t> replacedMatchers;
replacedMatchers.insert(matcher5Id);
// Mark predicate 1 as replaced. Causes event4 to be replaced.
set<int64_t> replacedConditions;
replacedConditions.insert(predicate1Id);
// Fake that predicate 2 is true.
ASSERT_EQ(oldMetricProducers[0]->getMetricId(), event1Id);
oldMetricProducers[0]->onConditionChanged(true, /*timestamp=*/0);
EXPECT_EQ(oldMetricProducers[0]->mCondition, ConditionState::kTrue);
// New event metric. Should have an initial condition of true since it depends on predicate2.
EventMetric event6 = createEventMetric("EVENT6", matcher3Id, predicate2Id);
int64_t event6Id = event6.id();
MetricActivation event6Activation;
event6Activation.set_metric_id(event6Id);
eventActivation = event6Activation.add_event_activation();
eventActivation->set_atom_matcher_id(matcher5Id);
eventActivation->set_ttl_seconds(20);
// Map the matchers and predicates in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher5Index = 0;
newAtomMatchingTrackerMap[matcher5Id] = 0;
const int matcher4Index = 1;
newAtomMatchingTrackerMap[matcher4Id] = 1;
const int matcher3Index = 2;
newAtomMatchingTrackerMap[matcher3Id] = 2;
const int matcher2Index = 3;
newAtomMatchingTrackerMap[matcher2Id] = 3;
const int matcher1Index = 4;
newAtomMatchingTrackerMap[matcher1Id] = 4;
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
std::unordered_map<int64_t, int> newConditionTrackerMap;
const int predicate2Index = 0;
newConditionTrackerMap[predicate2Id] = 0;
const int predicate1Index = 1;
newConditionTrackerMap[predicate1Id] = 1;
// Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
vector<sp<ConditionTracker>> newConditionTrackers(2);
std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
newConditionTrackers.begin());
// Fake that predicate2 is true.
vector<ConditionState> conditionCache = {ConditionState::kTrue, ConditionState::kUnknown};
StatsdConfig newConfig;
*newConfig.add_event_metric() = event6;
const int event6Index = 0;
*newConfig.add_event_metric() = event3;
const int event3Index = 1;
*newConfig.add_event_metric() = event1;
const int event1Index = 2;
*newConfig.add_event_metric() = event4;
const int event4Index = 3;
*newConfig.add_event_metric() = event2;
const int event2Index = 4;
*newConfig.add_metric_activation() = event3Activation;
*newConfig.add_metric_activation() = event6Activation;
// Output data structures to validate.
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
provider, newMetricProducerMap, newMetricProducers,
conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
metricsWithActivation, replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
{event1Id, event1Index}, {event2Id, event2Index}, {event3Id, event3Index},
{event4Id, event4Index}, {event6Id, event6Index},
};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
EXPECT_EQ(replacedMetrics, set<int64_t>({event2Id, event3Id, event4Id}));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 5);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(event1Id)],
newMetricProducers[newMetricProducerMap.at(event1Id)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(event2Id)],
newMetricProducers[newMetricProducerMap.at(event2Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(event3Id)],
newMetricProducers[newMetricProducerMap.at(event3Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(event4Id)],
newMetricProducers[newMetricProducerMap.at(event4Id)]);
// Verify the conditionToMetricMap.
ASSERT_EQ(conditionToMetricMap.size(), 2);
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(event2Index, event4Index));
const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
EXPECT_THAT(condition2Metrics, UnorderedElementsAre(event1Index, event6Index));
// Verify the trackerToMetricMap.
ASSERT_EQ(trackerToMetricMap.size(), 4);
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(event1Index));
const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(event2Index));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(event3Index, event6Index));
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(event4Index));
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 1);
EXPECT_THAT(activationAtomTrackerToMetricMap[matcher5Index],
UnorderedElementsAre(event3Index, event6Index));
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(metricsWithActivation.size(), 2);
EXPECT_THAT(metricsWithActivation, UnorderedElementsAre(event3Index, event6Index));
// Verify tracker indices/ids/conditions are correct.
EXPECT_EQ(newMetricProducers[event1Index]->getMetricId(), event1Id);
EXPECT_EQ(newMetricProducers[event1Index]->mConditionTrackerIndex, predicate2Index);
EXPECT_EQ(newMetricProducers[event1Index]->mCondition, ConditionState::kTrue);
EXPECT_EQ(newMetricProducers[event2Index]->getMetricId(), event2Id);
EXPECT_EQ(newMetricProducers[event2Index]->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(newMetricProducers[event2Index]->mCondition, ConditionState::kUnknown);
EXPECT_EQ(newMetricProducers[event3Index]->getMetricId(), event3Id);
EXPECT_EQ(newMetricProducers[event3Index]->mConditionTrackerIndex, -1);
EXPECT_EQ(newMetricProducers[event3Index]->mCondition, ConditionState::kTrue);
EXPECT_EQ(newMetricProducers[event4Index]->getMetricId(), event4Id);
EXPECT_EQ(newMetricProducers[event4Index]->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(newMetricProducers[event4Index]->mCondition, ConditionState::kUnknown);
EXPECT_EQ(newMetricProducers[event6Index]->getMetricId(), event6Id);
EXPECT_EQ(newMetricProducers[event6Index]->mConditionTrackerIndex, predicate2Index);
EXPECT_EQ(newMetricProducers[event6Index]->mCondition, ConditionState::kTrue);
sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
EXPECT_NE(newConditionWizard, oldConditionWizard);
EXPECT_EQ(newConditionWizard->getStrongCount(), newMetricProducers.size() + 1);
oldMetricProducers.clear();
// Only reference to the old wizard should be the one in the test.
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
}
TEST_F(ConfigUpdateTest, TestUpdateCountMetrics) {
StatsdConfig config;
// Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher();
int64_t matcher5Id = matcher5.id();
*config.add_atom_matcher() = matcher5;
Predicate predicate1 = CreateScreenIsOnPredicate();
int64_t predicate1Id = predicate1.id();
*config.add_predicate() = predicate1;
State state1 = CreateScreenStateWithOnOffMap(0x123, 0x321);
int64_t state1Id = state1.id();
*config.add_state() = state1;
State state2 = CreateScreenState();
int64_t state2Id = state2.id();
*config.add_state() = state2;
// Add a few count metrics.
// Will be preserved.
CountMetric count1 = createCountMetric("COUNT1", matcher1Id, predicate1Id, {state1Id});
int64_t count1Id = count1.id();
*config.add_count_metric() = count1;
// Will be replaced.
CountMetric count2 = createCountMetric("COUNT2", matcher2Id, nullopt, {});
int64_t count2Id = count2.id();
*config.add_count_metric() = count2;
// Will be replaced.
CountMetric count3 = createCountMetric("COUNT3", matcher3Id, nullopt, {});
int64_t count3Id = count3.id();
*config.add_count_metric() = count3;
// Will be replaced.
CountMetric count4 = createCountMetric("COUNT4", matcher4Id, nullopt, {state2Id});
int64_t count4Id = count4.id();
*config.add_count_metric() = count4;
// Will be deleted.
CountMetric count5 = createCountMetric("COUNT5", matcher5Id, nullopt, {});
int64_t count5Id = count5.id();
*config.add_count_metric() = count5;
EXPECT_TRUE(initConfig(config));
// Change bucket size of count2, causing it to be replaced.
count2.set_bucket(ONE_HOUR);
// Mark matcher 3 as replaced. Causes count3 to be replaced.
set<int64_t> replacedMatchers;
replacedMatchers.insert(matcher3Id);
// Mark state 2 as replaced and change the state to be about a different atom.
// Causes count4 to be replaced.
set<int64_t> replacedStates;
replacedStates.insert(state2Id);
state2.set_atom_id(util::BATTERY_SAVER_MODE_STATE_CHANGED);
// Fake that predicate 1 is true for count metric 1.
ASSERT_EQ(oldMetricProducers[0]->getMetricId(), count1Id);
oldMetricProducers[0]->onConditionChanged(true, /*timestamp=*/0);
EXPECT_EQ(oldMetricProducers[0]->mCondition, ConditionState::kTrue);
EXPECT_EQ(StateManager::getInstance().getStateTrackersCount(), 1);
// Tell the StateManager that the screen is on.
unique_ptr<LogEvent> event =
CreateScreenStateChangedEvent(0, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
StateManager::getInstance().onLogEvent(*event);
// New count metric. Should have an initial condition of true since it depends on predicate1.
CountMetric count6 = createCountMetric("EVENT6", matcher2Id, predicate1Id, {state1Id});
int64_t count6Id = count6.id();
// Map the matchers and predicates in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher5Index = 0;
newAtomMatchingTrackerMap[matcher5Id] = 0;
const int matcher4Index = 1;
newAtomMatchingTrackerMap[matcher4Id] = 1;
const int matcher3Index = 2;
newAtomMatchingTrackerMap[matcher3Id] = 2;
const int matcher2Index = 3;
newAtomMatchingTrackerMap[matcher2Id] = 3;
const int matcher1Index = 4;
newAtomMatchingTrackerMap[matcher1Id] = 4;
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
std::unordered_map<int64_t, int> newConditionTrackerMap;
const int predicate1Index = 0;
newConditionTrackerMap[predicate1Id] = 0;
// Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
vector<sp<ConditionTracker>> newConditionTrackers(1);
std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
newConditionTrackers.begin());
// Fake that predicate1 is true for all new metrics.
vector<ConditionState> conditionCache = {ConditionState::kTrue};
StatsdConfig newConfig;
*newConfig.add_count_metric() = count6;
const int count6Index = 0;
*newConfig.add_count_metric() = count3;
const int count3Index = 1;
*newConfig.add_count_metric() = count1;
const int count1Index = 2;
*newConfig.add_count_metric() = count4;
const int count4Index = 3;
*newConfig.add_count_metric() = count2;
const int count2Index = 4;
*newConfig.add_state() = state1;
*newConfig.add_state() = state2;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
map<int64_t, uint64_t> stateProtoHashes;
EXPECT_EQ(initStates(newConfig, stateAtomIdMap, allStateGroupMaps, stateProtoHashes), nullopt);
EXPECT_EQ(stateAtomIdMap[state2Id], util::BATTERY_SAVER_MODE_STATE_CHANGED);
// Output data structures to validate.
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, /*replacedConditions=*/{}, newConditionTrackers,
conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
{count1Id, count1Index}, {count2Id, count2Index}, {count3Id, count3Index},
{count4Id, count4Index}, {count6Id, count6Index},
};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
EXPECT_EQ(replacedMetrics, set<int64_t>({count2Id, count3Id, count4Id}));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 5);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(count1Id)],
newMetricProducers[newMetricProducerMap.at(count1Id)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(count2Id)],
newMetricProducers[newMetricProducerMap.at(count2Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(count3Id)],
newMetricProducers[newMetricProducerMap.at(count3Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(count4Id)],
newMetricProducers[newMetricProducerMap.at(count4Id)]);
// Verify the conditionToMetricMap.
ASSERT_EQ(conditionToMetricMap.size(), 1);
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(count1Index, count6Index));
// Verify the trackerToMetricMap.
ASSERT_EQ(trackerToMetricMap.size(), 4);
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(count1Index));
const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(count2Index, count6Index));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(count3Index));
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(count4Index));
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(metricsWithActivation.size(), 0);
// Verify tracker indices/ids/conditions/states are correct.
EXPECT_EQ(newMetricProducers[count1Index]->getMetricId(), count1Id);
EXPECT_EQ(newMetricProducers[count1Index]->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(newMetricProducers[count1Index]->mCondition, ConditionState::kTrue);
EXPECT_THAT(newMetricProducers[count1Index]->getSlicedStateAtoms(),
UnorderedElementsAre(util::SCREEN_STATE_CHANGED));
EXPECT_EQ(newMetricProducers[count2Index]->getMetricId(), count2Id);
EXPECT_EQ(newMetricProducers[count2Index]->mConditionTrackerIndex, -1);
EXPECT_EQ(newMetricProducers[count2Index]->mCondition, ConditionState::kTrue);
EXPECT_TRUE(newMetricProducers[count2Index]->getSlicedStateAtoms().empty());
EXPECT_EQ(newMetricProducers[count3Index]->getMetricId(), count3Id);
EXPECT_EQ(newMetricProducers[count3Index]->mConditionTrackerIndex, -1);
EXPECT_EQ(newMetricProducers[count3Index]->mCondition, ConditionState::kTrue);
EXPECT_TRUE(newMetricProducers[count3Index]->getSlicedStateAtoms().empty());
EXPECT_EQ(newMetricProducers[count4Index]->getMetricId(), count4Id);
EXPECT_EQ(newMetricProducers[count4Index]->mConditionTrackerIndex, -1);
EXPECT_EQ(newMetricProducers[count4Index]->mCondition, ConditionState::kTrue);
EXPECT_THAT(newMetricProducers[count4Index]->getSlicedStateAtoms(),
UnorderedElementsAre(util::BATTERY_SAVER_MODE_STATE_CHANGED));
EXPECT_EQ(newMetricProducers[count6Index]->getMetricId(), count6Id);
EXPECT_EQ(newMetricProducers[count6Index]->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(newMetricProducers[count6Index]->mCondition, ConditionState::kTrue);
EXPECT_THAT(newMetricProducers[count6Index]->getSlicedStateAtoms(),
UnorderedElementsAre(util::SCREEN_STATE_CHANGED));
oldMetricProducers.clear();
// Ensure that the screen state StateTracker did not get deleted and replaced.
EXPECT_EQ(StateManager::getInstance().getStateTrackersCount(), 2);
FieldValue screenState;
StateManager::getInstance().getStateValue(util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY,
&screenState);
EXPECT_EQ(screenState.mValue.int_value, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
}
TEST_F(ConfigUpdateTest, TestUpdateGaugeMetrics) {
StatsdConfig config;
// Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateTemperatureAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
AtomMatcher matcher5 = CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
int64_t matcher5Id = matcher5.id();
*config.add_atom_matcher() = matcher5;
Predicate predicate1 = CreateScreenIsOnPredicate();
int64_t predicate1Id = predicate1.id();
*config.add_predicate() = predicate1;
// Add a few gauge metrics.
// Will be preserved.
GaugeMetric gauge1 = createGaugeMetric("GAUGE1", matcher4Id, GaugeMetric::FIRST_N_SAMPLES,
predicate1Id, matcher1Id);
int64_t gauge1Id = gauge1.id();
*config.add_gauge_metric() = gauge1;
// Will be replaced.
GaugeMetric gauge2 =
createGaugeMetric("GAUGE2", matcher1Id, GaugeMetric::FIRST_N_SAMPLES, nullopt, nullopt);
int64_t gauge2Id = gauge2.id();
*config.add_gauge_metric() = gauge2;
// Will be replaced.
GaugeMetric gauge3 = createGaugeMetric("GAUGE3", matcher5Id, GaugeMetric::FIRST_N_SAMPLES,
nullopt, matcher3Id);
int64_t gauge3Id = gauge3.id();
*config.add_gauge_metric() = gauge3;
// Will be replaced.
GaugeMetric gauge4 = createGaugeMetric("GAUGE4", matcher3Id, GaugeMetric::RANDOM_ONE_SAMPLE,
predicate1Id, nullopt);
int64_t gauge4Id = gauge4.id();
*config.add_gauge_metric() = gauge4;
// Will be deleted.
GaugeMetric gauge5 =
createGaugeMetric("GAUGE5", matcher2Id, GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, {});
int64_t gauge5Id = gauge5.id();
*config.add_gauge_metric() = gauge5;
EXPECT_TRUE(initConfig(config));
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
sp<EventMatcherWizard> oldMatcherWizard =
static_cast<GaugeMetricProducer*>(oldMetricProducers[0].get())->mEventMatcherWizard;
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 6);
// Change gauge2, causing it to be replaced.
gauge2.set_max_num_gauge_atoms_per_bucket(50);
// Mark matcher 3 as replaced. Causes gauge3 and gauge4 to be replaced.
set<int64_t> replacedMatchers = {matcher3Id};
// New gauge metric.
GaugeMetric gauge6 = createGaugeMetric("GAUGE6", matcher5Id, GaugeMetric::FIRST_N_SAMPLES,
predicate1Id, matcher3Id);
int64_t gauge6Id = gauge6.id();
// Map the matchers and predicates in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher5Index = 0;
newAtomMatchingTrackerMap[matcher5Id] = 0;
const int matcher4Index = 1;
newAtomMatchingTrackerMap[matcher4Id] = 1;
const int matcher3Index = 2;
newAtomMatchingTrackerMap[matcher3Id] = 2;
const int matcher2Index = 3;
newAtomMatchingTrackerMap[matcher2Id] = 3;
const int matcher1Index = 4;
newAtomMatchingTrackerMap[matcher1Id] = 4;
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
std::unordered_map<int64_t, int> newConditionTrackerMap;
const int predicate1Index = 0;
newConditionTrackerMap[predicate1Id] = 0;
// Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
vector<sp<ConditionTracker>> newConditionTrackers(1);
std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
newConditionTrackers.begin());
// Say that predicate1 is unknown since the initial condition never changed.
vector<ConditionState> conditionCache = {ConditionState::kUnknown};
StatsdConfig newConfig;
*newConfig.add_gauge_metric() = gauge6;
const int gauge6Index = 0;
*newConfig.add_gauge_metric() = gauge3;
const int gauge3Index = 1;
*newConfig.add_gauge_metric() = gauge1;
const int gauge1Index = 2;
*newConfig.add_gauge_metric() = gauge4;
const int gauge4Index = 3;
*newConfig.add_gauge_metric() = gauge2;
const int gauge2Index = 4;
// Output data structures to validate.
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, /*replacedConditions=*/{}, newConditionTrackers,
conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
provider, newMetricProducerMap, newMetricProducers,
conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
metricsWithActivation, replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
{gauge1Id, gauge1Index}, {gauge2Id, gauge2Index}, {gauge3Id, gauge3Index},
{gauge4Id, gauge4Index}, {gauge6Id, gauge6Index},
};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
EXPECT_EQ(replacedMetrics, set<int64_t>({gauge2Id, gauge3Id, gauge4Id}));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 5);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(gauge1Id)],
newMetricProducers[newMetricProducerMap.at(gauge1Id)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(gauge2Id)],
newMetricProducers[newMetricProducerMap.at(gauge2Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(gauge3Id)],
newMetricProducers[newMetricProducerMap.at(gauge3Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(gauge4Id)],
newMetricProducers[newMetricProducerMap.at(gauge4Id)]);
// Verify the conditionToMetricMap.
ASSERT_EQ(conditionToMetricMap.size(), 1);
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(gauge1Index, gauge4Index, gauge6Index));
// Verify the trackerToMetricMap.
ASSERT_EQ(trackerToMetricMap.size(), 4);
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(gauge1Index, gauge2Index));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gauge3Index, gauge4Index, gauge6Index));
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(gauge1Index));
const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(gauge3Index, gauge6Index));
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(metricsWithActivation.size(), 0);
// Verify tracker indices/ids/conditions/states are correct.
GaugeMetricProducer* gaugeProducer1 =
static_cast<GaugeMetricProducer*>(newMetricProducers[gauge1Index].get());
EXPECT_EQ(gaugeProducer1->getMetricId(), gauge1Id);
EXPECT_EQ(gaugeProducer1->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(gaugeProducer1->mCondition, ConditionState::kUnknown);
EXPECT_EQ(gaugeProducer1->mWhatMatcherIndex, matcher4Index);
GaugeMetricProducer* gaugeProducer2 =
static_cast<GaugeMetricProducer*>(newMetricProducers[gauge2Index].get());
EXPECT_EQ(gaugeProducer2->getMetricId(), gauge2Id);
EXPECT_EQ(gaugeProducer2->mConditionTrackerIndex, -1);
EXPECT_EQ(gaugeProducer2->mCondition, ConditionState::kTrue);
EXPECT_EQ(gaugeProducer2->mWhatMatcherIndex, matcher1Index);
GaugeMetricProducer* gaugeProducer3 =
static_cast<GaugeMetricProducer*>(newMetricProducers[gauge3Index].get());
EXPECT_EQ(gaugeProducer3->getMetricId(), gauge3Id);
EXPECT_EQ(gaugeProducer3->mConditionTrackerIndex, -1);
EXPECT_EQ(gaugeProducer3->mCondition, ConditionState::kTrue);
EXPECT_EQ(gaugeProducer3->mWhatMatcherIndex, matcher5Index);
GaugeMetricProducer* gaugeProducer4 =
static_cast<GaugeMetricProducer*>(newMetricProducers[gauge4Index].get());
EXPECT_EQ(gaugeProducer4->getMetricId(), gauge4Id);
EXPECT_EQ(gaugeProducer4->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(gaugeProducer4->mCondition, ConditionState::kUnknown);
EXPECT_EQ(gaugeProducer4->mWhatMatcherIndex, matcher3Index);
GaugeMetricProducer* gaugeProducer6 =
static_cast<GaugeMetricProducer*>(newMetricProducers[gauge6Index].get());
EXPECT_EQ(gaugeProducer6->getMetricId(), gauge6Id);
EXPECT_EQ(gaugeProducer6->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(gaugeProducer6->mCondition, ConditionState::kUnknown);
EXPECT_EQ(gaugeProducer6->mWhatMatcherIndex, matcher5Index);
sp<EventMatcherWizard> newMatcherWizard = gaugeProducer1->mEventMatcherWizard;
EXPECT_NE(newMatcherWizard, oldMatcherWizard);
EXPECT_EQ(newMatcherWizard->getStrongCount(), 6);
oldMetricProducers.clear();
// Only reference to the old wizard should be the one in the test.
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 1);
}
TEST_F(ConfigUpdateTest, TestUpdateDurationMetrics) {
StatsdConfig config;
// Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateAcquireWakelockAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateReleaseWakelockAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
AtomMatcher matcher5 = CreateMoveToForegroundAtomMatcher();
int64_t matcher5Id = matcher5.id();
*config.add_atom_matcher() = matcher5;
AtomMatcher matcher6 = CreateMoveToBackgroundAtomMatcher();
int64_t matcher6Id = matcher6.id();
*config.add_atom_matcher() = matcher6;
AtomMatcher matcher7 = CreateBatteryStateNoneMatcher();
int64_t matcher7Id = matcher7.id();
*config.add_atom_matcher() = matcher7;
AtomMatcher matcher8 = CreateBatteryStateUsbMatcher();
int64_t matcher8Id = matcher8.id();
*config.add_atom_matcher() = matcher8;
Predicate predicate1 = CreateScreenIsOnPredicate();
int64_t predicate1Id = predicate1.id();
*config.add_predicate() = predicate1;
Predicate predicate2 = CreateScreenIsOffPredicate();
int64_t predicate2Id = predicate2.id();
*config.add_predicate() = predicate2;
Predicate predicate3 = CreateDeviceUnpluggedPredicate();
int64_t predicate3Id = predicate3.id();
*config.add_predicate() = predicate3;
Predicate predicate4 = CreateIsInBackgroundPredicate();
*predicate4.mutable_simple_predicate()->mutable_dimensions() =
CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1});
int64_t predicate4Id = predicate4.id();
*config.add_predicate() = predicate4;
Predicate predicate5 = CreateHoldingWakelockPredicate();
*predicate5.mutable_simple_predicate()->mutable_dimensions() =
CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
predicate5.mutable_simple_predicate()->set_stop_all(matcher7Id);
int64_t predicate5Id = predicate5.id();
*config.add_predicate() = predicate5;
State state1 = CreateScreenStateWithOnOffMap(0x123, 0x321);
int64_t state1Id = state1.id();
*config.add_state() = state1;
State state2 = CreateScreenState();
int64_t state2Id = state2.id();
*config.add_state() = state2;
// Add a few duration metrics.
// Will be preserved.
DurationMetric duration1 =
createDurationMetric("DURATION1", predicate5Id, predicate4Id, {state2Id});
*duration1.mutable_dimensions_in_what() =
CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
MetricConditionLink* link = duration1.add_links();
link->set_condition(predicate4Id);
*link->mutable_fields_in_what() =
CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
*link->mutable_fields_in_condition() =
CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
int64_t duration1Id = duration1.id();
*config.add_duration_metric() = duration1;
// Will be replaced.
DurationMetric duration2 = createDurationMetric("DURATION2", predicate1Id, nullopt, {});
int64_t duration2Id = duration2.id();
*config.add_duration_metric() = duration2;
// Will be replaced.
DurationMetric duration3 = createDurationMetric("DURATION3", predicate3Id, nullopt, {state1Id});
int64_t duration3Id = duration3.id();
*config.add_duration_metric() = duration3;
// Will be replaced.
DurationMetric duration4 = createDurationMetric("DURATION4", predicate3Id, predicate2Id, {});
int64_t duration4Id = duration4.id();
*config.add_duration_metric() = duration4;
// Will be deleted.
DurationMetric duration5 = createDurationMetric("DURATION5", predicate2Id, nullopt, {});
int64_t duration5Id = duration5.id();
*config.add_duration_metric() = duration5;
EXPECT_TRUE(initConfig(config));
// Make some sliced conditions true.
int uid1 = 10;
int uid2 = 11;
vector<MatchingState> matchingStates(8, MatchingState::kNotMatched);
matchingStates[2] = kMatched;
vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated);
vector<uint8_t> changedCache(5, false);
unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(timeBaseNs + 3, {uid1}, {"tag"}, "wl1");
oldConditionTrackers[4]->evaluateCondition(*event.get(), matchingStates, oldConditionTrackers,
conditionCache, changedCache);
EXPECT_TRUE(oldConditionTrackers[4]->isSliced());
EXPECT_TRUE(changedCache[4]);
EXPECT_EQ(conditionCache[4], ConditionState::kTrue);
oldMetricProducers[0]->onMatchedLogEvent(2, *event.get());
fill(conditionCache.begin(), conditionCache.end(), ConditionState::kNotEvaluated);
fill(changedCache.begin(), changedCache.end(), false);
event = CreateAcquireWakelockEvent(timeBaseNs + 3, {uid2}, {"tag"}, "wl2");
oldConditionTrackers[4]->evaluateCondition(*event.get(), matchingStates, oldConditionTrackers,
conditionCache, changedCache);
EXPECT_TRUE(changedCache[4]);
EXPECT_EQ(conditionCache[4], ConditionState::kTrue);
oldMetricProducers[0]->onMatchedLogEvent(2, *event.get());
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
// The duration trackers have a pointer to the wizard, and 2 trackers were created above.
sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard;
EXPECT_EQ(oldConditionWizard->getStrongCount(), 8);
// Replace predicate1, predicate3, and state1. Causes duration2/3/4 to be replaced.
set<int64_t> replacedConditions({predicate1Id, predicate2Id});
set<int64_t> replacedStates({state1Id});
// New duration metric.
DurationMetric duration6 = createDurationMetric("DURATION6", predicate4Id, predicate5Id, {});
*duration6.mutable_dimensions_in_what() =
CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
link = duration6.add_links();
link->set_condition(predicate5Id);
*link->mutable_fields_in_what() =
CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
*link->mutable_fields_in_condition() =
CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
int64_t duration6Id = duration6.id();
// Map the matchers and predicates in reverse order to force the indices to change.
const int matcher8Index = 0, matcher7Index = 1, matcher6Index = 2, matcher5Index = 3,
matcher4Index = 4, matcher3Index = 5, matcher2Index = 6, matcher1Index = 7;
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap({{matcher8Id, matcher8Index},
{matcher7Id, matcher7Index},
{matcher6Id, matcher6Index},
{matcher5Id, matcher5Index},
{matcher4Id, matcher4Index},
{matcher3Id, matcher3Index},
{matcher2Id, matcher2Index},
{matcher1Id, matcher1Index}});
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(8);
reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
const int predicate5Index = 0, predicate4Index = 1, predicate3Index = 2, predicate2Index = 3,
predicate1Index = 4;
std::unordered_map<int64_t, int> newConditionTrackerMap({
{predicate5Id, predicate5Index},
{predicate4Id, predicate4Index},
{predicate3Id, predicate3Index},
{predicate2Id, predicate2Index},
{predicate1Id, predicate1Index},
});
// Use the existing conditionTrackers and reinitialize them to get the initial condition cache.
vector<sp<ConditionTracker>> newConditionTrackers(5);
reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
newConditionTrackers.begin());
vector<Predicate> conditionProtos(5);
reverse_copy(config.predicate().begin(), config.predicate().end(), conditionProtos.begin());
for (int i = 0; i < newConditionTrackers.size(); i++) {
EXPECT_EQ(newConditionTrackers[i]->onConfigUpdated(conditionProtos, i, newConditionTrackers,
newAtomMatchingTrackerMap,
newConditionTrackerMap),
nullopt);
}
vector<uint8_t> cycleTracker(5, false);
fill(conditionCache.begin(), conditionCache.end(), ConditionState::kNotEvaluated);
for (int i = 0; i < newConditionTrackers.size(); i++) {
EXPECT_EQ(
newConditionTrackers[i]->init(conditionProtos, newConditionTrackers,
newConditionTrackerMap, cycleTracker, conditionCache),
nullopt);
}
// Predicate5 should be true since 2 uids have wakelocks
EXPECT_EQ(conditionCache, vector({kTrue, kFalse, kUnknown, kUnknown, kUnknown}));
StatsdConfig newConfig;
*newConfig.add_duration_metric() = duration6;
const int duration6Index = 0;
*newConfig.add_duration_metric() = duration3;
const int duration3Index = 1;
*newConfig.add_duration_metric() = duration1;
const int duration1Index = 2;
*newConfig.add_duration_metric() = duration4;
const int duration4Index = 3;
*newConfig.add_duration_metric() = duration2;
const int duration2Index = 4;
for (const Predicate& predicate : conditionProtos) {
*newConfig.add_predicate() = predicate;
}
*newConfig.add_state() = state1;
*newConfig.add_state() = state2;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
map<int64_t, uint64_t> stateProtoHashes;
EXPECT_EQ(initStates(newConfig, stateAtomIdMap, allStateGroupMaps, stateProtoHashes), nullopt);
// Output data structures to validate.
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, /*replacedMatchers=*/{},
newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps,
replacedStates, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
{duration1Id, duration1Index}, {duration2Id, duration2Index},
{duration3Id, duration3Index}, {duration4Id, duration4Index},
{duration6Id, duration6Index},
};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
EXPECT_EQ(replacedMetrics, set<int64_t>({duration2Id, duration3Id, duration4Id}));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 5);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(duration1Id)],
newMetricProducers[newMetricProducerMap.at(duration1Id)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration2Id)],
newMetricProducers[newMetricProducerMap.at(duration2Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration3Id)],
newMetricProducers[newMetricProducerMap.at(duration3Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration4Id)],
newMetricProducers[newMetricProducerMap.at(duration4Id)]);
// Verify the conditionToMetricMap. Note that the "what" is not in this map.
ASSERT_EQ(conditionToMetricMap.size(), 3);
const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
EXPECT_THAT(condition2Metrics, UnorderedElementsAre(duration4Index));
const vector<int>& condition4Metrics = conditionToMetricMap[predicate4Index];
EXPECT_THAT(condition4Metrics, UnorderedElementsAre(duration1Index));
const vector<int>& condition5Metrics = conditionToMetricMap[predicate5Index];
EXPECT_THAT(condition5Metrics, UnorderedElementsAre(duration6Index));
// Verify the trackerToMetricMap. The start/stop/stopall indices from the "what" should be here.
ASSERT_EQ(trackerToMetricMap.size(), 8);
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(duration2Index));
const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(duration2Index));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(duration1Index));
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(duration1Index));
const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(duration6Index));
const vector<int>& matcher6Metrics = trackerToMetricMap[matcher6Index];
EXPECT_THAT(matcher6Metrics, UnorderedElementsAre(duration6Index));
const vector<int>& matcher7Metrics = trackerToMetricMap[matcher7Index];
EXPECT_THAT(matcher7Metrics,
UnorderedElementsAre(duration1Index, duration3Index, duration4Index));
const vector<int>& matcher8Metrics = trackerToMetricMap[matcher8Index];
EXPECT_THAT(matcher8Metrics, UnorderedElementsAre(duration3Index, duration4Index));
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(metricsWithActivation.size(), 0);
// Verify tracker indices/ids/conditions are correct.
DurationMetricProducer* durationProducer1 =
static_cast<DurationMetricProducer*>(newMetricProducers[duration1Index].get());
EXPECT_EQ(durationProducer1->getMetricId(), duration1Id);
EXPECT_EQ(durationProducer1->mConditionTrackerIndex, predicate4Index);
EXPECT_EQ(durationProducer1->mCondition, ConditionState::kFalse);
EXPECT_EQ(durationProducer1->mStartIndex, matcher3Index);
EXPECT_EQ(durationProducer1->mStopIndex, matcher4Index);
EXPECT_EQ(durationProducer1->mStopAllIndex, matcher7Index);
EXPECT_EQ(durationProducer1->mCurrentSlicedDurationTrackerMap.size(), 2);
for (const auto& durationTrackerIt : durationProducer1->mCurrentSlicedDurationTrackerMap) {
EXPECT_EQ(durationTrackerIt.second->mConditionTrackerIndex, predicate4Index);
}
DurationMetricProducer* durationProducer2 =
static_cast<DurationMetricProducer*>(newMetricProducers[duration2Index].get());
EXPECT_EQ(durationProducer2->getMetricId(), duration2Id);
EXPECT_EQ(durationProducer2->mConditionTrackerIndex, -1);
EXPECT_EQ(durationProducer2->mCondition, ConditionState::kTrue);
EXPECT_EQ(durationProducer2->mStartIndex, matcher1Index);
EXPECT_EQ(durationProducer2->mStopIndex, matcher2Index);
EXPECT_EQ(durationProducer2->mStopAllIndex, -1);
DurationMetricProducer* durationProducer3 =
static_cast<DurationMetricProducer*>(newMetricProducers[duration3Index].get());
EXPECT_EQ(durationProducer3->getMetricId(), duration3Id);
EXPECT_EQ(durationProducer3->mConditionTrackerIndex, -1);
EXPECT_EQ(durationProducer3->mCondition, ConditionState::kTrue);
EXPECT_EQ(durationProducer3->mStartIndex, matcher7Index);
EXPECT_EQ(durationProducer3->mStopIndex, matcher8Index);
EXPECT_EQ(durationProducer3->mStopAllIndex, -1);
DurationMetricProducer* durationProducer4 =
static_cast<DurationMetricProducer*>(newMetricProducers[duration4Index].get());
EXPECT_EQ(durationProducer4->getMetricId(), duration4Id);
EXPECT_EQ(durationProducer4->mConditionTrackerIndex, predicate2Index);
EXPECT_EQ(durationProducer4->mCondition, ConditionState::kUnknown);
EXPECT_EQ(durationProducer4->mStartIndex, matcher7Index);
EXPECT_EQ(durationProducer4->mStopIndex, matcher8Index);
EXPECT_EQ(durationProducer4->mStopAllIndex, -1);
DurationMetricProducer* durationProducer6 =
static_cast<DurationMetricProducer*>(newMetricProducers[duration6Index].get());
EXPECT_EQ(durationProducer6->getMetricId(), duration6Id);
EXPECT_EQ(durationProducer6->mConditionTrackerIndex, predicate5Index);
// TODO(b/167491517): should this be unknown since the condition is sliced?
EXPECT_EQ(durationProducer6->mCondition, ConditionState::kTrue);
EXPECT_EQ(durationProducer6->mStartIndex, matcher6Index);
EXPECT_EQ(durationProducer6->mStopIndex, matcher5Index);
EXPECT_EQ(durationProducer6->mStopAllIndex, -1);
sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
EXPECT_NE(newConditionWizard, oldConditionWizard);
EXPECT_EQ(newConditionWizard->getStrongCount(), 8);
oldMetricProducers.clear();
// Only reference to the old wizard should be the one in the test.
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
}
TEST_F(ConfigUpdateTest, TestUpdateValueMetrics) {
StatsdConfig config;
// Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateTemperatureAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
AtomMatcher matcher5 = CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
int64_t matcher5Id = matcher5.id();
*config.add_atom_matcher() = matcher5;
Predicate predicate1 = CreateScreenIsOnPredicate();
int64_t predicate1Id = predicate1.id();
*config.add_predicate() = predicate1;
Predicate predicate2 = CreateScreenIsOffPredicate();
int64_t predicate2Id = predicate2.id();
*config.add_predicate() = predicate2;
State state1 = CreateScreenStateWithOnOffMap(0x123, 0x321);
int64_t state1Id = state1.id();
*config.add_state() = state1;
State state2 = CreateScreenState();
int64_t state2Id = state2.id();
*config.add_state() = state2;
// Add a few value metrics.
// Note that these will not work as "real" metrics since the value field is always 2.
// Will be preserved.
ValueMetric value1 = createValueMetric("VALUE1", matcher4, 2, predicate1Id, {state1Id});
int64_t value1Id = value1.id();
*config.add_value_metric() = value1;
// Will be replaced - definition change.
ValueMetric value2 = createValueMetric("VALUE2", matcher1, 2, nullopt, {});
int64_t value2Id = value2.id();
*config.add_value_metric() = value2;
// Will be replaced - condition change.
ValueMetric value3 = createValueMetric("VALUE3", matcher5, 2, predicate2Id, {});
int64_t value3Id = value3.id();
*config.add_value_metric() = value3;
// Will be replaced - state change.
ValueMetric value4 = createValueMetric("VALUE4", matcher3, 2, nullopt, {state2Id});
int64_t value4Id = value4.id();
*config.add_value_metric() = value4;
// Will be deleted.
ValueMetric value5 = createValueMetric("VALUE5", matcher2, 2, nullopt, {});
int64_t value5Id = value5.id();
*config.add_value_metric() = value5;
EXPECT_TRUE(initConfig(config));
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
sp<EventMatcherWizard> oldMatcherWizard =
static_cast<NumericValueMetricProducer*>(oldMetricProducers[0].get())
->mEventMatcherWizard;
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 6);
// Change value2, causing it to be replaced.
value2.set_aggregation_type(ValueMetric::AVG);
// Mark predicate 2 as replaced. Causes value3 to be replaced.
set<int64_t> replacedConditions = {predicate2Id};
// Mark state 2 as replaced. Causes value4 to be replaced.
set<int64_t> replacedStates = {state2Id};
// New value metric.
ValueMetric value6 = createValueMetric("VALUE6", matcher5, 2, predicate1Id, {state1Id});
int64_t value6Id = value6.id();
// Map the matchers and predicates in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher5Index = 0;
newAtomMatchingTrackerMap[matcher5Id] = 0;
const int matcher4Index = 1;
newAtomMatchingTrackerMap[matcher4Id] = 1;
const int matcher3Index = 2;
newAtomMatchingTrackerMap[matcher3Id] = 2;
const int matcher2Index = 3;
newAtomMatchingTrackerMap[matcher2Id] = 3;
const int matcher1Index = 4;
newAtomMatchingTrackerMap[matcher1Id] = 4;
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
std::unordered_map<int64_t, int> newConditionTrackerMap;
const int predicate2Index = 0;
newConditionTrackerMap[predicate2Id] = 0;
const int predicate1Index = 1;
newConditionTrackerMap[predicate1Id] = 1;
// Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
vector<sp<ConditionTracker>> newConditionTrackers(2);
std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
newConditionTrackers.begin());
// Say that predicate1 & predicate2 is unknown since the initial condition never changed.
vector<ConditionState> conditionCache = {ConditionState::kUnknown, ConditionState::kUnknown};
StatsdConfig newConfig;
*newConfig.add_value_metric() = value6;
const int value6Index = 0;
*newConfig.add_value_metric() = value3;
const int value3Index = 1;
*newConfig.add_value_metric() = value1;
const int value1Index = 2;
*newConfig.add_value_metric() = value4;
const int value4Index = 3;
*newConfig.add_value_metric() = value2;
const int value2Index = 4;
*newConfig.add_state() = state1;
*newConfig.add_state() = state2;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
map<int64_t, uint64_t> stateProtoHashes;
EXPECT_EQ(initStates(newConfig, stateAtomIdMap, allStateGroupMaps, stateProtoHashes), nullopt);
// Output data structures to validate.
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, /*replacedMatchers=*/{},
newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps,
replacedStates, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
{value1Id, value1Index}, {value2Id, value2Index}, {value3Id, value3Index},
{value4Id, value4Index}, {value6Id, value6Index},
};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
EXPECT_EQ(replacedMetrics, set<int64_t>({value2Id, value3Id, value4Id}));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 5);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(value1Id)],
newMetricProducers[newMetricProducerMap.at(value1Id)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value2Id)],
newMetricProducers[newMetricProducerMap.at(value2Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value3Id)],
newMetricProducers[newMetricProducerMap.at(value3Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value4Id)],
newMetricProducers[newMetricProducerMap.at(value4Id)]);
// Verify the conditionToMetricMap.
ASSERT_EQ(conditionToMetricMap.size(), 2);
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(value1Index, value6Index));
const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
EXPECT_THAT(condition2Metrics, UnorderedElementsAre(value3Index));
// Verify the trackerToMetricMap.
ASSERT_EQ(trackerToMetricMap.size(), 4);
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(value2Index));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(value4Index));
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(value1Index));
const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(value3Index, value6Index));
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(metricsWithActivation.size(), 0);
// Verify tracker indices/ids/conditions/states are correct.
NumericValueMetricProducer* valueProducer1 =
static_cast<NumericValueMetricProducer*>(newMetricProducers[value1Index].get());
EXPECT_EQ(valueProducer1->getMetricId(), value1Id);
EXPECT_EQ(valueProducer1->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(valueProducer1->mCondition, ConditionState::kUnknown);
EXPECT_EQ(valueProducer1->mWhatMatcherIndex, matcher4Index);
NumericValueMetricProducer* valueProducer2 =
static_cast<NumericValueMetricProducer*>(newMetricProducers[value2Index].get());
EXPECT_EQ(valueProducer2->getMetricId(), value2Id);
EXPECT_EQ(valueProducer2->mConditionTrackerIndex, -1);
EXPECT_EQ(valueProducer2->mCondition, ConditionState::kTrue);
EXPECT_EQ(valueProducer2->mWhatMatcherIndex, matcher1Index);
NumericValueMetricProducer* valueProducer3 =
static_cast<NumericValueMetricProducer*>(newMetricProducers[value3Index].get());
EXPECT_EQ(valueProducer3->getMetricId(), value3Id);
EXPECT_EQ(valueProducer3->mConditionTrackerIndex, predicate2Index);
EXPECT_EQ(valueProducer3->mCondition, ConditionState::kUnknown);
EXPECT_EQ(valueProducer3->mWhatMatcherIndex, matcher5Index);
NumericValueMetricProducer* valueProducer4 =
static_cast<NumericValueMetricProducer*>(newMetricProducers[value4Index].get());
EXPECT_EQ(valueProducer4->getMetricId(), value4Id);
EXPECT_EQ(valueProducer4->mConditionTrackerIndex, -1);
EXPECT_EQ(valueProducer4->mCondition, ConditionState::kTrue);
EXPECT_EQ(valueProducer4->mWhatMatcherIndex, matcher3Index);
NumericValueMetricProducer* valueProducer6 =
static_cast<NumericValueMetricProducer*>(newMetricProducers[value6Index].get());
EXPECT_EQ(valueProducer6->getMetricId(), value6Id);
EXPECT_EQ(valueProducer6->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(valueProducer6->mCondition, ConditionState::kUnknown);
EXPECT_EQ(valueProducer6->mWhatMatcherIndex, matcher5Index);
sp<EventMatcherWizard> newMatcherWizard = valueProducer1->mEventMatcherWizard;
EXPECT_NE(newMatcherWizard, oldMatcherWizard);
EXPECT_EQ(newMatcherWizard->getStrongCount(), 6);
oldMetricProducers.clear();
// Only reference to the old wizard should be the one in the test.
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 1);
}
TEST_F(ConfigUpdateTest, TestUpdateKllMetrics) {
StatsdConfig config;
// Add atom matchers/predicates. These are mostly needed for initStatsdConfig.
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateAppStartOccurredAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
AtomMatcher matcher5 = CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
int64_t matcher5Id = matcher5.id();
*config.add_atom_matcher() = matcher5;
Predicate predicate1 = CreateScreenIsOnPredicate();
int64_t predicate1Id = predicate1.id();
*config.add_predicate() = predicate1;
Predicate predicate2 = CreateScreenIsOffPredicate();
int64_t predicate2Id = predicate2.id();
*config.add_predicate() = predicate2;
// Add a few kll metrics.
// Note that these will not work as "real" metrics since the value field is always 2.
// Will be preserved.
KllMetric kll1 = createKllMetric("KLL1", matcher4, /*valueField=*/2, predicate1Id);
int64_t kll1Id = kll1.id();
*config.add_kll_metric() = kll1;
// Will be replaced - definition change.
KllMetric kll2 = createKllMetric("KLL2", matcher1, /*valueField=*/2, nullopt);
int64_t kll2Id = kll2.id();
*config.add_kll_metric() = kll2;
// Will be replaced - condition change.
KllMetric kll3 = createKllMetric("KLL3", matcher5, /*valueField=*/2, predicate2Id);
int64_t kll3Id = kll3.id();
*config.add_kll_metric() = kll3;
// Will be preserved.
KllMetric kll4 = createKllMetric("KLL", matcher3, /*valueField=*/2, nullopt);
int64_t kll4Id = kll4.id();
*config.add_kll_metric() = kll4;
// Will be deleted.
KllMetric kll5 = createKllMetric("KLL5", matcher2, /*valueField=*/2, nullopt);
int64_t kll5Id = kll5.id();
*config.add_kll_metric() = kll5;
ASSERT_TRUE(initConfig(config));
// Change kll2, causing it to be replaced.
kll2.set_split_bucket_for_app_upgrade(false);
// Mark predicate 2 as replaced. Causes kll3 to be replaced.
set<int64_t> replacedConditions = {predicate2Id};
// New kll metric.
KllMetric kll6 = createKllMetric("KLL6", matcher5, /*valueField=*/2, predicate1Id);
int64_t kll6Id = kll6.id();
// Map the matchers and predicates in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher5Index = 0;
newAtomMatchingTrackerMap[matcher5Id] = 0;
const int matcher4Index = 1;
newAtomMatchingTrackerMap[matcher4Id] = 1;
const int matcher3Index = 2;
newAtomMatchingTrackerMap[matcher3Id] = 2;
const int matcher2Index = 3;
newAtomMatchingTrackerMap[matcher2Id] = 3;
const int matcher1Index = 4;
newAtomMatchingTrackerMap[matcher1Id] = 4;
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
std::unordered_map<int64_t, int> newConditionTrackerMap;
const int predicate2Index = 0;
newConditionTrackerMap[predicate2Id] = 0;
const int predicate1Index = 1;
newConditionTrackerMap[predicate1Id] = 1;
// Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
vector<sp<ConditionTracker>> newConditionTrackers(2);
std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
newConditionTrackers.begin());
// Say that predicate1 & predicate2 is unknown since the initial condition never changed.
vector<ConditionState> conditionCache = {ConditionState::kUnknown, ConditionState::kUnknown};
StatsdConfig newConfig;
*newConfig.add_kll_metric() = kll6;
const int kll6Index = 0;
*newConfig.add_kll_metric() = kll3;
const int kll3Index = 1;
*newConfig.add_kll_metric() = kll1;
const int kll1Index = 2;
*newConfig.add_kll_metric() = kll4;
const int kll4Index = 3;
*newConfig.add_kll_metric() = kll2;
const int kll2Index = 4;
// Output data structures to validate.
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(
key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, /*replacedMatchers=*/{}, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation, replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
{kll1Id, kll1Index}, {kll2Id, kll2Index}, {kll3Id, kll3Index},
{kll4Id, kll4Index}, {kll6Id, kll6Index},
};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
EXPECT_EQ(replacedMetrics, set<int64_t>({kll2Id, kll3Id}));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 5);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(kll1Id)],
newMetricProducers[newMetricProducerMap.at(kll1Id)]);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(kll4Id)],
newMetricProducers[newMetricProducerMap.at(kll4Id)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(kll2Id)],
newMetricProducers[newMetricProducerMap.at(kll2Id)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(kll3Id)],
newMetricProducers[newMetricProducerMap.at(kll3Id)]);
// Verify the conditionToMetricMap.
ASSERT_EQ(conditionToMetricMap.size(), 2);
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(kll1Index, kll6Index));
const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
EXPECT_THAT(condition2Metrics, UnorderedElementsAre(kll3Index));
// Verify the trackerToMetricMap.
ASSERT_EQ(trackerToMetricMap.size(), 4);
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(kll2Index));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(kll4Index));
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(kll1Index));
const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(kll3Index, kll6Index));
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(metricsWithActivation.size(), 0);
// Verify tracker indices/ids/conditions are correct.
KllMetricProducer* kllProducer1 =
static_cast<KllMetricProducer*>(newMetricProducers[kll1Index].get());
EXPECT_EQ(kllProducer1->getMetricId(), kll1Id);
EXPECT_EQ(kllProducer1->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(kllProducer1->mCondition, ConditionState::kUnknown);
EXPECT_EQ(kllProducer1->mWhatMatcherIndex, matcher4Index);
KllMetricProducer* kllProducer2 =
static_cast<KllMetricProducer*>(newMetricProducers[kll2Index].get());
EXPECT_EQ(kllProducer2->getMetricId(), kll2Id);
EXPECT_EQ(kllProducer2->mConditionTrackerIndex, -1);
EXPECT_EQ(kllProducer2->mCondition, ConditionState::kTrue);
EXPECT_EQ(kllProducer2->mWhatMatcherIndex, matcher1Index);
KllMetricProducer* kllProducer3 =
static_cast<KllMetricProducer*>(newMetricProducers[kll3Index].get());
EXPECT_EQ(kllProducer3->getMetricId(), kll3Id);
EXPECT_EQ(kllProducer3->mConditionTrackerIndex, predicate2Index);
EXPECT_EQ(kllProducer3->mCondition, ConditionState::kUnknown);
EXPECT_EQ(kllProducer3->mWhatMatcherIndex, matcher5Index);
KllMetricProducer* kllProducer4 =
static_cast<KllMetricProducer*>(newMetricProducers[kll4Index].get());
EXPECT_EQ(kllProducer4->getMetricId(), kll4Id);
EXPECT_EQ(kllProducer4->mConditionTrackerIndex, -1);
EXPECT_EQ(kllProducer4->mCondition, ConditionState::kTrue);
EXPECT_EQ(kllProducer4->mWhatMatcherIndex, matcher3Index);
KllMetricProducer* kllProducer6 =
static_cast<KllMetricProducer*>(newMetricProducers[kll6Index].get());
EXPECT_EQ(kllProducer6->getMetricId(), kll6Id);
EXPECT_EQ(kllProducer6->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(kllProducer6->mCondition, ConditionState::kUnknown);
EXPECT_EQ(kllProducer6->mWhatMatcherIndex, matcher5Index);
oldMetricProducers.clear();
}
TEST_F(ConfigUpdateTest, TestUpdateMetricActivations) {
StatsdConfig config;
// Add atom matchers
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
int64_t matcher4Id = matcher4.id();
*config.add_atom_matcher() = matcher4;
// Add an event metric with multiple activations.
EventMetric event1 = createEventMetric("EVENT1", matcher1Id, nullopt);
int64_t event1Id = event1.id();
*config.add_event_metric() = event1;
int64_t matcher2TtlSec = 2, matcher3TtlSec = 3, matcher4TtlSec = 4;
MetricActivation metricActivation;
metricActivation.set_metric_id(event1Id);
EventActivation* activation = metricActivation.add_event_activation();
activation->set_atom_matcher_id(matcher2Id);
activation->set_ttl_seconds(matcher2TtlSec);
activation->set_activation_type(ACTIVATE_IMMEDIATELY);
activation->set_deactivation_atom_matcher_id(matcher1Id);
activation = metricActivation.add_event_activation();
activation->set_atom_matcher_id(matcher3Id);
activation->set_ttl_seconds(matcher3TtlSec);
activation->set_activation_type(ACTIVATE_ON_BOOT);
activation->set_deactivation_atom_matcher_id(matcher1Id);
activation = metricActivation.add_event_activation();
activation->set_atom_matcher_id(matcher4Id);
activation->set_ttl_seconds(matcher4TtlSec);
activation->set_activation_type(ACTIVATE_IMMEDIATELY);
activation->set_deactivation_atom_matcher_id(matcher2Id);
*config.add_metric_activation() = metricActivation;
EXPECT_TRUE(initConfig(config));
// Activate some of the event activations.
ASSERT_EQ(oldMetricProducers[0]->getMetricId(), event1Id);
int64_t matcher2StartNs = 12345;
oldMetricProducers[0]->activate(oldAtomMatchingTrackerMap[matcher2Id], matcher2StartNs);
int64_t matcher3StartNs = 23456;
oldMetricProducers[0]->activate(oldAtomMatchingTrackerMap[matcher3Id], matcher3StartNs);
EXPECT_TRUE(oldMetricProducers[0]->isActive());
// Map the matchers and predicates in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher4Index = 0;
newAtomMatchingTrackerMap[matcher4Id] = 0;
const int matcher3Index = 1;
newAtomMatchingTrackerMap[matcher3Id] = 1;
const int matcher2Index = 2;
newAtomMatchingTrackerMap[matcher2Id] = 2;
const int matcher1Index = 3;
newAtomMatchingTrackerMap[matcher1Id] = 3;
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(4);
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
set<int64_t> replacedMatchers;
unordered_map<int64_t, int> newConditionTrackerMap;
vector<sp<ConditionTracker>> newConditionTrackers;
set<int64_t> replacedConditions;
vector<ConditionState> conditionCache;
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
provider, newMetricProducerMap, newMetricProducers,
conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
metricsWithActivation, replacedMetrics),
nullopt);
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 3);
EXPECT_THAT(activationAtomTrackerToMetricMap[matcher2Index], UnorderedElementsAre(0));
EXPECT_THAT(activationAtomTrackerToMetricMap[matcher3Index], UnorderedElementsAre(0));
EXPECT_THAT(activationAtomTrackerToMetricMap[matcher4Index], UnorderedElementsAre(0));
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 2);
EXPECT_THAT(deactivationAtomTrackerToMetricMap[matcher1Index], UnorderedElementsAre(0, 0));
EXPECT_THAT(deactivationAtomTrackerToMetricMap[matcher2Index], UnorderedElementsAre(0));
ASSERT_EQ(metricsWithActivation.size(), 1);
EXPECT_THAT(metricsWithActivation, UnorderedElementsAre(0));
// Verify mEventActivation and mEventDeactivation map of the producer.
sp<MetricProducer> producer = newMetricProducers[0];
EXPECT_TRUE(producer->isActive());
ASSERT_EQ(producer->mEventActivationMap.size(), 3);
shared_ptr<Activation> matcher2Activation = producer->mEventActivationMap[matcher2Index];
EXPECT_EQ(matcher2Activation->ttl_ns, matcher2TtlSec * NS_PER_SEC);
EXPECT_EQ(matcher2Activation->activationType, ACTIVATE_IMMEDIATELY);
EXPECT_EQ(matcher2Activation->state, kActive);
EXPECT_EQ(matcher2Activation->start_ns, matcher2StartNs);
shared_ptr<Activation> matcher3Activation = producer->mEventActivationMap[matcher3Index];
EXPECT_EQ(matcher3Activation->ttl_ns, matcher3TtlSec * NS_PER_SEC);
EXPECT_EQ(matcher3Activation->activationType, ACTIVATE_ON_BOOT);
EXPECT_EQ(matcher3Activation->state, kActiveOnBoot);
shared_ptr<Activation> matcher4Activation = producer->mEventActivationMap[matcher4Index];
EXPECT_EQ(matcher4Activation->ttl_ns, matcher4TtlSec * NS_PER_SEC);
EXPECT_EQ(matcher4Activation->activationType, ACTIVATE_IMMEDIATELY);
EXPECT_EQ(matcher4Activation->state, kNotActive);
ASSERT_EQ(producer->mEventDeactivationMap.size(), 2);
EXPECT_THAT(producer->mEventDeactivationMap[matcher1Index],
UnorderedElementsAre(matcher2Activation, matcher3Activation));
EXPECT_THAT(producer->mEventDeactivationMap[matcher2Index],
UnorderedElementsAre(matcher4Activation));
}
TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
StatsdConfig config;
// Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
int64_t matcher1Id = matcher1.id();
*config.add_atom_matcher() = matcher1;
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
int64_t matcher2Id = matcher2.id();
*config.add_atom_matcher() = matcher2;
AtomMatcher matcher3 = CreateTemperatureAtomMatcher();
int64_t matcher3Id = matcher3.id();
*config.add_atom_matcher() = matcher3;
Predicate predicate1 = CreateScreenIsOnPredicate();
int64_t predicate1Id = predicate1.id();
*config.add_predicate() = predicate1;
// Add a few count metrics.
// Will be preserved.
CountMetric countMetric = createCountMetric("COUNT1", matcher1Id, predicate1Id, {});
int64_t countMetricId = countMetric.id();
*config.add_count_metric() = countMetric;
// Will be replaced since matcher2 is replaced.
EventMetric eventMetric = createEventMetric("EVENT1", matcher2Id, nullopt);
int64_t eventMetricId = eventMetric.id();
*config.add_event_metric() = eventMetric;
// Will be replaced because the definition changes - a predicate is added.
GaugeMetric gaugeMetric = createGaugeMetric("GAUGE1", matcher3Id,
GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, nullopt);
int64_t gaugeMetricId = gaugeMetric.id();
*config.add_gauge_metric() = gaugeMetric;
// Preserved.
ValueMetric valueMetric = createValueMetric("VALUE1", matcher3, 2, predicate1Id, {});
int64_t valueMetricId = valueMetric.id();
*config.add_value_metric() = valueMetric;
// Preserved.
DurationMetric durationMetric = createDurationMetric("DURATION1", predicate1Id, nullopt, {});
int64_t durationMetricId = durationMetric.id();
*config.add_duration_metric() = durationMetric;
// Preserved.
KllMetric kllMetric = createKllMetric("KLL1", matcher3, /*valueField=*/2, predicate1Id);
int64_t kllMetricId = kllMetric.id();
*config.add_kll_metric() = kllMetric;
EXPECT_TRUE(initConfig(config));
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard;
EXPECT_EQ(oldConditionWizard->getStrongCount(), 7);
// Mark matcher 2 as replaced. Causes eventMetric to be replaced.
set<int64_t> replacedMatchers;
replacedMatchers.insert(matcher2Id);
// Add predicate1 as a predicate on gaugeMetric, causing it to be replaced.
gaugeMetric.set_condition(predicate1Id);
// Map the matchers and predicates in reverse order to force the indices to change.
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
const int matcher3Index = 0;
newAtomMatchingTrackerMap[matcher3Id] = 0;
const int matcher2Index = 1;
newAtomMatchingTrackerMap[matcher2Id] = 1;
const int matcher1Index = 2;
newAtomMatchingTrackerMap[matcher1Id] = 2;
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(3);
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
newAtomMatchingTrackers.begin());
std::unordered_map<int64_t, int> newConditionTrackerMap;
const int predicate1Index = 0;
newConditionTrackerMap[predicate1Id] = 0;
// Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
vector<sp<ConditionTracker>> newConditionTrackers(1);
std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
newConditionTrackers.begin());
vector<ConditionState> conditionCache = {ConditionState::kUnknown};
// The order matters. we parse in the order of: count, duration, event, value, gauge.
StatsdConfig newConfig;
*newConfig.add_count_metric() = countMetric;
const int countMetricIndex = 0;
*newConfig.add_duration_metric() = durationMetric;
const int durationMetricIndex = 1;
*newConfig.add_event_metric() = eventMetric;
const int eventMetricIndex = 2;
*newConfig.add_value_metric() = valueMetric;
const int valueMetricIndex = 3;
*newConfig.add_gauge_metric() = gaugeMetric;
const int gaugeMetricIndex = 4;
*newConfig.add_kll_metric() = kllMetric;
const int kllMetricIndex = 5;
// Add the predicate since duration metric needs it.
*newConfig.add_predicate() = predicate1;
// Output data structures to validate.
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, /*replacedConditions=*/{}, newConditionTrackers,
conditionCache, /*stateAtomIdMap*/ {}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers,
provider, newMetricProducerMap, newMetricProducers,
conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
metricsWithActivation, replacedMetrics),
nullopt);
unordered_map<int64_t, int> expectedMetricProducerMap = {
{countMetricId, countMetricIndex}, {durationMetricId, durationMetricIndex},
{eventMetricId, eventMetricIndex}, {valueMetricId, valueMetricIndex},
{gaugeMetricId, gaugeMetricIndex}, {kllMetricId, kllMetricIndex}};
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
EXPECT_EQ(replacedMetrics, set<int64_t>({eventMetricId, gaugeMetricId}));
// Make sure preserved metrics are the same.
ASSERT_EQ(newMetricProducers.size(), 6);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(countMetricId)],
newMetricProducers[newMetricProducerMap.at(countMetricId)]);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(durationMetricId)],
newMetricProducers[newMetricProducerMap.at(durationMetricId)]);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(valueMetricId)],
newMetricProducers[newMetricProducerMap.at(valueMetricId)]);
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(kllMetricId)],
newMetricProducers[newMetricProducerMap.at(kllMetricId)]);
// Make sure replaced metrics are different.
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(eventMetricId)],
newMetricProducers[newMetricProducerMap.at(eventMetricId)]);
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(gaugeMetricId)],
newMetricProducers[newMetricProducerMap.at(gaugeMetricId)]);
// Verify the conditionToMetricMap.
ASSERT_EQ(conditionToMetricMap.size(), 1);
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(countMetricIndex, gaugeMetricIndex,
valueMetricIndex, kllMetricIndex));
// Verify the trackerToMetricMap.
ASSERT_EQ(trackerToMetricMap.size(), 3);
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(countMetricIndex, durationMetricIndex));
const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(eventMetricIndex, durationMetricIndex));
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
EXPECT_THAT(matcher3Metrics,
UnorderedElementsAre(gaugeMetricIndex, valueMetricIndex, kllMetricIndex));
// Verify event activation/deactivation maps.
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
ASSERT_EQ(metricsWithActivation.size(), 0);
// Verify tracker indices/ids/conditions are correct.
EXPECT_EQ(newMetricProducers[countMetricIndex]->getMetricId(), countMetricId);
EXPECT_EQ(newMetricProducers[countMetricIndex]->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(newMetricProducers[countMetricIndex]->mCondition, ConditionState::kUnknown);
EXPECT_EQ(newMetricProducers[durationMetricIndex]->getMetricId(), durationMetricId);
EXPECT_EQ(newMetricProducers[durationMetricIndex]->mConditionTrackerIndex, -1);
EXPECT_EQ(newMetricProducers[durationMetricIndex]->mCondition, ConditionState::kTrue);
EXPECT_EQ(newMetricProducers[eventMetricIndex]->getMetricId(), eventMetricId);
EXPECT_EQ(newMetricProducers[eventMetricIndex]->mConditionTrackerIndex, -1);
EXPECT_EQ(newMetricProducers[eventMetricIndex]->mCondition, ConditionState::kTrue);
EXPECT_EQ(newMetricProducers[gaugeMetricIndex]->getMetricId(), gaugeMetricId);
EXPECT_EQ(newMetricProducers[gaugeMetricIndex]->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(newMetricProducers[gaugeMetricIndex]->mCondition, ConditionState::kUnknown);
EXPECT_EQ(newMetricProducers[kllMetricIndex]->getMetricId(), kllMetricId);
EXPECT_EQ(newMetricProducers[kllMetricIndex]->mConditionTrackerIndex, predicate1Index);
EXPECT_EQ(newMetricProducers[kllMetricIndex]->mCondition, ConditionState::kUnknown);
sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
EXPECT_NE(newConditionWizard, oldConditionWizard);
EXPECT_EQ(newConditionWizard->getStrongCount(), 7);
oldMetricProducers.clear();
// Only reference to the old wizard should be the one in the test.
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
}
TEST_F(ConfigUpdateTest, TestAlertPreserve) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_count_metric() = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
*config.add_alert() = alert;
EXPECT_TRUE(initConfig(config));
UpdateStatus updateStatus = UPDATE_UNKNOWN;
EXPECT_EQ(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
/*replacedMetrics*/ {}, updateStatus),
nullopt);
EXPECT_EQ(updateStatus, UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestAlertMetricChanged) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
CountMetric metric = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
*config.add_count_metric() = metric;
Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
*config.add_alert() = alert;
EXPECT_TRUE(initConfig(config));
UpdateStatus updateStatus = UPDATE_UNKNOWN;
EXPECT_EQ(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
/*replacedMetrics*/ {metric.id()}, updateStatus),
nullopt);
EXPECT_EQ(updateStatus, UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestAlertDefinitionChanged) {
StatsdConfig config;
AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = whatMatcher;
*config.add_count_metric() = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
*config.add_alert() = alert;
EXPECT_TRUE(initConfig(config));
alert.set_num_buckets(2);
UpdateStatus updateStatus = UPDATE_UNKNOWN;
EXPECT_EQ(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
/*replacedMetrics*/ {}, updateStatus),
nullopt);
EXPECT_EQ(updateStatus, UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestUpdateAlerts) {
StatsdConfig config;
// Add atom matchers/predicates/metrics. These are mostly needed for initStatsdConfig
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
*config.add_predicate() = CreateScreenIsOnPredicate();
CountMetric countMetric = createCountMetric("COUNT1", config.atom_matcher(0).id(), nullopt, {});
int64_t countMetricId = countMetric.id();
*config.add_count_metric() = countMetric;
DurationMetric durationMetric =
createDurationMetric("DURATION1", config.predicate(0).id(), nullopt, {});
int64_t durationMetricId = durationMetric.id();
*config.add_duration_metric() = durationMetric;
// Add alerts.
// Preserved.
Alert alert1 = createAlert("Alert1", durationMetricId, /*buckets*/ 1, /*triggerSum*/ 5000);
int64_t alert1Id = alert1.id();
*config.add_alert() = alert1;
// Replaced.
Alert alert2 = createAlert("Alert2", countMetricId, /*buckets*/ 1, /*triggerSum*/ 2);
int64_t alert2Id = alert2.id();
*config.add_alert() = alert2;
// Replaced.
Alert alert3 = createAlert("Alert3", durationMetricId, /*buckets*/ 3, /*triggerSum*/ 5000);
int64_t alert3Id = alert3.id();
*config.add_alert() = alert3;
// Add Subscriptions.
Subscription subscription1 = createSubscription("S1", Subscription::ALERT, alert1Id);
*config.add_subscription() = subscription1;
Subscription subscription2 = createSubscription("S2", Subscription::ALERT, alert1Id);
*config.add_subscription() = subscription2;
Subscription subscription3 = createSubscription("S3", Subscription::ALERT, alert2Id);
*config.add_subscription() = subscription3;
EXPECT_TRUE(initConfig(config));
// Add a duration tracker to the duration metric to ensure durationTrackers are updated
// with the proper anomalyTrackers.
unique_ptr<LogEvent> event = CreateScreenStateChangedEvent(
timeBaseNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
oldMetricProducers[1]->onMatchedLogEvent(0, *event.get());
// Change the count metric. Causes alert2 to be replaced.
config.mutable_count_metric(0)->set_bucket(ONE_DAY);
// Change num buckets on alert3, causing replacement.
alert3.set_num_buckets(5);
// New alert.
Alert alert4 = createAlert("Alert4", durationMetricId, /*buckets*/ 3, /*triggerSum*/ 10000);
int64_t alert4Id = alert4.id();
// Move subscription2 to be on alert2 and make a new subscription.
subscription2.set_rule_id(alert2Id);
Subscription subscription4 = createSubscription("S4", Subscription::ALERT, alert2Id);
// Create the new config. Modify the old one to avoid adding the matchers/predicates.
// Add alerts in different order so the map is changed.
config.clear_alert();
*config.add_alert() = alert4;
const int alert4Index = 0;
*config.add_alert() = alert3;
const int alert3Index = 1;
*config.add_alert() = alert1;
const int alert1Index = 2;
*config.add_alert() = alert2;
const int alert2Index = 3;
// Subscription3 is removed.
config.clear_subscription();
*config.add_subscription() = subscription4;
*config.add_subscription() = subscription2;
*config.add_subscription() = subscription1;
// Output data structures from update metrics. Don't care about the outputs besides
// replacedMetrics, but need to do this so that the metrics clear their anomaly trackers.
unordered_map<int64_t, int> newMetricProducerMap;
vector<sp<MetricProducer>> newMetricProducers;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
set<int64_t> noReportMetricIds;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
vector<int> metricsWithActivation;
set<int64_t> replacedMetrics;
int64_t currentTimeNs = 12345;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(
key, config, /*timeBaseNs=*/123, currentTimeNs, new StatsPullerManager(),
oldAtomMatchingTrackerMap, oldAtomMatchingTrackerMap, /*replacedMatchers*/ {},
oldAtomMatchingTrackers, oldConditionTrackerMap, /*replacedConditions=*/{},
oldConditionTrackers, {ConditionState::kUnknown}, /*stateAtomIdMap*/ {},
/*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation, replacedMetrics),
nullopt);
EXPECT_EQ(replacedMetrics, set<int64_t>({countMetricId}));
unordered_map<int64_t, int> newAlertTrackerMap;
vector<sp<AnomalyTracker>> newAnomalyTrackers;
EXPECT_EQ(updateAlerts(config, currentTimeNs, newMetricProducerMap, replacedMetrics,
oldAlertTrackerMap, oldAnomalyTrackers, anomalyAlarmMonitor,
newMetricProducers, newAlertTrackerMap, newAnomalyTrackers),
nullopt);
unordered_map<int64_t, int> expectedAlertMap = {
{alert1Id, alert1Index},
{alert2Id, alert2Index},
{alert3Id, alert3Index},
{alert4Id, alert4Index},
};
EXPECT_THAT(newAlertTrackerMap, ContainerEq(expectedAlertMap));
// Make sure preserved alerts are the same.
ASSERT_EQ(newAnomalyTrackers.size(), 4);
EXPECT_EQ(oldAnomalyTrackers[oldAlertTrackerMap.at(alert1Id)],
newAnomalyTrackers[newAlertTrackerMap.at(alert1Id)]);
// Make sure replaced alerts are different.
EXPECT_NE(oldAnomalyTrackers[oldAlertTrackerMap.at(alert2Id)],
newAnomalyTrackers[newAlertTrackerMap.at(alert2Id)]);
EXPECT_NE(oldAnomalyTrackers[oldAlertTrackerMap.at(alert3Id)],
newAnomalyTrackers[newAlertTrackerMap.at(alert3Id)]);
// Verify the alerts have the correct anomaly trackers.
ASSERT_EQ(newMetricProducers.size(), 2);
EXPECT_THAT(newMetricProducers[0]->mAnomalyTrackers,
UnorderedElementsAre(newAnomalyTrackers[alert2Index]));
// For durationMetric, make sure the duration trackers get the updated anomalyTrackers.
DurationMetricProducer* durationProducer =
static_cast<DurationMetricProducer*>(newMetricProducers[1].get());
EXPECT_THAT(
durationProducer->mAnomalyTrackers,
UnorderedElementsAre(newAnomalyTrackers[alert1Index], newAnomalyTrackers[alert3Index],
newAnomalyTrackers[alert4Index]));
ASSERT_EQ(durationProducer->mCurrentSlicedDurationTrackerMap.size(), 1);
for (const auto& durationTrackerIt : durationProducer->mCurrentSlicedDurationTrackerMap) {
EXPECT_EQ(durationTrackerIt.second->mAnomalyTrackers, durationProducer->mAnomalyTrackers);
}
// Verify alerts have the correct subscriptions. Use subscription id as proxy for equivalency.
vector<int64_t> alert1Subscriptions;
for (const Subscription& subscription : newAnomalyTrackers[alert1Index]->mSubscriptions) {
alert1Subscriptions.push_back(subscription.id());
}
EXPECT_THAT(alert1Subscriptions, UnorderedElementsAre(subscription1.id()));
vector<int64_t> alert2Subscriptions;
for (const Subscription& subscription : newAnomalyTrackers[alert2Index]->mSubscriptions) {
alert2Subscriptions.push_back(subscription.id());
}
EXPECT_THAT(alert2Subscriptions, UnorderedElementsAre(subscription2.id(), subscription4.id()));
EXPECT_THAT(newAnomalyTrackers[alert3Index]->mSubscriptions, IsEmpty());
EXPECT_THAT(newAnomalyTrackers[alert4Index]->mSubscriptions, IsEmpty());
}
TEST_F(ConfigUpdateTest, TestUpdateAlarms) {
StatsdConfig config;
// Add alarms.
Alarm alarm1 = createAlarm("Alarm1", /*offset*/ 1 * MS_PER_SEC, /*period*/ 50 * MS_PER_SEC);
int64_t alarm1Id = alarm1.id();
*config.add_alarm() = alarm1;
Alarm alarm2 = createAlarm("Alarm2", /*offset*/ 1 * MS_PER_SEC, /*period*/ 2000 * MS_PER_SEC);
int64_t alarm2Id = alarm2.id();
*config.add_alarm() = alarm2;
Alarm alarm3 = createAlarm("Alarm3", /*offset*/ 10 * MS_PER_SEC, /*period*/ 5000 * MS_PER_SEC);
int64_t alarm3Id = alarm3.id();
*config.add_alarm() = alarm3;
// Add Subscriptions.
Subscription subscription1 = createSubscription("S1", Subscription::ALARM, alarm1Id);
*config.add_subscription() = subscription1;
Subscription subscription2 = createSubscription("S2", Subscription::ALARM, alarm1Id);
*config.add_subscription() = subscription2;
Subscription subscription3 = createSubscription("S3", Subscription::ALARM, alarm2Id);
*config.add_subscription() = subscription3;
EXPECT_TRUE(initConfig(config));
ASSERT_EQ(oldAlarmTrackers.size(), 3);
// Config is created at statsd start time, so just add the offsets.
EXPECT_EQ(oldAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1);
EXPECT_EQ(oldAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1);
EXPECT_EQ(oldAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10);
// Change alarm2/alarm3.
config.mutable_alarm(1)->set_offset_millis(5 * MS_PER_SEC);
config.mutable_alarm(2)->set_period_millis(10000 * MS_PER_SEC);
// Move subscription2 to be on alarm2 and make a new subscription.
config.mutable_subscription(1)->set_rule_id(alarm2Id);
Subscription subscription4 = createSubscription("S4", Subscription::ALARM, alarm1Id);
*config.add_subscription() = subscription4;
// Update time is 2 seconds after the base time.
int64_t currentTimeNs = timeBaseNs + 2 * NS_PER_SEC;
vector<sp<AlarmTracker>> newAlarmTrackers;
EXPECT_EQ(initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
newAlarmTrackers),
nullopt);
ASSERT_EQ(newAlarmTrackers.size(), 3);
// Config is updated 2 seconds after statsd start
// The offset has passed for alarm1, but not for alarms 2/3.
EXPECT_EQ(newAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1 + 50);
EXPECT_EQ(newAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 5);
EXPECT_EQ(newAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10);
// Verify alarms have the correct subscriptions. Use subscription id as proxy for equivalency.
vector<int64_t> alarm1Subscriptions;
for (const Subscription& subscription : newAlarmTrackers[0]->mSubscriptions) {
alarm1Subscriptions.push_back(subscription.id());
}
EXPECT_THAT(alarm1Subscriptions, UnorderedElementsAre(subscription1.id(), subscription4.id()));
vector<int64_t> alarm2Subscriptions;
for (const Subscription& subscription : newAlarmTrackers[1]->mSubscriptions) {
alarm2Subscriptions.push_back(subscription.id());
}
EXPECT_THAT(alarm2Subscriptions, UnorderedElementsAre(subscription2.id(), subscription3.id()));
EXPECT_THAT(newAlarmTrackers[2]->mSubscriptions, IsEmpty());
// Verify the alarm monitor is updated accordingly once the old alarms are removed.
// Alarm2 fires the earliest.
oldAlarmTrackers.clear();
EXPECT_EQ(periodicAlarmMonitor->getRegisteredAlarmTimeSec(), timeBaseNs / NS_PER_SEC + 5);
// Do another update 60 seconds after config creation time, after the offsets of each alarm.
currentTimeNs = timeBaseNs + 60 * NS_PER_SEC;
newAlarmTrackers.clear();
EXPECT_EQ(initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
newAlarmTrackers),
nullopt);
ASSERT_EQ(newAlarmTrackers.size(), 3);
// Config is updated one minute after statsd start.
// Two periods have passed for alarm 1, one has passed for alarms2/3.
EXPECT_EQ(newAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1 + 2 * 50);
EXPECT_EQ(newAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 5 + 2000);
EXPECT_EQ(newAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10 + 10000);
}
TEST_F(ConfigUpdateTest, TestMetricHasMultipleActivations) {
StatsdConfig config;
int64_t metricId = 1;
auto metric_activation1 = config.add_metric_activation();
metric_activation1->set_metric_id(metricId);
metric_activation1->set_activation_type(ACTIVATE_IMMEDIATELY);
EXPECT_TRUE(initConfig(config));
auto metric_activation2 = config.add_metric_activation();
metric_activation2->set_metric_id(metricId);
metric_activation2->set_activation_type(ACTIVATE_IMMEDIATELY);
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
unordered_map<int64_t, int> newConditionTrackerMap;
unordered_map<int64_t, int> newMetricProducerMap;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
set<int64_t> noReportMetricIds;
vector<int> metricsWithActivation;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
vector<sp<ConditionTracker>> newConditionTrackers;
vector<sp<MetricProducer>> newMetricProducers;
vector<ConditionState> conditionCache;
set<int64_t> replacedMetrics;
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
set<int64_t> replacedStates;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_HAS_MULTIPLE_ACTIVATIONS, metricId));
}
TEST_F(ConfigUpdateTest, TestNoReportMetricNotFound) {
StatsdConfig config;
int64_t metricId = 1;
config.add_no_report_metric(metricId);
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
unordered_map<int64_t, int> newConditionTrackerMap;
unordered_map<int64_t, int> newMetricProducerMap;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
set<int64_t> noReportMetricIds;
vector<int> metricsWithActivation;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
vector<sp<ConditionTracker>> newConditionTrackers;
vector<sp<MetricProducer>> newMetricProducers;
vector<ConditionState> conditionCache;
set<int64_t> replacedMetrics;
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
set<int64_t> replacedStates;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
InvalidConfigReason(INVALID_CONFIG_REASON_NO_REPORT_METRIC_NOT_FOUND, metricId));
}
TEST_F(ConfigUpdateTest, TestMetricSlicedStateAtomAllowedFromAnyUid) {
StatsdConfig config;
CountMetric* metric = config.add_count_metric();
*metric = createCountMetric(/*name=*/"Count", /*what=*/StringToId("ScreenTurnedOn"),
/*condition=*/nullopt, /*states=*/{});
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
*config.add_state() = CreateScreenState();
metric->add_slice_by_state(StringToId("ScreenState"));
EXPECT_TRUE(initConfig(config));
config.add_whitelisted_atom_ids(util::SCREEN_STATE_CHANGED);
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
unordered_map<int64_t, int> newConditionTrackerMap;
unordered_map<int64_t, int> newMetricProducerMap;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
set<int64_t> noReportMetricIds;
vector<int> metricsWithActivation;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
vector<sp<ConditionTracker>> newConditionTrackers;
vector<sp<MetricProducer>> newMetricProducers;
vector<ConditionState> conditionCache;
set<int64_t> replacedMetrics;
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
set<int64_t> replacedStates;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
newAtomMatchingTrackerMap[StringToId("ScreenTurnedOn")] = 0;
stateAtomIdMap[StringToId("ScreenState")] = util::SCREEN_STATE_CHANGED;
EXPECT_EQ(
updateMetrics(
key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap,
replacedMatchers, newAtomMatchingTrackers, newConditionTrackerMap,
replacedConditions, newConditionTrackers, conditionCache, stateAtomIdMap,
allStateGroupMaps, replacedStates, oldMetricProducerMap, oldMetricProducers,
provider, newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation, replacedMetrics),
InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_SLICED_STATE_ATOM_ALLOWED_FROM_ANY_UID,
StringToId("Count")));
}
TEST_F(ConfigUpdateTest, TestMatcherDuplicate) {
StatsdConfig config;
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
EXPECT_TRUE(initConfig(config));
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
unordered_map<int, vector<int>> newTagIds;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
set<int64_t> replacedMatchers;
EXPECT_EQ(updateAtomMatchingTrackers(
config, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, newTagIds,
newAtomMatchingTrackerMap, newAtomMatchingTrackers, replacedMatchers),
createInvalidConfigReasonWithMatcher(INVALID_CONFIG_REASON_MATCHER_DUPLICATE,
StringToId("ScreenTurnedOn")));
}
TEST_F(ConfigUpdateTest, TestConditionDuplicate) {
StatsdConfig config;
*config.add_predicate() = CreateScreenIsOnPredicate();
EXPECT_TRUE(initConfig(config));
*config.add_predicate() = CreateScreenIsOnPredicate();
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
unordered_map<int64_t, int> newConditionTrackerMap;
vector<sp<ConditionTracker>> newConditionTrackers;
unordered_map<int, vector<int>> trackerToConditionMap;
vector<ConditionState> conditionCache;
set<int64_t> replacedConditions;
set<int64_t> replacedMatchers;
EXPECT_EQ(updateConditions(key, config, newAtomMatchingTrackerMap, replacedMatchers,
oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap,
newConditionTrackers, trackerToConditionMap, conditionCache,
replacedConditions),
createInvalidConfigReasonWithPredicate(INVALID_CONFIG_REASON_CONDITION_DUPLICATE,
StringToId("ScreenIsOn")));
}
TEST_F(ConfigUpdateTest, TestUpdateConfigNonEventMetricHasRestrictedDelegate) {
StatsdConfig config;
CountMetric* metric = config.add_count_metric();
config.set_restricted_metrics_delegate_package_name("com.android.app.test");
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
unordered_map<int64_t, int> newConditionTrackerMap;
unordered_map<int64_t, int> newMetricProducerMap;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
set<int64_t> noReportMetricIds;
vector<int> metricsWithActivation;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
vector<sp<ConditionTracker>> newConditionTrackers;
vector<sp<MetricProducer>> newMetricProducers;
vector<ConditionState> conditionCache;
set<int64_t> replacedMetrics;
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
set<int64_t> replacedStates;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
newAtomMatchingTrackerMap, replacedMatchers, newAtomMatchingTrackers,
newConditionTrackerMap, replacedConditions, newConditionTrackers,
conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation,
replacedMetrics),
InvalidConfigReason(INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_SUPPORTED));
}
TEST_P(ConfigUpdateDimLimitTest, TestDimLimit) {
StatsdConfig config = buildGoodConfig(configId);
const auto& [oldLimit, newLimit, actualLimit] = GetParam();
if (oldLimit > 0) {
config.mutable_count_metric(0)->set_max_dimensions_per_bucket(oldLimit);
config.mutable_duration_metric(0)->set_max_dimensions_per_bucket(oldLimit);
config.mutable_gauge_metric(0)->set_max_dimensions_per_bucket(oldLimit);
config.mutable_value_metric(0)->set_max_dimensions_per_bucket(oldLimit);
config.mutable_kll_metric(0)->set_max_dimensions_per_bucket(oldLimit);
}
EXPECT_TRUE(initConfig(config));
StatsdConfig newConfig = config;
if (newLimit == 0) {
newConfig.mutable_count_metric(0)->clear_max_dimensions_per_bucket();
newConfig.mutable_duration_metric(0)->clear_max_dimensions_per_bucket();
newConfig.mutable_gauge_metric(0)->clear_max_dimensions_per_bucket();
newConfig.mutable_value_metric(0)->clear_max_dimensions_per_bucket();
newConfig.mutable_kll_metric(0)->clear_max_dimensions_per_bucket();
} else {
newConfig.mutable_count_metric(0)->set_max_dimensions_per_bucket(newLimit);
newConfig.mutable_duration_metric(0)->set_max_dimensions_per_bucket(newLimit);
newConfig.mutable_gauge_metric(0)->set_max_dimensions_per_bucket(newLimit);
newConfig.mutable_value_metric(0)->set_max_dimensions_per_bucket(newLimit);
newConfig.mutable_kll_metric(0)->set_max_dimensions_per_bucket(newLimit);
}
unordered_map<int64_t, int> newMetricProducerMap;
unordered_map<int, vector<int>> conditionToMetricMap;
unordered_map<int, vector<int>> trackerToMetricMap;
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
set<int64_t> noReportMetricIds;
vector<int> metricsWithActivation;
vector<sp<MetricProducer>> newMetricProducers;
set<int64_t> replacedMetrics;
sp<MockConfigMetadataProvider> provider = makeMockConfigMetadataProvider(/*enabled=*/false);
EXPECT_EQ(updateMetrics(
key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345,
new StatsPullerManager(), oldAtomMatchingTrackerMap,
oldAtomMatchingTrackerMap, /*replacedMatchers=*/{}, oldAtomMatchingTrackers,
oldConditionTrackerMap, /*replacedConditions=*/{}, oldConditionTrackers,
/*conditionCache=*/{}, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
/*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, provider,
newMetricProducerMap, newMetricProducers, conditionToMetricMap,
trackerToMetricMap, noReportMetricIds, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation, replacedMetrics),
nullopt);
ASSERT_EQ(5u, oldMetricProducers.size());
ASSERT_EQ(5u, newMetricProducers.size());
// Check that old MetricProducers have the old dimension limit and the new producers have the
// new dimension limit.
// Count
sp<MetricProducer> producer =
oldMetricProducers[oldMetricProducerMap.at(config.count_metric(0).id())];
CountMetricProducer* countProducer = static_cast<CountMetricProducer*>(producer.get());
EXPECT_EQ(countProducer->mDimensionHardLimit, oldLimit);
producer = newMetricProducers[newMetricProducerMap.at(newConfig.count_metric(0).id())];
countProducer = static_cast<CountMetricProducer*>(producer.get());
EXPECT_EQ(countProducer->mDimensionHardLimit, actualLimit);
// Duration
producer = oldMetricProducers[oldMetricProducerMap.at(config.duration_metric(0).id())];
DurationMetricProducer* durationProducer = static_cast<DurationMetricProducer*>(producer.get());
EXPECT_EQ(durationProducer->mDimensionHardLimit, oldLimit);
producer = newMetricProducers[newMetricProducerMap.at(newConfig.duration_metric(0).id())];
durationProducer = static_cast<DurationMetricProducer*>(producer.get());
EXPECT_EQ(durationProducer->mDimensionHardLimit, actualLimit);
// Gauge
producer = oldMetricProducers[oldMetricProducerMap.at(config.gauge_metric(0).id())];
GaugeMetricProducer* gaugeProducer = static_cast<GaugeMetricProducer*>(producer.get());
EXPECT_EQ(gaugeProducer->mDimensionHardLimit, oldLimit);
producer = newMetricProducers[newMetricProducerMap.at(newConfig.gauge_metric(0).id())];
gaugeProducer = static_cast<GaugeMetricProducer*>(producer.get());
EXPECT_EQ(gaugeProducer->mDimensionHardLimit, actualLimit);
// Value
producer = oldMetricProducers[oldMetricProducerMap.at(config.value_metric(0).id())];
NumericValueMetricProducer* numericValueProducer =
static_cast<NumericValueMetricProducer*>(producer.get());
EXPECT_EQ(numericValueProducer->mDimensionHardLimit, oldLimit);
producer = newMetricProducers[newMetricProducerMap.at(newConfig.value_metric(0).id())];
numericValueProducer = static_cast<NumericValueMetricProducer*>(producer.get());
EXPECT_EQ(numericValueProducer->mDimensionHardLimit, actualLimit);
// KLL
producer = oldMetricProducers[oldMetricProducerMap.at(config.kll_metric(0).id())];
KllMetricProducer* kllProducer = static_cast<KllMetricProducer*>(producer.get());
EXPECT_EQ(kllProducer->mDimensionHardLimit, oldLimit);
producer = newMetricProducers[newMetricProducerMap.at(newConfig.kll_metric(0).id())];
kllProducer = static_cast<KllMetricProducer*>(producer.get());
EXPECT_EQ(kllProducer->mDimensionHardLimit, actualLimit);
}
} // namespace statsd
} // namespace os
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif