13eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// Copyright (C) 2017 The Android Open Source Project
23eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu//
33eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// Licensed under the Apache License, Version 2.0 (the "License");
43eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// you may not use this file except in compliance with the License.
53eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// You may obtain a copy of the License at
63eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu//
73eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu//      http://www.apache.org/licenses/LICENSE-2.0
83eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu//
93eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// Unless required by applicable law or agreed to in writing, software
103eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// distributed under the License is distributed on an "AS IS" BASIS,
113eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// See the License for the specific language governing permissions and
133eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu// limitations under the License.
143eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
15e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac#include "src/anomaly/AnomalyTracker.h"
16d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen#include "../metrics/metrics_test_helper.h"
173eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
183eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu#include <gtest/gtest.h>
196bf9825b1575bfc3c62ef0a5129f94b6a776ef66Bookatz#include <math.h>
203eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu#include <stdio.h>
213eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu#include <vector>
223eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
233eba62186592382ed3d97cecca0c547487e4b2e4Yang Luusing namespace testing;
243eba62186592382ed3d97cecca0c547487e4b2e4Yang Luusing android::sp;
253eba62186592382ed3d97cecca0c547487e4b2e4Yang Luusing std::set;
263eba62186592382ed3d97cecca0c547487e4b2e4Yang Luusing std::unordered_map;
273eba62186592382ed3d97cecca0c547487e4b2e4Yang Luusing std::vector;
283eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
293eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu#ifdef __ANDROID__
303eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
313eba62186592382ed3d97cecca0c547487e4b2e4Yang Lunamespace android {
323eba62186592382ed3d97cecca0c547487e4b2e4Yang Lunamespace os {
333eba62186592382ed3d97cecca0c547487e4b2e4Yang Lunamespace statsd {
343eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
3594e197cceb2ba7df13ff8de04f60bfeec64015d9Yangster-macconst ConfigKey kConfigKey(0, 12345);
368f2f3d82053693b0dac828e848e2bb238e1db2d2Bookatz
379369446f0b04945d6674550728ae81196d6fb5c2Yangster-macMetricDimensionKey getMockMetricDimensionKey(int key, string value) {
388a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen    int pos[] = {key, 0, 0};
398a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen    HashableDimensionKey dim;
408a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen    dim.addValue(FieldValue(Field(1, pos, 0), Value(value)));
418a8d16ceea1e5b7a2f8c41e17b5d993035f50f5dYao Chen    return MetricDimensionKey(dim, DEFAULT_DIMENSION_KEY);
42d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen}
43d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen
449369446f0b04945d6674550728ae81196d6fb5c2Yangster-macvoid AddValueToBucket(const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list,
453eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu                      std::shared_ptr<DimToValMap> bucket) {
463eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
473eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu        (*bucket)[itr->first] += itr->second;
483eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    }
493eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu}
503eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
51e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-macstd::shared_ptr<DimToValMap> MockBucket(
529369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac        const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list) {
533eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
543eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    AddValueToBucket(key_value_pair_list, bucket);
553eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    return bucket;
563eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu}
573eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
581bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz// Returns the value, for the given key, in that bucket, or 0 if not present.
591bf94382d036fa8d61258205c5f4e18cd53cb61dBookatzint64_t getBucketValue(const std::shared_ptr<DimToValMap>& bucket,
609369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac                       const MetricDimensionKey& key) {
611bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    const auto& itr = bucket->find(key);
621bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    if (itr != bucket->end()) {
631bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        return itr->second;
641bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    }
651bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    return 0;
661bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz}
671bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
681bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz// Returns true if keys in trueList are detected as anomalies and keys in falseList are not.
691bf94382d036fa8d61258205c5f4e18cd53cb61dBookatzbool detectAnomaliesPass(AnomalyTracker& tracker,
701bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                         const int64_t& bucketNum,
711bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                         const std::shared_ptr<DimToValMap>& currentBucket,
729369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac                         const std::set<const MetricDimensionKey>& trueList,
739369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac                         const std::set<const MetricDimensionKey>& falseList) {
749369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    for (MetricDimensionKey key : trueList) {
751bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        if (!tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
761bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            return false;
771bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        }
781bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    }
799369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    for (MetricDimensionKey key : falseList) {
801bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        if (tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
811bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            return false;
821bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        }
831bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    }
841bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    return true;
851bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz}
861bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
871bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz// Calls tracker.detectAndDeclareAnomaly on each key in the bucket.
881bf94382d036fa8d61258205c5f4e18cd53cb61dBookatzvoid detectAndDeclareAnomalies(AnomalyTracker& tracker,
891bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                               const int64_t& bucketNum,
901bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                               const std::shared_ptr<DimToValMap>& bucket,
911bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                               const int64_t& eventTimestamp) {
921bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    for (const auto& kv : *bucket) {
931bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, kv.first, kv.second);
941bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    }
951bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz}
961bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
971bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz// Asserts that the refractory time for each key in timestamps is the corresponding
981bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz// timestamp (in ns) + refractoryPeriodSec.
991bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz// If a timestamp value is negative, instead asserts that the refractory period is inapplicable
1001bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz// (either non-existant or already past).
1011bf94382d036fa8d61258205c5f4e18cd53cb61dBookatzvoid checkRefractoryTimes(AnomalyTracker& tracker,
1021bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                          const int64_t& currTimestampNs,
1031bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                          const int32_t& refractoryPeriodSec,
1049369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac                          const std::unordered_map<MetricDimensionKey, int64_t>& timestamps) {
1051bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    for (const auto& kv : timestamps) {
1061bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        if (kv.second < 0) {
1071bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            // Make sure that, if there is a refractory period, it is already past.
1086bf9825b1575bfc3c62ef0a5129f94b6a776ef66Bookatz            EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first) * NS_PER_SEC,
1096bf9825b1575bfc3c62ef0a5129f94b6a776ef66Bookatz                    (uint64_t)currTimestampNs)
1101bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                    << "Failure was at currTimestampNs " << currTimestampNs;
1111bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        } else {
1121bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            EXPECT_EQ(tracker.getRefractoryPeriodEndsSec(kv.first),
1136bf9825b1575bfc3c62ef0a5129f94b6a776ef66Bookatz                      std::ceil(1.0 * kv.second / NS_PER_SEC) + refractoryPeriodSec)
1141bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz                      << "Failure was at currTimestampNs " << currTimestampNs;
1151bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz        }
1161bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    }
1171bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz}
1181bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
1193eba62186592382ed3d97cecca0c547487e4b2e4Yang LuTEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
120e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    const int64_t bucketSizeNs = 30 * NS_PER_SEC;
1211bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC;
1223eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    Alert alert;
123a7fb12d2d285a3a62f5e8956d1bacfa0e15e9d0fYangster-mac    alert.set_num_buckets(3);
1241bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    alert.set_refractory_period_secs(refractoryPeriodSec);
1253eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    alert.set_trigger_if_sum_gt(2);
1263eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
1278f2f3d82053693b0dac828e848e2bb238e1db2d2Bookatz    AnomalyTracker anomalyTracker(alert, kConfigKey);
1289369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey keyA = getMockMetricDimensionKey(1, "a");
1299369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey keyB = getMockMetricDimensionKey(1, "b");
1309369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey keyC = getMockMetricDimensionKey(1, "c");
131e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
1321bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    int64_t eventTimestamp0 = 10 * NS_PER_SEC;
1331bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    int64_t eventTimestamp1 = bucketSizeNs + 11 * NS_PER_SEC;
1341bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    int64_t eventTimestamp2 = 2 * bucketSizeNs + 12 * NS_PER_SEC;
1351bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    int64_t eventTimestamp3 = 3 * bucketSizeNs + 13 * NS_PER_SEC;
1361bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    int64_t eventTimestamp4 = 4 * bucketSizeNs + 14 * NS_PER_SEC;
1371bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    int64_t eventTimestamp5 = 5 * bucketSizeNs + 5 * NS_PER_SEC;
1381bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    int64_t eventTimestamp6 = 6 * bucketSizeNs + 16 * NS_PER_SEC;
1391bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
140d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket0 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
141d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket1 = MockBucket({{keyA, 1}});
142d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket2 = MockBucket({{keyB, 1}});
143d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket3 = MockBucket({{keyA, 2}});
1441bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    std::shared_ptr<DimToValMap> bucket4 = MockBucket({{keyB, 5}});
145d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket5 = MockBucket({{keyA, 2}});
146d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket6 = MockBucket({{keyA, 2}});
147e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
1481bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Start time with no events.
149e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u);
150e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
1511bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
1521bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Event from bucket #0 occurs.
1531bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 0, bucket0, {}, {keyA, keyB, keyC}));
1541bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 0, bucket0, eventTimestamp1);
1551bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp0, refractoryPeriodSec,
1561bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, -1}, {keyC, -1}});
157e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
158e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Adds past bucket #0
159e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket0, 0);
160e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
161d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
162d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
163d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
164e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
1651bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
1661bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Event from bucket #1 occurs.
1671bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC}));
1681bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1);
1691bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
1701bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, -1}, {keyC, -1}});
171e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
172e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Adds past bucket #0 again. The sum does not change.
173e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket0, 0);
174e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
175d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
176d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
177d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
178e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
1791bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC}));
1801bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1 + 1);
1811bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
1821bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, -1}, {keyC, -1}});
183e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
184e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Adds past bucket #1.
185e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket1, 1);
186e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
187e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
188d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
189d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
190d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
1911bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
1921bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Event from bucket #2 occurs. New anomaly on keyB.
1931bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC}));
1941bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2);
1951bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
1961bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}});
197e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
198e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Adds past bucket #1 again. Nothing changes.
199e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket1, 1);
200e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
201e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
202d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
203d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
204d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
2051bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Event from bucket #2 occurs (again).
2061bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC}));
2071bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2 + 1);
2081bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
2091bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}});
210e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
211e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Adds past bucket #2.
212e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket2, 2);
213e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 2L);
214e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
215d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
216d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
2171bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
2181bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Event from bucket #3 occurs. New anomaly on keyA.
2191bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 3, bucket3, {keyA}, {keyB, keyC}));
2201bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 3, bucket3, eventTimestamp3);
2211bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
2221bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, eventTimestamp3}, {keyB, eventTimestamp2}, {keyC, -1}});
2233eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
2243eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    // Adds bucket #3.
225e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket3, 3L);
226e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 3L);
227e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
228d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
229d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
2301bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
2311bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Event from bucket #4 occurs. New anomaly on keyB.
2321bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 4, bucket4, {keyB}, {keyA, keyC}));
2331bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 4, bucket4, eventTimestamp4);
2341bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec,
2351bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}});
2363eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
237e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Adds bucket #4.
238e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket4, 4);
239e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 4L);
240e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
241d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
2421bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
2431bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
2441bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Event from bucket #5 occurs. New anomaly on keyA, which is still in refractory.
2451bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 5, bucket5, {keyA, keyB}, {keyC}));
2461bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 5, bucket5, eventTimestamp5);
2471bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
2481bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}});
249e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
250e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Adds bucket #5.
251e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket5, 5);
252e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 5L);
253e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
254d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
2551bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
2561bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz
2571bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // Event from bucket #6 occurs. New anomaly on keyA, which is now out of refractory.
2581bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 6, bucket6, {keyA, keyB}, {keyC}));
2591bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 6, bucket6, eventTimestamp6);
2601bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
2611bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, eventTimestamp6}, {keyB, eventTimestamp4}, {keyC, -1}});
2623eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu}
2633eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
2643eba62186592382ed3d97cecca0c547487e4b2e4Yang LuTEST(AnomalyTrackerTest, TestSparseBuckets) {
265e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    const int64_t bucketSizeNs = 30 * NS_PER_SEC;
2661bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC;
2673eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    Alert alert;
268a7fb12d2d285a3a62f5e8956d1bacfa0e15e9d0fYangster-mac    alert.set_num_buckets(3);
2691bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    alert.set_refractory_period_secs(refractoryPeriodSec);
2703eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    alert.set_trigger_if_sum_gt(2);
2713eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
2728f2f3d82053693b0dac828e848e2bb238e1db2d2Bookatz    AnomalyTracker anomalyTracker(alert, kConfigKey);
2739369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey keyA = getMockMetricDimensionKey(1, "a");
2749369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey keyB = getMockMetricDimensionKey(1, "b");
2759369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey keyC = getMockMetricDimensionKey(1, "c");
2769369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey keyD = getMockMetricDimensionKey(1, "d");
2779369446f0b04945d6674550728ae81196d6fb5c2Yangster-mac    MetricDimensionKey keyE = getMockMetricDimensionKey(1, "e");
278d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen
279d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket9 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
280d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket16 = MockBucket({{keyB, 4}});
281d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket18 = MockBucket({{keyB, 1}, {keyC, 1}});
282d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket20 = MockBucket({{keyB, 3}, {keyC, 1}});
283d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket25 = MockBucket({{keyD, 1}});
284d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    std::shared_ptr<DimToValMap> bucket28 = MockBucket({{keyE, 2}});
285e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
286e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    int64_t eventTimestamp1 = bucketSizeNs * 8 + 1;
287e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    int64_t eventTimestamp2 = bucketSizeNs * 15 + 11;
288e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    int64_t eventTimestamp3 = bucketSizeNs * 17 + 1;
289e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    int64_t eventTimestamp4 = bucketSizeNs * 19 + 2;
290e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    int64_t eventTimestamp5 = bucketSizeNs * 24 + 3;
291e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    int64_t eventTimestamp6 = bucketSizeNs * 27 + 3;
292e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
293e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
294e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
2951bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 9, bucket9, {}, {keyA, keyB, keyC, keyD}));
2961bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 9, bucket9, eventTimestamp1);
2971bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
2981bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
299e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
300e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Add past bucket #9
301e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket9, 9);
302e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 9L);
303e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
304d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
305d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
306d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
3071bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 16, bucket16, {keyB}, {keyA, keyC, keyD}));
3081bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
309e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
3101bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 16, bucket16, eventTimestamp2);
3111bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
312e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
3131bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
3141bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
315e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
316e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Add past bucket #16
317e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket16, 16);
318e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 16L);
319e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
320d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
3211bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 18, bucket18, {keyB}, {keyA, keyC, keyD}));
322e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
323d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
324e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Within refractory period.
3251bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 18, bucket18, eventTimestamp3);
3261bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
3271bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
328e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
329d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
330e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
331e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Add past bucket #18
332e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket18, 18);
333e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 18L);
334e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
335d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
336d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
3371bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
338e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
339e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
340d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
341d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
3421bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4);
3431bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec,
3441bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
345e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
346e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Add bucket #18 again. Nothing changes.
347e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket18, 18);
348e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
349e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
350d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
351d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
3521bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
353e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
354d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
355d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
3561bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4 + 1);
3573eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu    // Within refractory period.
3581bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp4 + 1, refractoryPeriodSec,
3591bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
360e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
361e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Add past bucket #20
362e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket20, 20);
363e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 20L);
364e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
365d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 3LL);
366d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
3671bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 25, bucket25, {}, {keyA, keyB, keyC, keyD}));
368e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
3691bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
3701bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 25, bucket25, eventTimestamp5);
3711bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
3721bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
373e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
374e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Add past bucket #25
375e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    anomalyTracker.addPastBucket(bucket25, 25);
376e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L);
3771bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
378d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyD), 1LL);
3791bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {},
3801bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {keyA, keyB, keyC, keyD, keyE}));
381e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
3821bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
3831bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6);
3841bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
3851bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
3861bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
387e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac
388e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    // Updates current bucket #28.
389d5aa01b3716e07463019fa772f07a40613f9e39eYao Chen    (*bucket28)[keyE] = 5;
3901bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {keyE},
3911bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {keyA, keyB, keyC, keyD}));
392e2cd6d509b17894b95d14523ae3e7c4c7a9a74e3Yangster-mac    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
3931bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
3941bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6 + 7);
3951bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
3961bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz    checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
3971bf94382d036fa8d61258205c5f4e18cd53cb61dBookatz            {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, eventTimestamp6 + 7}});
3983eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu}
3993eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu
4003eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu}  // namespace statsd
4013eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu}  // namespace os
4023eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu}  // namespace android
4033eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu#else
4043eba62186592382ed3d97cecca0c547487e4b2e4Yang LuGTEST_LOG_(INFO) << "This test does nothing.\n";
4053eba62186592382ed3d97cecca0c547487e4b2e4Yang Lu#endif
406