blob: f6d30618ee159cc7521be9e312f6d70539b924b3 [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 <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
#include <set>
#include <unordered_map>
#include <vector>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "src/metrics/parsing_utils/metrics_manager_util.h"
#include "tests/statsd_test_util.h"
using namespace testing;
using android::sp;
using android::os::statsd::Predicate;
using std::map;
using std::set;
using std::unordered_map;
using std::vector;
#ifdef __ANDROID__
namespace android {
namespace os {
namespace statsd {
namespace {
ConfigKey key(123, 456);
const int64_t timeBaseNs = 1000;
sp<UidMap> uidMap = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> periodicAlarmMonitor;
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers;
unordered_map<int64_t, int> oldAtomMatchingTrackerMap;
vector<sp<ConditionTracker>> oldConditionTrackers;
vector<sp<MetricProducer>> oldMetricProducers;
std::vector<sp<AnomalyTracker>> oldAnomalyTrackers;
std::vector<sp<AlarmTracker>> oldAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
class ConfigUpdateTest : public ::testing::Test {
public:
ConfigUpdateTest() {
}
void SetUp() override {
allTagIds.clear();
oldAtomMatchingTrackers.clear();
oldAtomMatchingTrackerMap.clear();
oldConditionTrackers.clear();
oldMetricProducers.clear();
oldAnomalyTrackers.clear();
oldAlarmTrackers.clear();
conditionToMetricMap.clear();
trackerToMetricMap.clear();
trackerToConditionMap.clear();
activationAtomTrackerToMetricMap.clear();
deactivationAtomTrackerToMetricMap.clear();
alertTrackerMap.clear();
metricsWithActivation.clear();
noReportMetricIds.clear();
}
};
bool initConfig(const StatsdConfig& config) {
return initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, timeBaseNs, allTagIds, oldAtomMatchingTrackers, oldAtomMatchingTrackerMap,
oldConditionTrackers, oldMetricProducers, oldAnomalyTrackers, oldAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds);
}
} // 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<bool> cycleTracker(1, false);
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
newAtomMatchingTrackerMap[matcherId] = 0;
EXPECT_TRUE(determineMatcherUpdateStatus(config, 0, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker));
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<bool> cycleTracker(1, false);
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
newAtomMatchingTrackerMap[matcherId] = 0;
EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker));
EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
}
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<bool> cycleTracker(3, false);
// Only update the combination. It should recurse the two child matchers and preserve all 3.
EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker));
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<bool> cycleTracker(3, false);
// Only update the combination. The simple matchers should not be evaluated.
EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker));
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<bool> cycleTracker(3, false);
// Only update the combination.
EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
matchersToUpdate, cycleTracker));
// 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;
set<int> newTagIds;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
EXPECT_TRUE(updateAtomTrackers(newConfig, uidMap, oldAtomMatchingTrackerMap,
oldAtomMatchingTrackers, newTagIds, newAtomMatchingTrackerMap,
newAtomMatchingTrackers));
ASSERT_EQ(newTagIds.size(), 3);
EXPECT_EQ(newTagIds.count(10), 1);
EXPECT_EQ(newTagIds.count(111), 1);
EXPECT_EQ(newTagIds.count(13), 1);
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);
}
} // namespace statsd
} // namespace os
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif