1 // Copyright (C) 2017 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "src/anomaly/AnomalyTracker.h" 16 #include "../metrics/metrics_test_helper.h" 17 18 #include <gtest/gtest.h> 19 #include <math.h> 20 #include <stdio.h> 21 #include <vector> 22 23 using namespace testing; 24 using android::sp; 25 using std::set; 26 using std::unordered_map; 27 using std::vector; 28 29 #ifdef __ANDROID__ 30 31 namespace android { 32 namespace os { 33 namespace statsd { 34 35 const ConfigKey kConfigKey(0, 12345); 36 37 MetricDimensionKey getMockMetricDimensionKey(int key, string value) { 38 int pos[] = {key, 0, 0}; 39 HashableDimensionKey dim; 40 dim.addValue(FieldValue(Field(1, pos, 0), Value(value))); 41 return MetricDimensionKey(dim, DEFAULT_DIMENSION_KEY); 42 } 43 44 void AddValueToBucket(const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list, 45 std::shared_ptr<DimToValMap> bucket) { 46 for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) { 47 (*bucket)[itr->first] += itr->second; 48 } 49 } 50 51 std::shared_ptr<DimToValMap> MockBucket( 52 const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list) { 53 std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>(); 54 AddValueToBucket(key_value_pair_list, bucket); 55 return bucket; 56 } 57 58 // Returns the value, for the given key, in that bucket, or 0 if not present. 59 int64_t getBucketValue(const std::shared_ptr<DimToValMap>& bucket, 60 const MetricDimensionKey& key) { 61 const auto& itr = bucket->find(key); 62 if (itr != bucket->end()) { 63 return itr->second; 64 } 65 return 0; 66 } 67 68 // Returns true if keys in trueList are detected as anomalies and keys in falseList are not. 69 bool detectAnomaliesPass(AnomalyTracker& tracker, 70 const int64_t& bucketNum, 71 const std::shared_ptr<DimToValMap>& currentBucket, 72 const std::set<const MetricDimensionKey>& trueList, 73 const std::set<const MetricDimensionKey>& falseList) { 74 for (MetricDimensionKey key : trueList) { 75 if (!tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) { 76 return false; 77 } 78 } 79 for (MetricDimensionKey key : falseList) { 80 if (tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) { 81 return false; 82 } 83 } 84 return true; 85 } 86 87 // Calls tracker.detectAndDeclareAnomaly on each key in the bucket. 88 void detectAndDeclareAnomalies(AnomalyTracker& tracker, 89 const int64_t& bucketNum, 90 const std::shared_ptr<DimToValMap>& bucket, 91 const int64_t& eventTimestamp) { 92 for (const auto& kv : *bucket) { 93 tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, kv.first, kv.second); 94 } 95 } 96 97 // Asserts that the refractory time for each key in timestamps is the corresponding 98 // timestamp (in ns) + refractoryPeriodSec. 99 // If a timestamp value is negative, instead asserts that the refractory period is inapplicable 100 // (either non-existant or already past). 101 void checkRefractoryTimes(AnomalyTracker& tracker, 102 const int64_t& currTimestampNs, 103 const int32_t& refractoryPeriodSec, 104 const std::unordered_map<MetricDimensionKey, int64_t>& timestamps) { 105 for (const auto& kv : timestamps) { 106 if (kv.second < 0) { 107 // Make sure that, if there is a refractory period, it is already past. 108 EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first) * NS_PER_SEC, 109 (uint64_t)currTimestampNs) 110 << "Failure was at currTimestampNs " << currTimestampNs; 111 } else { 112 EXPECT_EQ(tracker.getRefractoryPeriodEndsSec(kv.first), 113 std::ceil(1.0 * kv.second / NS_PER_SEC) + refractoryPeriodSec) 114 << "Failure was at currTimestampNs " << currTimestampNs; 115 } 116 } 117 } 118 119 TEST(AnomalyTrackerTest, TestConsecutiveBuckets) { 120 const int64_t bucketSizeNs = 30 * NS_PER_SEC; 121 const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC; 122 Alert alert; 123 alert.set_num_buckets(3); 124 alert.set_refractory_period_secs(refractoryPeriodSec); 125 alert.set_trigger_if_sum_gt(2); 126 127 AnomalyTracker anomalyTracker(alert, kConfigKey); 128 MetricDimensionKey keyA = getMockMetricDimensionKey(1, "a"); 129 MetricDimensionKey keyB = getMockMetricDimensionKey(1, "b"); 130 MetricDimensionKey keyC = getMockMetricDimensionKey(1, "c"); 131 132 int64_t eventTimestamp0 = 10 * NS_PER_SEC; 133 int64_t eventTimestamp1 = bucketSizeNs + 11 * NS_PER_SEC; 134 int64_t eventTimestamp2 = 2 * bucketSizeNs + 12 * NS_PER_SEC; 135 int64_t eventTimestamp3 = 3 * bucketSizeNs + 13 * NS_PER_SEC; 136 int64_t eventTimestamp4 = 4 * bucketSizeNs + 14 * NS_PER_SEC; 137 int64_t eventTimestamp5 = 5 * bucketSizeNs + 5 * NS_PER_SEC; 138 int64_t eventTimestamp6 = 6 * bucketSizeNs + 16 * NS_PER_SEC; 139 140 std::shared_ptr<DimToValMap> bucket0 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}}); 141 std::shared_ptr<DimToValMap> bucket1 = MockBucket({{keyA, 1}}); 142 std::shared_ptr<DimToValMap> bucket2 = MockBucket({{keyB, 1}}); 143 std::shared_ptr<DimToValMap> bucket3 = MockBucket({{keyA, 2}}); 144 std::shared_ptr<DimToValMap> bucket4 = MockBucket({{keyB, 5}}); 145 std::shared_ptr<DimToValMap> bucket5 = MockBucket({{keyA, 2}}); 146 std::shared_ptr<DimToValMap> bucket6 = MockBucket({{keyA, 2}}); 147 148 // Start time with no events. 149 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u); 150 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL); 151 152 // Event from bucket #0 occurs. 153 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 0, bucket0, {}, {keyA, keyB, keyC})); 154 detectAndDeclareAnomalies(anomalyTracker, 0, bucket0, eventTimestamp1); 155 checkRefractoryTimes(anomalyTracker, eventTimestamp0, refractoryPeriodSec, 156 {{keyA, -1}, {keyB, -1}, {keyC, -1}}); 157 158 // Adds past bucket #0 159 anomalyTracker.addPastBucket(bucket0, 0); 160 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u); 161 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL); 162 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL); 163 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 164 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL); 165 166 // Event from bucket #1 occurs. 167 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC})); 168 detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1); 169 checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec, 170 {{keyA, -1}, {keyB, -1}, {keyC, -1}}); 171 172 // Adds past bucket #0 again. The sum does not change. 173 anomalyTracker.addPastBucket(bucket0, 0); 174 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u); 175 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL); 176 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL); 177 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 178 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL); 179 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC})); 180 detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1 + 1); 181 checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec, 182 {{keyA, -1}, {keyB, -1}, {keyC, -1}}); 183 184 // Adds past bucket #1. 185 anomalyTracker.addPastBucket(bucket1, 1); 186 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L); 187 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL); 188 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL); 189 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL); 190 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 191 192 // Event from bucket #2 occurs. New anomaly on keyB. 193 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC})); 194 detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2); 195 checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec, 196 {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}}); 197 198 // Adds past bucket #1 again. Nothing changes. 199 anomalyTracker.addPastBucket(bucket1, 1); 200 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L); 201 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL); 202 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL); 203 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL); 204 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 205 // Event from bucket #2 occurs (again). 206 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC})); 207 detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2 + 1); 208 checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec, 209 {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}}); 210 211 // Adds past bucket #2. 212 anomalyTracker.addPastBucket(bucket2, 2); 213 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 2L); 214 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 215 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL); 216 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL); 217 218 // Event from bucket #3 occurs. New anomaly on keyA. 219 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 3, bucket3, {keyA}, {keyB, keyC})); 220 detectAndDeclareAnomalies(anomalyTracker, 3, bucket3, eventTimestamp3); 221 checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec, 222 {{keyA, eventTimestamp3}, {keyB, eventTimestamp2}, {keyC, -1}}); 223 224 // Adds bucket #3. 225 anomalyTracker.addPastBucket(bucket3, 3L); 226 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 3L); 227 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 228 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL); 229 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL); 230 231 // Event from bucket #4 occurs. New anomaly on keyB. 232 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 4, bucket4, {keyB}, {keyA, keyC})); 233 detectAndDeclareAnomalies(anomalyTracker, 4, bucket4, eventTimestamp4); 234 checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec, 235 {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}}); 236 237 // Adds bucket #4. 238 anomalyTracker.addPastBucket(bucket4, 4); 239 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 4L); 240 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 241 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL); 242 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL); 243 244 // Event from bucket #5 occurs. New anomaly on keyA, which is still in refractory. 245 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 5, bucket5, {keyA, keyB}, {keyC})); 246 detectAndDeclareAnomalies(anomalyTracker, 5, bucket5, eventTimestamp5); 247 checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec, 248 {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}}); 249 250 // Adds bucket #5. 251 anomalyTracker.addPastBucket(bucket5, 5); 252 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 5L); 253 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 254 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL); 255 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL); 256 257 // Event from bucket #6 occurs. New anomaly on keyA, which is now out of refractory. 258 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 6, bucket6, {keyA, keyB}, {keyC})); 259 detectAndDeclareAnomalies(anomalyTracker, 6, bucket6, eventTimestamp6); 260 checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec, 261 {{keyA, eventTimestamp6}, {keyB, eventTimestamp4}, {keyC, -1}}); 262 } 263 264 TEST(AnomalyTrackerTest, TestSparseBuckets) { 265 const int64_t bucketSizeNs = 30 * NS_PER_SEC; 266 const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC; 267 Alert alert; 268 alert.set_num_buckets(3); 269 alert.set_refractory_period_secs(refractoryPeriodSec); 270 alert.set_trigger_if_sum_gt(2); 271 272 AnomalyTracker anomalyTracker(alert, kConfigKey); 273 MetricDimensionKey keyA = getMockMetricDimensionKey(1, "a"); 274 MetricDimensionKey keyB = getMockMetricDimensionKey(1, "b"); 275 MetricDimensionKey keyC = getMockMetricDimensionKey(1, "c"); 276 MetricDimensionKey keyD = getMockMetricDimensionKey(1, "d"); 277 MetricDimensionKey keyE = getMockMetricDimensionKey(1, "e"); 278 279 std::shared_ptr<DimToValMap> bucket9 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}}); 280 std::shared_ptr<DimToValMap> bucket16 = MockBucket({{keyB, 4}}); 281 std::shared_ptr<DimToValMap> bucket18 = MockBucket({{keyB, 1}, {keyC, 1}}); 282 std::shared_ptr<DimToValMap> bucket20 = MockBucket({{keyB, 3}, {keyC, 1}}); 283 std::shared_ptr<DimToValMap> bucket25 = MockBucket({{keyD, 1}}); 284 std::shared_ptr<DimToValMap> bucket28 = MockBucket({{keyE, 2}}); 285 286 int64_t eventTimestamp1 = bucketSizeNs * 8 + 1; 287 int64_t eventTimestamp2 = bucketSizeNs * 15 + 11; 288 int64_t eventTimestamp3 = bucketSizeNs * 17 + 1; 289 int64_t eventTimestamp4 = bucketSizeNs * 19 + 2; 290 int64_t eventTimestamp5 = bucketSizeNs * 24 + 3; 291 int64_t eventTimestamp6 = bucketSizeNs * 27 + 3; 292 293 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL); 294 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL); 295 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 9, bucket9, {}, {keyA, keyB, keyC, keyD})); 296 detectAndDeclareAnomalies(anomalyTracker, 9, bucket9, eventTimestamp1); 297 checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec, 298 {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}}); 299 300 // Add past bucket #9 301 anomalyTracker.addPastBucket(bucket9, 9); 302 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 9L); 303 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL); 304 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL); 305 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL); 306 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 307 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 16, bucket16, {keyB}, {keyA, keyC, keyD})); 308 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL); 309 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L); 310 detectAndDeclareAnomalies(anomalyTracker, 16, bucket16, eventTimestamp2); 311 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL); 312 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L); 313 checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec, 314 {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}}); 315 316 // Add past bucket #16 317 anomalyTracker.addPastBucket(bucket16, 16); 318 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 16L); 319 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL); 320 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL); 321 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 18, bucket18, {keyB}, {keyA, keyC, keyD})); 322 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL); 323 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL); 324 // Within refractory period. 325 detectAndDeclareAnomalies(anomalyTracker, 18, bucket18, eventTimestamp3); 326 checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec, 327 {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}}); 328 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL); 329 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL); 330 331 // Add past bucket #18 332 anomalyTracker.addPastBucket(bucket18, 18); 333 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 18L); 334 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 335 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL); 336 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 337 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD})); 338 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L); 339 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 340 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL); 341 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 342 detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4); 343 checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec, 344 {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}}); 345 346 // Add bucket #18 again. Nothing changes. 347 anomalyTracker.addPastBucket(bucket18, 18); 348 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L); 349 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 350 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL); 351 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 352 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD})); 353 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 354 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL); 355 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 356 detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4 + 1); 357 // Within refractory period. 358 checkRefractoryTimes(anomalyTracker, eventTimestamp4 + 1, refractoryPeriodSec, 359 {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}}); 360 361 // Add past bucket #20 362 anomalyTracker.addPastBucket(bucket20, 20); 363 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 20L); 364 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL); 365 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 3LL); 366 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL); 367 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 25, bucket25, {}, {keyA, keyB, keyC, keyD})); 368 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L); 369 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL); 370 detectAndDeclareAnomalies(anomalyTracker, 25, bucket25, eventTimestamp5); 371 checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec, 372 {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}}); 373 374 // Add past bucket #25 375 anomalyTracker.addPastBucket(bucket25, 25); 376 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L); 377 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL); 378 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyD), 1LL); 379 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {}, 380 {keyA, keyB, keyC, keyD, keyE})); 381 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L); 382 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL); 383 detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6); 384 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL); 385 checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec, 386 {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}}); 387 388 // Updates current bucket #28. 389 (*bucket28)[keyE] = 5; 390 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {keyE}, 391 {keyA, keyB, keyC, keyD})); 392 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L); 393 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL); 394 detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6 + 7); 395 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL); 396 checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec, 397 {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, eventTimestamp6 + 7}}); 398 } 399 400 } // namespace statsd 401 } // namespace os 402 } // namespace android 403 #else 404 GTEST_LOG_(INFO) << "This test does nothing.\n"; 405 #endif 406