diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 3e517bb0a029a..f98ee3de2c953 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -54,7 +54,7 @@ statsd_common_src := \ 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 @@ LOCAL_SRC_FILES := \ 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 0000000000000..0b6f8f2b335d5 --- /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 0000000000000..85215552b777e --- /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 +#include "frameworks/base/cmds/statsd/src/stats_log.pb.h" + +namespace android { +namespace os { +namespace statsd { + +class HashableDimensionKey { +public: + explicit HashableDimensionKey(const std::vector& 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& 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 mKeyValuePairs; +}; + +} // namespace statsd +} // namespace os +} // namespace android + +namespace std { + +using android::os::statsd::HashableDimensionKey; +using android::os::statsd::KeyValuePair; + +template <> +struct hash { + 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(pair.value_case()))); + switch (pair.value_case()) { + case KeyValuePair::ValueCase::kValueStr: + hash = android::JenkinsHashMix( + hash, + static_cast(std::hash()(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(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 18b93ee0fd47f..a63bc042284ad 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp +++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp @@ -279,7 +279,7 @@ void SimpleConditionTracker::evaluateCondition(const LogEvent& event, } // 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 ff0e3bc0d21ab..53ef9d58b8893 100644 --- a/cmds/statsd/src/condition/condition_util.cpp +++ b/cmds/statsd/src/condition/condition_util.cpp @@ -109,7 +109,7 @@ HashableDimensionKey getDimensionKeyForCondition(const LogEvent& event, 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 bc12a788a2b69..9031ed018df2c 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -107,17 +107,14 @@ void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, for (const auto& counter : mPastBuckets) { const HashableDimensionKey& hashableKey = counter.first; + const vector& 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 220861d6f9798..1c8f422eca61f 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -159,18 +159,14 @@ void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, for (const auto& pair : mPastBuckets) { const HashableDimensionKey& hashableKey = pair.first; + const vector& 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 @@ void DurationMetricProducer::onMatchedLogEventInternalLocked( 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 640263300f77e..47cca0e238926 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -128,18 +128,14 @@ void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, 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& 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 f38f3df13d9b0..528690832f03b 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -32,12 +32,7 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo if (mDimension.size() > 0) { vector key = getDimensionKey(event, mDimension); - eventKey = getHashableKey(key); - // Add the HashableDimensionKey->vector to the map, because StatsLogReport - // expects vector. - if (mDimensionKeyMap.find(eventKey) == mDimensionKeyMap.end()) { - mDimensionKeyMap[eventKey] = key; - } + eventKey = HashableDimensionKey(key); } else { eventKey = DEFAULT_DIMENSION_KEY; } @@ -58,7 +53,6 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo } 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 7bd274dc129bb..85ef4ada07d8d 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -49,10 +49,7 @@ public: 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(); - }; + mConditionTrackerIndex(conditionIndex){}; virtual ~MetricProducer(){}; void notifyAppUpgrade(const string& apk, const int uid, const int64_t version) override{ @@ -145,10 +142,6 @@ protected: std::vector mDimension; // The dimension defined in statsd_config - // Keep the map from the internal HashableDimensionKey to std::vector - // that StatsLogReport wants. - std::unordered_map> mDimensionKeyMap; - std::vector mConditionLinks; std::vector> mAnomalyTrackers; diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 7efa6cd179e6c..40aed7bcf9347 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -132,16 +132,12 @@ void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, 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& 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 95c8a59bf8c59..6050f4395a5ff 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp @@ -42,7 +42,7 @@ bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) { // 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 36e25edfccd2f..5c430961036d0 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp @@ -45,7 +45,7 @@ bool OringDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) { } 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 7527a6455b056..0000000000000 --- 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. -HashableDimensionKey getHashableKey(std::vector 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 8fd1ea8c0d327..1cdf031c78581 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 +#include "HashableDimensionKey.h" +#include "frameworks/base/cmds/statsd/src/stats_log.pb.h" #include "logd/LogReader.h" #include @@ -26,13 +27,11 @@ namespace android { namespace os { namespace statsd { -#define DEFAULT_DIMENSION_KEY "" +const HashableDimensionKey DEFAULT_DIMENSION_KEY = HashableDimensionKey(vector()); // Minimum bucket size in seconds const long kMinBucketSizeSec = 5 * 60; -typedef std::string HashableDimensionKey; - typedef std::map ConditionKey; typedef std::unordered_map DimToValMap; @@ -67,13 +66,6 @@ typedef struct EventKV { } EventKV; typedef std::unordered_map> DimToEventKVMap; - -EventMetricData parse(log_msg msg); - -int getTagId(log_msg msg); - -std::string getHashableKey(std::vector 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 f38576398f116..f62171d57a5a1 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 #include @@ -32,7 +33,18 @@ namespace statsd { const ConfigKey kConfigKey(0, "test"); -void AddValueToBucket(const std::vector>& key_value_pair_list, +HashableDimensionKey getMockDimensionKey(int key, string value) { + KeyValuePair pair; + pair.set_key(key); + pair.set_value_str(value); + + vector pairs; + pairs.push_back(pair); + + return HashableDimensionKey(pairs); +} + +void AddValueToBucket(const std::vector>& key_value_pair_list, std::shared_ptr 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 @@ void AddValueToBucket(const std::vector>& key_value_pair } std::shared_ptr MockBucket( - const std::vector>& key_value_pair_list) { + const std::vector>& key_value_pair_list) { std::shared_ptr bucket = std::make_shared(); AddValueToBucket(key_value_pair_list, bucket); return bucket; @@ -54,20 +66,23 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { 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 bucket0 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}}); + std::shared_ptr bucket0 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}}); int64_t eventTimestamp0 = 10; - std::shared_ptr bucket1 = MockBucket({{"a", 1}}); + std::shared_ptr bucket1 = MockBucket({{keyA, 1}}); int64_t eventTimestamp1 = bucketSizeNs + 11; - std::shared_ptr bucket2 = MockBucket({{"b", 1}}); + std::shared_ptr bucket2 = MockBucket({{keyB, 1}}); int64_t eventTimestamp2 = 2 * bucketSizeNs + 12; - std::shared_ptr bucket3 = MockBucket({{"a", 2}}); + std::shared_ptr bucket3 = MockBucket({{keyA, 2}}); int64_t eventTimestamp3 = 3 * bucketSizeNs + 13; - std::shared_ptr bucket4 = MockBucket({{"b", 1}}); + std::shared_ptr bucket4 = MockBucket({{keyB, 1}}); int64_t eventTimestamp4 = 4 * bucketSizeNs + 14; - std::shared_ptr bucket5 = MockBucket({{"a", 2}}); + std::shared_ptr bucket5 = MockBucket({{keyA, 2}}); int64_t eventTimestamp5 = 5 * bucketSizeNs + 15; - std::shared_ptr bucket6 = MockBucket({{"a", 2}}); + std::shared_ptr bucket6 = MockBucket({{keyA, 2}}); int64_t eventTimestamp6 = 6 * bucketSizeNs + 16; EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u); @@ -79,9 +94,9 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { // 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 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { // 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 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) { 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 bucket9 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}}); - std::shared_ptr bucket16 = MockBucket({{"b", 4}}); - std::shared_ptr bucket18 = MockBucket({{"b", 1}, {"c", 1}}); - std::shared_ptr bucket20 = MockBucket({{"b", 3}, {"c", 1}}); - std::shared_ptr bucket25 = MockBucket({{"d", 1}}); - std::shared_ptr bucket28 = MockBucket({{"e", 2}}); + std::shared_ptr bucket9 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}}); + std::shared_ptr bucket16 = MockBucket({{keyB, 4}}); + std::shared_ptr bucket18 = MockBucket({{keyB, 1}, {keyC, 1}}); + std::shared_ptr bucket20 = MockBucket({{keyB, 3}, {keyC, 1}}); + std::shared_ptr bucket25 = MockBucket({{keyD, 1}}); + std::shared_ptr bucket28 = MockBucket({{keyE, 2}}); int64_t eventTimestamp1 = bucketSizeNs * 8 + 1; int64_t eventTimestamp2 = bucketSizeNs * 15 + 11; @@ -196,9 +216,9 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) { 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 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) { 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 01ba82d31549c..eb0fafe781c64 100644 --- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp @@ -63,7 +63,7 @@ map getWakeLockQueryKey(int key, int uid, vector kv_list; kv_list.push_back(kv1); map 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 51eabd5387c17..eec9453940dcf 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 #include @@ -150,13 +150,13 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) { 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 wizard = new NaggyMock(); 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 e4fc67f95ec0b..baaac67f395b8 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 #include @@ -100,13 +100,13 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) { 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 wizard = new NaggyMock(); 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 68b7dcb641003..5204834634ce5 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 #include diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp index 4e5e0d6dbfb37..7dac0fbb38a04 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 #include @@ -37,13 +37,18 @@ namespace os { 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 wizard = new NaggyMock(); unordered_map> buckets; - ConditionKey key1; + ConditionKey conditionKey1; + conditionKey1["condition"] = conditionKey; uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; @@ -51,15 +56,15 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) { 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 @@ TEST(MaxDurationTrackerTest, TestStopAll) { sp wizard = new NaggyMock(); unordered_map> buckets; - ConditionKey key1; + ConditionKey conditionKey1; + conditionKey1["condition"] = conditionKey; uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; @@ -79,10 +85,10 @@ TEST(MaxDurationTrackerTest, TestStopAll) { 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 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) { sp wizard = new NaggyMock(); unordered_map> buckets; - ConditionKey key1; + ConditionKey conditionKey1; + conditionKey1["condition"] = conditionKey; uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; @@ -110,14 +117,16 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) { 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 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) { sp wizard = new NaggyMock(); unordered_map> buckets; - ConditionKey key1; + ConditionKey conditionKey1; + conditionKey1["condition"] = conditionKey; uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; @@ -138,10 +148,10 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) { 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 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) { 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, TestCrossBucketBoundary_nested) { TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) { sp wizard = new NaggyMock(); - 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> buckets; @@ -180,11 +191,11 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) { 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, TestMaxDurationWithCondition) { 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> buckets; sp wizard = new NaggyMock(); - 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 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) { 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 99d3e054d893b..9ec302fbfd7d0 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 #include @@ -35,13 +35,17 @@ namespace os { 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 wizard = new NaggyMock(); ConditionKey key1; - key1["APP_BACKGROUND"] = "1:maps|"; + key1["APP_BACKGROUND"] = kConditionKey1; unordered_map> buckets; @@ -53,12 +57,12 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) { 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 @@ TEST(OringDurationTrackerTest, TestDurationNested) { sp wizard = new NaggyMock(); ConditionKey key1; - key1["APP_BACKGROUND"] = "1:maps|"; + key1["APP_BACKGROUND"] = kConditionKey1; unordered_map> buckets; @@ -81,11 +85,11 @@ TEST(OringDurationTrackerTest, TestDurationNested) { 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 @@ TEST(OringDurationTrackerTest, TestStopAll) { sp wizard = new NaggyMock(); ConditionKey key1; - key1["APP_BACKGROUND"] = "1:maps|"; + key1["APP_BACKGROUND"] = kConditionKey1; unordered_map> buckets; @@ -108,8 +112,8 @@ TEST(OringDurationTrackerTest, TestStopAll) { 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 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) { sp wizard = new NaggyMock(); ConditionKey key1; - key1["APP_BACKGROUND"] = "1:maps|"; + key1["APP_BACKGROUND"] = kConditionKey1; unordered_map> buckets; @@ -135,18 +139,18 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) { 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 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) { sp wizard = new NaggyMock(); 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 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) { 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 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) { sp wizard = new NaggyMock(); ConditionKey key1; - key1["APP_BACKGROUND"] = "1:maps|"; + key1["APP_BACKGROUND"] = kConditionKey1; EXPECT_CALL(*wizard, query(_, key1)) .Times(2) @@ -206,13 +210,13 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) { 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 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) { sp wizard = new NaggyMock(); 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 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) { 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 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) { unordered_map> buckets; sp wizard = new NaggyMock(); 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 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) { 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 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) { // 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 @@ TEST(OringDurationTrackerTest, TestAnomalyDetection) { unordered_map> buckets; sp wizard = new NaggyMock(); 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 @@ TEST(OringDurationTrackerTest, TestAnomalyDetection) { 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 0000000000000..a0a854a28d36f --- /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 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 fa221aae17313..7cb3329530165 100644 --- a/cmds/statsd/tests/metrics/metrics_test_helper.h +++ b/cmds/statsd/tests/metrics/metrics_test_helper.h @@ -38,6 +38,8 @@ public: MOCK_METHOD2(Pull, bool(const int pullCode, vector>* data)); }; +HashableDimensionKey getMockedDimensionKey(int key, std::string value); + } // namespace statsd } // namespace os -} // namespace android +} // namespace android \ No newline at end of file