Remove the hacky HashableDimensionKey.
+ Add a real HashableDimensionKey as a wrapper of the dimension.
So we can get rid of the maps that we kept.
Pay down technical debt and reduce memory usage.
Test: statsd_test & manual
Change-Id: I233280cf1e2ce93da6a8cd4e8514abb066f4016d
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 3e517bb..f98ee3d 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -54,7 +54,7 @@
src/storage/StorageManager.cpp \
src/StatsLogProcessor.cpp \
src/StatsService.cpp \
- src/stats_util.cpp \
+ src/HashableDimensionKey.cpp \
src/guardrail/MemoryLeakTrackUtil.cpp \
src/guardrail/StatsdStats.cpp
@@ -174,7 +174,8 @@
tests/metrics/EventMetricProducer_test.cpp \
tests/metrics/ValueMetricProducer_test.cpp \
tests/metrics/GaugeMetricProducer_test.cpp \
- tests/guardrail/StatsdStats_test.cpp
+ tests/guardrail/StatsdStats_test.cpp \
+ tests/metrics/metrics_test_helper.cpp
LOCAL_STATIC_LIBRARIES := \
$(statsd_common_static_libraries) \
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
new file mode 100644
index 0000000..0b6f8f2
--- /dev/null
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "HashableDimensionKey.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::string;
+
+string HashableDimensionKey::toString() const {
+ string flattened;
+ for (const auto& pair : mKeyValuePairs) {
+ flattened += std::to_string(pair.key());
+ flattened += ":";
+ switch (pair.value_case()) {
+ case KeyValuePair::ValueCase::kValueStr:
+ flattened += pair.value_str();
+ break;
+ case KeyValuePair::ValueCase::kValueInt:
+ flattened += std::to_string(pair.value_int());
+ break;
+ case KeyValuePair::ValueCase::kValueLong:
+ flattened += std::to_string(pair.value_long());
+ break;
+ case KeyValuePair::ValueCase::kValueBool:
+ flattened += std::to_string(pair.value_bool());
+ break;
+ case KeyValuePair::ValueCase::kValueFloat:
+ flattened += std::to_string(pair.value_float());
+ break;
+ default:
+ break;
+ }
+ flattened += "|";
+ }
+ return flattened;
+}
+
+bool HashableDimensionKey::operator==(const HashableDimensionKey& that) const {
+ const auto& keyValue2 = that.getKeyValuePairs();
+ if (mKeyValuePairs.size() != keyValue2.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < keyValue2.size(); i++) {
+ const auto& kv1 = mKeyValuePairs[i];
+ const auto& kv2 = keyValue2[i];
+ if (kv1.key() != kv2.key()) {
+ return false;
+ }
+
+ if (kv1.value_case() != kv2.value_case()) {
+ return false;
+ }
+
+ switch (kv1.value_case()) {
+ case KeyValuePair::ValueCase::kValueStr:
+ if (kv1.value_str() != kv2.value_str()) {
+ return false;
+ }
+ break;
+ case KeyValuePair::ValueCase::kValueInt:
+ if (kv1.value_int() != kv2.value_int()) {
+ return false;
+ }
+ break;
+ case KeyValuePair::ValueCase::kValueLong:
+ if (kv1.value_long() != kv2.value_long()) {
+ return false;
+ }
+ break;
+ case KeyValuePair::ValueCase::kValueBool:
+ if (kv1.value_bool() != kv2.value_bool()) {
+ return false;
+ }
+ break;
+ case KeyValuePair::ValueCase::kValueFloat: {
+ if (kv1.value_float() != kv2.value_float()) {
+ return false;
+ }
+ break;
+ }
+ case KeyValuePair::ValueCase::VALUE_NOT_SET:
+ break;
+ }
+ }
+ return true;
+};
+
+bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const {
+ return toString().compare(that.toString()) < 0;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
new file mode 100644
index 0000000..85215552
--- /dev/null
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/JenkinsHash.h>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class HashableDimensionKey {
+public:
+ explicit HashableDimensionKey(const std::vector<KeyValuePair>& keyValuePairs)
+ : mKeyValuePairs(keyValuePairs){};
+
+ HashableDimensionKey(){};
+
+ HashableDimensionKey(const HashableDimensionKey& that)
+ : mKeyValuePairs(that.getKeyValuePairs()){};
+
+ HashableDimensionKey& operator=(const HashableDimensionKey& from) = default;
+
+ std::string toString() const;
+
+ inline const std::vector<KeyValuePair>& getKeyValuePairs() const {
+ return mKeyValuePairs;
+ }
+
+ bool operator==(const HashableDimensionKey& that) const;
+
+ bool operator<(const HashableDimensionKey& that) const;
+
+ inline const char* c_str() const {
+ return toString().c_str();
+ }
+
+private:
+ std::vector<KeyValuePair> mKeyValuePairs;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+namespace std {
+
+using android::os::statsd::HashableDimensionKey;
+using android::os::statsd::KeyValuePair;
+
+template <>
+struct hash<HashableDimensionKey> {
+ std::size_t operator()(const HashableDimensionKey& key) const {
+ android::hash_t hash = 0;
+ for (const auto& pair : key.getKeyValuePairs()) {
+ hash = android::JenkinsHashMix(hash, android::hash_type(pair.key()));
+ hash = android::JenkinsHashMix(
+ hash, android::hash_type(static_cast<int32_t>(pair.value_case())));
+ switch (pair.value_case()) {
+ case KeyValuePair::ValueCase::kValueStr:
+ hash = android::JenkinsHashMix(
+ hash,
+ static_cast<uint32_t>(std::hash<std::string>()(pair.value_str())));
+ break;
+ case KeyValuePair::ValueCase::kValueInt:
+ hash = android::JenkinsHashMix(hash, android::hash_type(pair.value_int()));
+ break;
+ case KeyValuePair::ValueCase::kValueLong:
+ hash = android::JenkinsHashMix(
+ hash, android::hash_type(static_cast<int64_t>(pair.value_long())));
+ break;
+ case KeyValuePair::ValueCase::kValueBool:
+ hash = android::JenkinsHashMix(hash, android::hash_type(pair.value_bool()));
+ break;
+ case KeyValuePair::ValueCase::kValueFloat: {
+ float floatVal = pair.value_float();
+ hash = android::JenkinsHashMixBytes(hash, (uint8_t*)&floatVal, sizeof(float));
+ break;
+ }
+ case KeyValuePair::ValueCase::VALUE_NOT_SET:
+ break;
+ }
+ }
+ return hash;
+ }
+};
+
+} // namespace std
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 18b93ee..a63bc04 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -279,7 +279,7 @@
}
// outputKey is the output key values. e.g, uid:1234
- const HashableDimensionKey outputKey = getHashableKey(getDimensionKey(event, mOutputDimension));
+ const HashableDimensionKey outputKey(getDimensionKey(event, mOutputDimension));
handleConditionEvent(outputKey, matchedState == 1, conditionCache, conditionChangedCache);
}
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index ff0e3bc..53ef9d5 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -109,7 +109,7 @@
kv.set_key(link.key_in_condition(i).key());
}
- return getHashableKey(dimensionKey);
+ return HashableDimensionKey(dimensionKey);
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index bc12a78..9031ed0 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -107,17 +107,14 @@
for (const auto& counter : mPastBuckets) {
const HashableDimensionKey& hashableKey = counter.first;
+ const vector<KeyValuePair>& kvs = hashableKey.getKeyValuePairs();
VLOG(" dimension key %s", hashableKey.c_str());
- auto it = mDimensionKeyMap.find(hashableKey);
- if (it == mDimensionKeyMap.end()) {
- ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
- continue;
- }
+
long long wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension (KeyValuePairs).
- for (const auto& kv : it->second) {
+ for (const auto& kv : kvs) {
long long dimensionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 220861d..1c8f422 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -159,18 +159,14 @@
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
+ const vector<KeyValuePair>& kvs = hashableKey.getKeyValuePairs();
VLOG(" dimension key %s", hashableKey.c_str());
- auto it = mDimensionKeyMap.find(hashableKey);
- if (it == mDimensionKeyMap.end()) {
- ALOGW("Dimension key %s not found?!?! skip...", hashableKey.c_str());
- continue;
- }
long long wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension (KeyValuePairs).
- for (const auto& kv : it->second) {
+ for (const auto& kv : kvs) {
long long dimensionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
@@ -260,7 +256,7 @@
return;
}
- HashableDimensionKey atomKey = getHashableKey(getDimensionKey(event, mInternalDimension));
+ HashableDimensionKey atomKey(getDimensionKey(event, mInternalDimension));
if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end()) {
if (hitGuardRailLocked(eventKey)) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 6402633..47cca0e 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -128,18 +128,14 @@
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
- auto it = mDimensionKeyMap.find(hashableKey);
- if (it == mDimensionKeyMap.end()) {
- ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
- continue;
- }
+ const vector<KeyValuePair>& kvs = hashableKey.getKeyValuePairs();
VLOG(" dimension key %s", hashableKey.c_str());
long long wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension (KeyValuePairs).
- for (const auto& kv : it->second) {
+ for (const auto& kv : kvs) {
long long dimensionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index f38f3df..5286908 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -32,12 +32,7 @@
if (mDimension.size() > 0) {
vector<KeyValuePair> key = getDimensionKey(event, mDimension);
- eventKey = getHashableKey(key);
- // Add the HashableDimensionKey->vector<KeyValuePair> to the map, because StatsLogReport
- // expects vector<KeyValuePair>.
- if (mDimensionKeyMap.find(eventKey) == mDimensionKeyMap.end()) {
- mDimensionKeyMap[eventKey] = key;
- }
+ eventKey = HashableDimensionKey(key);
} else {
eventKey = DEFAULT_DIMENSION_KEY;
}
@@ -58,7 +53,6 @@
} else {
condition = mCondition;
}
-
onMatchedLogEventInternalLocked(matcherIndex, eventKey, conditionKeys, condition, event);
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 7bd274d..85ef4ad 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -49,10 +49,7 @@
mCondition(conditionIndex >= 0 ? false : true),
mConditionSliced(false),
mWizard(wizard),
- mConditionTrackerIndex(conditionIndex) {
- // reuse the same map for non-sliced metrics too. this way, we avoid too many if-else.
- mDimensionKeyMap[DEFAULT_DIMENSION_KEY] = std::vector<KeyValuePair>();
- };
+ mConditionTrackerIndex(conditionIndex){};
virtual ~MetricProducer(){};
void notifyAppUpgrade(const string& apk, const int uid, const int64_t version) override{
@@ -145,10 +142,6 @@
std::vector<KeyMatcher> mDimension; // The dimension defined in statsd_config
- // Keep the map from the internal HashableDimensionKey to std::vector<KeyValuePair>
- // that StatsLogReport wants.
- std::unordered_map<HashableDimensionKey, std::vector<KeyValuePair>> mDimensionKeyMap;
-
std::vector<MetricConditionLink> mConditionLinks;
std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 7efa6cd..40aed7b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -132,16 +132,12 @@
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
VLOG(" dimension key %s", hashableKey.c_str());
- auto it = mDimensionKeyMap.find(hashableKey);
- if (it == mDimensionKeyMap.end()) {
- ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
- continue;
- }
+ const vector<KeyValuePair>& kvs = hashableKey.getKeyValuePairs();
long long wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension (KeyValuePairs).
- for (const auto& kv : it->second) {
+ for (const auto& kv : kvs) {
long long dimensionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 95c8a59..6050f43 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -42,7 +42,7 @@
// 1. Report the tuple count if the tuple count > soft limit
if (mInfos.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mInfos.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey,
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey.toString(),
newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index 36e25edf..5c43096 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -45,7 +45,7 @@
}
if (mConditionKeyMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mConditionKeyMap.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey,
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey.toString(),
newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
diff --git a/cmds/statsd/src/stats_util.cpp b/cmds/statsd/src/stats_util.cpp
deleted file mode 100644
index 7527a64..0000000
--- a/cmds/statsd/src/stats_util.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// There is no existing hash function for the dimension key ("repeated KeyValuePair").
-// Temporarily use a string concatenation as the hashable key.
-// TODO: Find a better hash function for std::vector<KeyValuePair>.
-HashableDimensionKey getHashableKey(std::vector<KeyValuePair> keys) {
- std::string flattened;
- for (const KeyValuePair& pair : keys) {
- flattened += std::to_string(pair.key());
- flattened += ":";
- switch (pair.value_case()) {
- case KeyValuePair::ValueCase::kValueStr:
- flattened += pair.value_str();
- break;
- case KeyValuePair::ValueCase::kValueInt:
- flattened += std::to_string(pair.value_int());
- break;
- case KeyValuePair::ValueCase::kValueLong:
- flattened += std::to_string(pair.value_long());
- break;
- case KeyValuePair::ValueCase::kValueBool:
- flattened += std::to_string(pair.value_bool());
- break;
- case KeyValuePair::ValueCase::kValueFloat:
- flattened += std::to_string(pair.value_float());
- break;
- default:
- break;
- }
- flattened += "|";
- }
- return flattened;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index 8fd1ea8c..1cdf031 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -16,8 +16,9 @@
#pragma once
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include <sstream>
+#include "HashableDimensionKey.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "logd/LogReader.h"
#include <unordered_map>
@@ -26,13 +27,11 @@
namespace os {
namespace statsd {
-#define DEFAULT_DIMENSION_KEY ""
+const HashableDimensionKey DEFAULT_DIMENSION_KEY = HashableDimensionKey(vector<KeyValuePair>());
// Minimum bucket size in seconds
const long kMinBucketSizeSec = 5 * 60;
-typedef std::string HashableDimensionKey;
-
typedef std::map<std::string, HashableDimensionKey> ConditionKey;
typedef std::unordered_map<HashableDimensionKey, int64_t> DimToValMap;
@@ -67,13 +66,6 @@
} EventKV;
typedef std::unordered_map<HashableDimensionKey, std::shared_ptr<EventKV>> DimToEventKVMap;
-
-EventMetricData parse(log_msg msg);
-
-int getTagId(log_msg msg);
-
-std::string getHashableKey(std::vector<KeyValuePair> key);
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index f385763..f62171d 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/anomaly/AnomalyTracker.h"
+#include "../metrics/metrics_test_helper.h"
#include <gtest/gtest.h>
#include <stdio.h>
@@ -32,7 +33,18 @@
const ConfigKey kConfigKey(0, "test");
-void AddValueToBucket(const std::vector<std::pair<string, long>>& key_value_pair_list,
+HashableDimensionKey getMockDimensionKey(int key, string value) {
+ KeyValuePair pair;
+ pair.set_key(key);
+ pair.set_value_str(value);
+
+ vector<KeyValuePair> pairs;
+ pairs.push_back(pair);
+
+ return HashableDimensionKey(pairs);
+}
+
+void AddValueToBucket(const std::vector<std::pair<HashableDimensionKey, long>>& key_value_pair_list,
std::shared_ptr<DimToValMap> bucket) {
for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
(*bucket)[itr->first] += itr->second;
@@ -40,7 +52,7 @@
}
std::shared_ptr<DimToValMap> MockBucket(
- const std::vector<std::pair<string, long>>& key_value_pair_list) {
+ const std::vector<std::pair<HashableDimensionKey, long>>& key_value_pair_list) {
std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
AddValueToBucket(key_value_pair_list, bucket);
return bucket;
@@ -54,20 +66,23 @@
alert.set_trigger_if_sum_gt(2);
AnomalyTracker anomalyTracker(alert, kConfigKey);
+ HashableDimensionKey keyA = getMockDimensionKey(1, "a");
+ HashableDimensionKey keyB = getMockDimensionKey(1, "b");
+ HashableDimensionKey keyC = getMockDimensionKey(1, "c");
- std::shared_ptr<DimToValMap> bucket0 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
+ std::shared_ptr<DimToValMap> bucket0 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
int64_t eventTimestamp0 = 10;
- std::shared_ptr<DimToValMap> bucket1 = MockBucket({{"a", 1}});
+ std::shared_ptr<DimToValMap> bucket1 = MockBucket({{keyA, 1}});
int64_t eventTimestamp1 = bucketSizeNs + 11;
- std::shared_ptr<DimToValMap> bucket2 = MockBucket({{"b", 1}});
+ std::shared_ptr<DimToValMap> bucket2 = MockBucket({{keyB, 1}});
int64_t eventTimestamp2 = 2 * bucketSizeNs + 12;
- std::shared_ptr<DimToValMap> bucket3 = MockBucket({{"a", 2}});
+ std::shared_ptr<DimToValMap> bucket3 = MockBucket({{keyA, 2}});
int64_t eventTimestamp3 = 3 * bucketSizeNs + 13;
- std::shared_ptr<DimToValMap> bucket4 = MockBucket({{"b", 1}});
+ std::shared_ptr<DimToValMap> bucket4 = MockBucket({{keyB, 1}});
int64_t eventTimestamp4 = 4 * bucketSizeNs + 14;
- std::shared_ptr<DimToValMap> bucket5 = MockBucket({{"a", 2}});
+ std::shared_ptr<DimToValMap> bucket5 = MockBucket({{keyA, 2}});
int64_t eventTimestamp5 = 5 * bucketSizeNs + 15;
- std::shared_ptr<DimToValMap> bucket6 = MockBucket({{"a", 2}});
+ std::shared_ptr<DimToValMap> bucket6 = MockBucket({{keyA, 2}});
int64_t eventTimestamp6 = 6 * bucketSizeNs + 16;
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u);
@@ -79,9 +94,9 @@
// Adds past bucket #0
anomalyTracker.addPastBucket(bucket0, 0);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 1LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
EXPECT_FALSE(anomalyTracker.detectAnomaly(1, *bucket1));
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1, 1, *bucket1);
@@ -90,9 +105,9 @@
// Adds past bucket #0 again. The sum does not change.
anomalyTracker.addPastBucket(bucket0, 0);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 1LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
EXPECT_FALSE(anomalyTracker.detectAnomaly(1, *bucket1));
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1 + 1, 1, *bucket1);
@@ -102,9 +117,9 @@
anomalyTracker.addPastBucket(bucket1, 1);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(2, *bucket2));
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2, 2, *bucket2);
EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
@@ -113,9 +128,9 @@
anomalyTracker.addPastBucket(bucket1, 1);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(2, *bucket2));
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2 + 1, 2, *bucket2);
EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
@@ -124,8 +139,8 @@
anomalyTracker.addPastBucket(bucket2, 2);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 2L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 1LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(3, *bucket3));
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp3, 3, *bucket3);
// Within refractory period.
@@ -135,8 +150,8 @@
anomalyTracker.addPastBucket(bucket3, 3L);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 3L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_FALSE(anomalyTracker.detectAnomaly(4, *bucket4));
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4, 4, *bucket4);
EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
@@ -145,8 +160,8 @@
anomalyTracker.addPastBucket(bucket4, 4);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 4L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(5, *bucket5));
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp5, 5, *bucket5);
EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp5);
@@ -155,8 +170,8 @@
anomalyTracker.addPastBucket(bucket5, 5);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 5L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(6, *bucket6));
// Within refractory period.
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6, 6, *bucket6);
@@ -171,13 +186,18 @@
alert.set_trigger_if_sum_gt(2);
AnomalyTracker anomalyTracker(alert, kConfigKey);
+ HashableDimensionKey keyA = getMockDimensionKey(1, "a");
+ HashableDimensionKey keyB = getMockDimensionKey(1, "b");
+ HashableDimensionKey keyC = getMockDimensionKey(1, "c");
+ HashableDimensionKey keyD = getMockDimensionKey(1, "d");
+ HashableDimensionKey keyE = getMockDimensionKey(1, "e");
- std::shared_ptr<DimToValMap> bucket9 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
- std::shared_ptr<DimToValMap> bucket16 = MockBucket({{"b", 4}});
- std::shared_ptr<DimToValMap> bucket18 = MockBucket({{"b", 1}, {"c", 1}});
- std::shared_ptr<DimToValMap> bucket20 = MockBucket({{"b", 3}, {"c", 1}});
- std::shared_ptr<DimToValMap> bucket25 = MockBucket({{"d", 1}});
- std::shared_ptr<DimToValMap> bucket28 = MockBucket({{"e", 2}});
+ std::shared_ptr<DimToValMap> bucket9 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
+ std::shared_ptr<DimToValMap> bucket16 = MockBucket({{keyB, 4}});
+ std::shared_ptr<DimToValMap> bucket18 = MockBucket({{keyB, 1}, {keyC, 1}});
+ std::shared_ptr<DimToValMap> bucket20 = MockBucket({{keyB, 3}, {keyC, 1}});
+ std::shared_ptr<DimToValMap> bucket25 = MockBucket({{keyD, 1}});
+ std::shared_ptr<DimToValMap> bucket28 = MockBucket({{keyE, 2}});
int64_t eventTimestamp1 = bucketSizeNs * 8 + 1;
int64_t eventTimestamp2 = bucketSizeNs * 15 + 11;
@@ -196,9 +216,9 @@
anomalyTracker.addPastBucket(bucket9, 9);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 9L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 1LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(16, *bucket16));
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
@@ -211,27 +231,27 @@
anomalyTracker.addPastBucket(bucket16, 16);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 16L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 4LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(18, *bucket18));
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 4LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
// Within refractory period.
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp3, 18, *bucket18);
EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 4LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
// Add past bucket #18
anomalyTracker.addPastBucket(bucket18, 18);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 18L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(20, *bucket20));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4, 20, *bucket20);
EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
@@ -239,12 +259,12 @@
anomalyTracker.addPastBucket(bucket18, 18);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_TRUE(anomalyTracker.detectAnomaly(20, *bucket20));
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4 + 1, 20, *bucket20);
// Within refractory period.
EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
@@ -253,8 +273,8 @@
anomalyTracker.addPastBucket(bucket20, 20);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 20L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 3LL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 3LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
EXPECT_FALSE(anomalyTracker.detectAnomaly(25, *bucket25));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
@@ -265,7 +285,7 @@
anomalyTracker.addPastBucket(bucket25, 25);
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
- EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("d"), 1LL);
+ EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyD), 1LL);
EXPECT_FALSE(anomalyTracker.detectAnomaly(28, *bucket28));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
@@ -274,7 +294,7 @@
EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
// Updates current bucket #28.
- (*bucket28)["e"] = 5;
+ (*bucket28)[keyE] = 5;
EXPECT_TRUE(anomalyTracker.detectAnomaly(28, *bucket28));
EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 01ba82d..eb0fafe 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -63,7 +63,7 @@
vector<KeyValuePair> kv_list;
kv_list.push_back(kv1);
map<string, HashableDimensionKey> queryKey;
- queryKey[conditionName] = getHashableKey(kv_list);
+ queryKey[conditionName] = HashableDimensionKey(kv_list);
return queryKey;
}
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 51eabd5..eec94539 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "metrics_test_helper.h"
#include "src/metrics/CountMetricProducer.h"
+#include "metrics_test_helper.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -150,13 +150,13 @@
event1.write("111"); // uid
event1.init();
ConditionKey key1;
- key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
+ key1["APP_IN_BACKGROUND_PER_UID"] = getMockedDimensionKey(2, "111");
LogEvent event2(1, bucketStartTimeNs + 10);
event2.write("222"); // uid
event2.init();
ConditionKey key2;
- key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
+ key2["APP_IN_BACKGROUND_PER_UID"] = getMockedDimensionKey(2, "222");
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index e4fc67f..baaac67 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "metrics_test_helper.h"
#include "src/metrics/EventMetricProducer.h"
+#include "metrics_test_helper.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -100,13 +100,13 @@
event1.write("111"); // uid
event1.init();
ConditionKey key1;
- key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
+ key1["APP_IN_BACKGROUND_PER_UID"] = getMockedDimensionKey(2, "111");
LogEvent event2(1, bucketStartTimeNs + 10);
event2.write("222"); // uid
event2.init();
ConditionKey key2;
- key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
+ key2["APP_IN_BACKGROUND_PER_UID"] = getMockedDimensionKey(2, "222");
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 68b7dcb..5204834 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/metrics/GaugeMetricProducer.h"
#include "logd/LogEvent.h"
#include "metrics_test_helper.h"
-#include "src/metrics/GaugeMetricProducer.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 4e5e0d6..7dac0fb 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/metrics/duration_helper/MaxDurationTracker.h"
#include "metrics_test_helper.h"
#include "src/condition/ConditionWizard.h"
-#include "src/metrics/duration_helper/MaxDurationTracker.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -37,13 +37,18 @@
namespace statsd {
const ConfigKey kConfigKey(0, "test");
-const string eventKey = "event";
+
+const HashableDimensionKey eventKey = getMockedDimensionKey(0, "1");
+const HashableDimensionKey conditionKey = getMockedDimensionKey(4, "1");
+const HashableDimensionKey key1 = getMockedDimensionKey(1, "1");
+const HashableDimensionKey key2 = getMockedDimensionKey(1, "2");
TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
- ConditionKey key1;
+ ConditionKey conditionKey1;
+ conditionKey1["condition"] = conditionKey;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
@@ -51,15 +56,15 @@
MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
bucketSizeNs, {});
- tracker.noteStart("1", true, bucketStartTimeNs, key1);
+ tracker.noteStart(key1, true, bucketStartTimeNs, conditionKey1);
// Event starts again. This would not change anything as it already starts.
- tracker.noteStart("1", true, bucketStartTimeNs + 3, key1);
+ tracker.noteStart(key1, true, bucketStartTimeNs + 3, conditionKey1);
// Stopped.
- tracker.noteStop("1", bucketStartTimeNs + 10, false);
+ tracker.noteStop(key1, bucketStartTimeNs + 10, false);
// Another event starts in this bucket.
- tracker.noteStart("2", true, bucketStartTimeNs + 20, key1);
- tracker.noteStop("2", bucketStartTimeNs + 40, false /*stop all*/);
+ tracker.noteStart(key2, true, bucketStartTimeNs + 20, conditionKey1);
+ tracker.noteStop(key2, bucketStartTimeNs + 40, false /*stop all*/);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
@@ -71,7 +76,8 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
- ConditionKey key1;
+ ConditionKey conditionKey1;
+ conditionKey1["condition"] = conditionKey;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
@@ -79,10 +85,10 @@
MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
bucketSizeNs, {});
- tracker.noteStart("1", true, bucketStartTimeNs + 1, key1);
+ tracker.noteStart(key1, true, bucketStartTimeNs + 1, conditionKey1);
// Another event starts in this bucket.
- tracker.noteStart("2", true, bucketStartTimeNs + 20, key1);
+ tracker.noteStart(key2, true, bucketStartTimeNs + 20, conditionKey1);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 40, &buckets);
tracker.noteStopAll(bucketStartTimeNs + bucketSizeNs + 40);
EXPECT_TRUE(tracker.mInfos.empty());
@@ -101,7 +107,8 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
- ConditionKey key1;
+ ConditionKey conditionKey1;
+ conditionKey1["condition"] = conditionKey;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
@@ -110,14 +117,16 @@
bucketSizeNs, {});
// The event starts.
- tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
+ tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 1, conditionKey1);
// Starts again. Does not change anything.
- tracker.noteStart("", true, bucketStartTimeNs + bucketSizeNs + 1, key1);
+ tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + bucketSizeNs + 1,
+ conditionKey1);
// The event stops at early 4th bucket.
tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 20, &buckets);
- tracker.noteStop("", bucketStartTimeNs + (3 * bucketSizeNs) + 20, false /*stop all*/);
+ tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + (3 * bucketSizeNs) + 20,
+ false /*stop all*/);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
EXPECT_EQ(3u, buckets[eventKey].size());
EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[eventKey][0].mDuration);
@@ -129,7 +138,8 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
- ConditionKey key1;
+ ConditionKey conditionKey1;
+ conditionKey1["condition"] = conditionKey;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
@@ -138,10 +148,10 @@
bucketSizeNs, {});
// 2 starts
- tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
- tracker.noteStart("", true, bucketStartTimeNs + 10, key1);
+ tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 1, conditionKey1);
+ tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 10, conditionKey1);
// one stop
- tracker.noteStop("", bucketStartTimeNs + 20, false /*stop all*/);
+ tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + 20, false /*stop all*/);
tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1, &buckets);
@@ -151,7 +161,7 @@
EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
// real stop now.
- tracker.noteStop("", bucketStartTimeNs + (2 * bucketSizeNs) + 5, false);
+ tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + (2 * bucketSizeNs) + 5, false);
tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1, &buckets);
EXPECT_EQ(3u, buckets[eventKey].size());
@@ -163,10 +173,11 @@
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ ConditionKey conditionKey1;
+ HashableDimensionKey eventKey = getMockedDimensionKey(2, "maps");
+ conditionKey1["APP_BACKGROUND"] = conditionKey;
- EXPECT_CALL(*wizard, query(_, key1)) // #4
+ EXPECT_CALL(*wizard, query(_, conditionKey1)) // #4
.WillOnce(Return(ConditionState::kFalse));
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -180,11 +191,11 @@
bucketSizeNs, {});
EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
- tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+ tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
- tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
+ tracker.noteStop(key1, eventStartTimeNs + durationTimeNs, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
@@ -195,15 +206,15 @@
TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
Alert alert;
alert.set_name("alert");
- alert.set_metric_name("1");
+ alert.set_metric_name("metric");
alert.set_trigger_if_sum_gt(32 * NS_PER_SEC);
alert.set_number_of_buckets(2);
alert.set_refractory_period_secs(1);
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ ConditionKey conditionKey1;
+ conditionKey1["APP_BACKGROUND"] = conditionKey;
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
@@ -212,14 +223,14 @@
MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
bucketSizeNs, {anomalyTracker});
- tracker.noteStart("1", true, eventStartTimeNs, key1);
- tracker.noteStop("1", eventStartTimeNs + 10, false);
+ tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
+ tracker.noteStop(key1, eventStartTimeNs + 10, false);
EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs, -1);
EXPECT_EQ(10LL, tracker.mDuration);
- tracker.noteStart("2", true, eventStartTimeNs + 20, key1);
+ tracker.noteStart(key2, true, eventStartTimeNs + 20, conditionKey1);
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, &buckets);
- tracker.noteStop("2", eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, false);
+ tracker.noteStop(key2, eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, false);
EXPECT_EQ((long long)(4 * NS_PER_SEC + 1LL), tracker.mDuration);
EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs,
(long long)(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC));
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 99d3e05..9ec302f 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/metrics/duration_helper/OringDurationTracker.h"
#include "metrics_test_helper.h"
#include "src/condition/ConditionWizard.h"
-#include "src/metrics/duration_helper/OringDurationTracker.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -35,13 +35,17 @@
namespace statsd {
const ConfigKey kConfigKey(0, "test");
-const string eventKey = "event";
+const HashableDimensionKey eventKey = getMockedDimensionKey(0, "event");
+
+const HashableDimensionKey kConditionKey1 = getMockedDimensionKey(1, "maps");
+const HashableDimensionKey kEventKey1 = getMockedDimensionKey(2, "maps");
+const HashableDimensionKey kEventKey2 = getMockedDimensionKey(3, "maps");
TEST(OringDurationTrackerTest, TestDurationOverlap) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -53,12 +57,12 @@
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
bucketStartTimeNs, bucketSizeNs, {});
- tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
- tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, key1); // overlapping wl
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
- tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
@@ -70,7 +74,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -81,11 +85,11 @@
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {});
- tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
- tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, key1); // overlapping wl
- tracker.noteStop("2:maps", eventStartTimeNs + 2000, false);
- tracker.noteStop("2:maps", eventStartTimeNs + 2003, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + 2000, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
@@ -97,7 +101,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -108,8 +112,8 @@
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {});
- tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
- tracker.noteStart("3:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
+ tracker.noteStart(kEventKey2, true, eventStartTimeNs + 10, key1); // overlapping wl
tracker.noteStopAll(eventStartTimeNs + 2003);
@@ -123,7 +127,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
@@ -135,18 +139,18 @@
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {});
- tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs, &buckets);
- tracker.noteStart("2:maps", true, eventStartTimeNs + 2 * bucketSizeNs, key1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2 * bucketSizeNs, key1);
EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
EXPECT_EQ(2u, buckets[eventKey].size());
EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
- tracker.noteStop("2:maps", eventStartTimeNs + 2 * bucketSizeNs + 10, false);
- tracker.noteStop("2:maps", eventStartTimeNs + 2 * bucketSizeNs + 12, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 10, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 12, false);
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
EXPECT_EQ(2u, buckets[eventKey].size());
@@ -158,7 +162,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
@@ -173,11 +177,11 @@
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
bucketStartTimeNs, bucketSizeNs, {});
- tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
- tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
@@ -189,7 +193,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
EXPECT_CALL(*wizard, query(_, key1))
.Times(2)
@@ -206,13 +210,13 @@
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
bucketStartTimeNs, bucketSizeNs, {});
- tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
// condition to false; record duration 5n
tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
// condition to true.
tracker.onSlicedConditionMayChange(eventStartTimeNs + 1000);
// 2nd duration: 1000ns
- tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
@@ -224,7 +228,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
@@ -238,14 +242,14 @@
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {});
- tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
- tracker.noteStart("2:maps", true, eventStartTimeNs + 2, key1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2, key1);
- tracker.noteStop("2:maps", eventStartTimeNs + 3, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + 3, false);
tracker.onSlicedConditionMayChange(eventStartTimeNs + 15);
- tracker.noteStop("2:maps", eventStartTimeNs + 2003, false);
+ tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
@@ -264,7 +268,7 @@
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
@@ -274,22 +278,22 @@
bucketSizeNs, {anomalyTracker});
// Nothing in the past bucket.
- tracker.noteStart("", true, eventStartTimeNs, key1);
+ tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
EXPECT_EQ((long long)(alert.trigger_if_sum_gt() + eventStartTimeNs),
tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
- tracker.noteStop("", eventStartTimeNs + 3, false);
+ tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 3, false);
EXPECT_EQ(0u, buckets[eventKey].size());
uint64_t event1StartTimeNs = eventStartTimeNs + 10;
- tracker.noteStart("1", true, event1StartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, event1StartTimeNs, key1);
// No past buckets. The anomaly will happen in bucket #0.
EXPECT_EQ((long long)(event1StartTimeNs + alert.trigger_if_sum_gt() - 3),
tracker.predictAnomalyTimestampNs(*anomalyTracker, event1StartTimeNs));
uint64_t event1StopTimeNs = eventStartTimeNs + bucketSizeNs + 10;
tracker.flushIfNeeded(event1StopTimeNs, &buckets);
- tracker.noteStop("1", event1StopTimeNs, false);
+ tracker.noteStop(kEventKey1, event1StopTimeNs, false);
EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
EXPECT_EQ(1u, buckets[eventKey].size());
@@ -301,16 +305,16 @@
// One past buckets. The anomaly will happen in bucket #1.
uint64_t event2StartTimeNs = eventStartTimeNs + bucketSizeNs + 15;
- tracker.noteStart("1", true, event2StartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, event2StartTimeNs, key1);
EXPECT_EQ((long long)(event2StartTimeNs + alert.trigger_if_sum_gt() - bucket0Duration -
bucket1Duration),
tracker.predictAnomalyTimestampNs(*anomalyTracker, event2StartTimeNs));
- tracker.noteStop("1", event2StartTimeNs + 1, false);
+ tracker.noteStop(kEventKey1, event2StartTimeNs + 1, false);
// Only one past buckets is applicable. Bucket +0 should be trashed. The anomaly will happen in
// bucket #2.
uint64_t event3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs - 9 * NS_PER_SEC;
- tracker.noteStart("1", true, event3StartTimeNs, key1);
+ tracker.noteStart(kEventKey1, true, event3StartTimeNs, key1);
EXPECT_EQ((long long)(event3StartTimeNs + alert.trigger_if_sum_gt() - bucket1Duration - 1LL),
tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs));
}
@@ -326,7 +330,7 @@
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
- key1["APP_BACKGROUND"] = "1:maps|";
+ key1["APP_BACKGROUND"] = kConditionKey1;
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
@@ -335,21 +339,21 @@
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
- tracker.noteStart("", true, eventStartTimeNs, key1);
- tracker.noteStop("", eventStartTimeNs + 10, false);
+ tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
+ tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 10, false);
EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs, -1);
EXPECT_TRUE(tracker.mStarted.empty());
EXPECT_EQ(10LL, tracker.mDuration);
EXPECT_EQ(0u, tracker.mStarted.size());
- tracker.noteStart("", true, eventStartTimeNs + 20, key1);
+ tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs + 20, key1);
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
(long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
- tracker.noteStop("", eventStartTimeNs + 2 * bucketSizeNs + 25, false);
- EXPECT_EQ(anomalyTracker->getSumOverPastBuckets("event"), (long long)(bucketSizeNs));
+ tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
+ EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
anomalyTracker->mLastAlarmTimestampNs);
}
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.cpp b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
new file mode 100644
index 0000000..a0a854a
--- /dev/null
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "metrics_test_helper.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+HashableDimensionKey getMockedDimensionKey(int key, string value) {
+ KeyValuePair pair;
+ pair.set_key(key);
+ pair.set_value_str(value);
+
+ vector<KeyValuePair> pairs;
+ pairs.push_back(pair);
+
+ return HashableDimensionKey(pairs);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index fa221aa..7cb3329 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -38,6 +38,8 @@
MOCK_METHOD2(Pull, bool(const int pullCode, vector<std::shared_ptr<LogEvent>>* data));
};
+HashableDimensionKey getMockedDimensionKey(int key, std::string value);
+
} // namespace statsd
} // namespace os
-} // namespace android
+} // namespace android
\ No newline at end of file