blob: b4a7bb706029437688cecd789bd1b5d40ee72783 [file] [log] [blame]
Yang Lu3eba6212017-10-25 19:54:45 -07001// 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
Yangster-mace2cd6d52017-11-09 20:38:30 -080015#include "src/anomaly/AnomalyTracker.h"
Yao Chend5aa01b32017-12-19 16:46:36 -080016#include "../metrics/metrics_test_helper.h"
Yang Lu3eba6212017-10-25 19:54:45 -070017
18#include <gtest/gtest.h>
19#include <stdio.h>
20#include <vector>
21
22using namespace testing;
23using android::sp;
24using std::set;
25using std::unordered_map;
26using std::vector;
27
28#ifdef __ANDROID__
29
30namespace android {
31namespace os {
32namespace statsd {
33
Yangster-mac94e197c2018-01-02 16:03:03 -080034const ConfigKey kConfigKey(0, 12345);
Bookatz8f2f3d82017-12-07 13:53:21 -080035
Yangster-mac93694462018-01-22 20:49:31 -080036MetricDimensionKey getMockMetricDimensionKey(int key, string value) {
Yao Chen8a8d16c2018-02-08 14:50:40 -080037 int pos[] = {key, 0, 0};
38 HashableDimensionKey dim;
39 dim.addValue(FieldValue(Field(1, pos, 0), Value(value)));
40 return MetricDimensionKey(dim, DEFAULT_DIMENSION_KEY);
Yao Chend5aa01b32017-12-19 16:46:36 -080041}
42
Yangster-mac93694462018-01-22 20:49:31 -080043void AddValueToBucket(const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list,
Yang Lu3eba6212017-10-25 19:54:45 -070044 std::shared_ptr<DimToValMap> bucket) {
45 for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
46 (*bucket)[itr->first] += itr->second;
47 }
48}
49
Yangster-mace2cd6d52017-11-09 20:38:30 -080050std::shared_ptr<DimToValMap> MockBucket(
Yangster-mac93694462018-01-22 20:49:31 -080051 const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list) {
Yang Lu3eba6212017-10-25 19:54:45 -070052 std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
53 AddValueToBucket(key_value_pair_list, bucket);
54 return bucket;
55}
56
Bookatz1bf94382018-01-04 11:43:20 -080057// Returns the value, for the given key, in that bucket, or 0 if not present.
58int64_t getBucketValue(const std::shared_ptr<DimToValMap>& bucket,
Yangster-mac93694462018-01-22 20:49:31 -080059 const MetricDimensionKey& key) {
Bookatz1bf94382018-01-04 11:43:20 -080060 const auto& itr = bucket->find(key);
61 if (itr != bucket->end()) {
62 return itr->second;
63 }
64 return 0;
65}
66
67// Returns true if keys in trueList are detected as anomalies and keys in falseList are not.
68bool detectAnomaliesPass(AnomalyTracker& tracker,
69 const int64_t& bucketNum,
70 const std::shared_ptr<DimToValMap>& currentBucket,
Yangster-mac93694462018-01-22 20:49:31 -080071 const std::set<const MetricDimensionKey>& trueList,
72 const std::set<const MetricDimensionKey>& falseList) {
73 for (MetricDimensionKey key : trueList) {
Bookatz1bf94382018-01-04 11:43:20 -080074 if (!tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
75 return false;
76 }
77 }
Yangster-mac93694462018-01-22 20:49:31 -080078 for (MetricDimensionKey key : falseList) {
Bookatz1bf94382018-01-04 11:43:20 -080079 if (tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
80 return false;
81 }
82 }
83 return true;
84}
85
86// Calls tracker.detectAndDeclareAnomaly on each key in the bucket.
87void detectAndDeclareAnomalies(AnomalyTracker& tracker,
88 const int64_t& bucketNum,
89 const std::shared_ptr<DimToValMap>& bucket,
90 const int64_t& eventTimestamp) {
91 for (const auto& kv : *bucket) {
92 tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, kv.first, kv.second);
93 }
94}
95
96// Asserts that the refractory time for each key in timestamps is the corresponding
97// timestamp (in ns) + refractoryPeriodSec.
98// If a timestamp value is negative, instead asserts that the refractory period is inapplicable
99// (either non-existant or already past).
100void checkRefractoryTimes(AnomalyTracker& tracker,
101 const int64_t& currTimestampNs,
102 const int32_t& refractoryPeriodSec,
Yangster-mac93694462018-01-22 20:49:31 -0800103 const std::unordered_map<MetricDimensionKey, int64_t>& timestamps) {
Bookatz1bf94382018-01-04 11:43:20 -0800104 for (const auto& kv : timestamps) {
105 if (kv.second < 0) {
106 // Make sure that, if there is a refractory period, it is already past.
107 EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first),
108 currTimestampNs / NS_PER_SEC + 1)
109 << "Failure was at currTimestampNs " << currTimestampNs;
110 } else {
111 EXPECT_EQ(tracker.getRefractoryPeriodEndsSec(kv.first),
112 kv.second / NS_PER_SEC + refractoryPeriodSec)
113 << "Failure was at currTimestampNs " << currTimestampNs;
114 }
115 }
116}
117
Yang Lu3eba6212017-10-25 19:54:45 -0700118TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800119 const int64_t bucketSizeNs = 30 * NS_PER_SEC;
Bookatz1bf94382018-01-04 11:43:20 -0800120 const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC;
Yang Lu3eba6212017-10-25 19:54:45 -0700121 Alert alert;
Yangster-maca7fb12d2018-01-03 17:17:20 -0800122 alert.set_num_buckets(3);
Bookatz1bf94382018-01-04 11:43:20 -0800123 alert.set_refractory_period_secs(refractoryPeriodSec);
Yang Lu3eba6212017-10-25 19:54:45 -0700124 alert.set_trigger_if_sum_gt(2);
125
Bookatz8f2f3d82017-12-07 13:53:21 -0800126 AnomalyTracker anomalyTracker(alert, kConfigKey);
Yangster-mac93694462018-01-22 20:49:31 -0800127 MetricDimensionKey keyA = getMockMetricDimensionKey(1, "a");
128 MetricDimensionKey keyB = getMockMetricDimensionKey(1, "b");
129 MetricDimensionKey keyC = getMockMetricDimensionKey(1, "c");
Yang Lu3eba6212017-10-25 19:54:45 -0700130
Bookatz1bf94382018-01-04 11:43:20 -0800131 int64_t eventTimestamp0 = 10 * NS_PER_SEC;
132 int64_t eventTimestamp1 = bucketSizeNs + 11 * NS_PER_SEC;
133 int64_t eventTimestamp2 = 2 * bucketSizeNs + 12 * NS_PER_SEC;
134 int64_t eventTimestamp3 = 3 * bucketSizeNs + 13 * NS_PER_SEC;
135 int64_t eventTimestamp4 = 4 * bucketSizeNs + 14 * NS_PER_SEC;
136 int64_t eventTimestamp5 = 5 * bucketSizeNs + 5 * NS_PER_SEC;
137 int64_t eventTimestamp6 = 6 * bucketSizeNs + 16 * NS_PER_SEC;
Yang Lu3eba6212017-10-25 19:54:45 -0700138
Bookatz1bf94382018-01-04 11:43:20 -0800139 std::shared_ptr<DimToValMap> bucket0 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
140 std::shared_ptr<DimToValMap> bucket1 = MockBucket({{keyA, 1}});
141 std::shared_ptr<DimToValMap> bucket2 = MockBucket({{keyB, 1}});
142 std::shared_ptr<DimToValMap> bucket3 = MockBucket({{keyA, 2}});
143 std::shared_ptr<DimToValMap> bucket4 = MockBucket({{keyB, 5}});
144 std::shared_ptr<DimToValMap> bucket5 = MockBucket({{keyA, 2}});
145 std::shared_ptr<DimToValMap> bucket6 = MockBucket({{keyA, 2}});
146
147 // Start time with no events.
Yangster-mace2cd6d52017-11-09 20:38:30 -0800148 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u);
149 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800150
151 // Event from bucket #0 occurs.
152 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 0, bucket0, {}, {keyA, keyB, keyC}));
153 detectAndDeclareAnomalies(anomalyTracker, 0, bucket0, eventTimestamp1);
154 checkRefractoryTimes(anomalyTracker, eventTimestamp0, refractoryPeriodSec,
155 {{keyA, -1}, {keyB, -1}, {keyC, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700156
Yangster-mace2cd6d52017-11-09 20:38:30 -0800157 // Adds past bucket #0
158 anomalyTracker.addPastBucket(bucket0, 0);
159 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
Yao Chend5aa01b32017-12-19 16:46:36 -0800160 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
161 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
162 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800163 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
Bookatz1bf94382018-01-04 11:43:20 -0800164
165 // Event from bucket #1 occurs.
166 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC}));
167 detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1);
168 checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
169 {{keyA, -1}, {keyB, -1}, {keyC, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700170
Yangster-mace2cd6d52017-11-09 20:38:30 -0800171 // Adds past bucket #0 again. The sum does not change.
172 anomalyTracker.addPastBucket(bucket0, 0);
173 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
Yao Chend5aa01b32017-12-19 16:46:36 -0800174 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
175 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
176 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800177 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
Bookatz1bf94382018-01-04 11:43:20 -0800178 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC}));
179 detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1 + 1);
180 checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
181 {{keyA, -1}, {keyB, -1}, {keyC, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700182
Yangster-mace2cd6d52017-11-09 20:38:30 -0800183 // Adds past bucket #1.
184 anomalyTracker.addPastBucket(bucket1, 1);
185 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
186 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800187 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
188 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
189 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800190
191 // Event from bucket #2 occurs. New anomaly on keyB.
192 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC}));
193 detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2);
194 checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
195 {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800196
197 // Adds past bucket #1 again. Nothing changes.
198 anomalyTracker.addPastBucket(bucket1, 1);
199 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
200 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800201 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
202 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
203 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800204 // Event from bucket #2 occurs (again).
205 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC}));
206 detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2 + 1);
207 checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
208 {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800209
210 // Adds past bucket #2.
211 anomalyTracker.addPastBucket(bucket2, 2);
212 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 2L);
213 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800214 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
215 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800216
217 // Event from bucket #3 occurs. New anomaly on keyA.
218 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 3, bucket3, {keyA}, {keyB, keyC}));
219 detectAndDeclareAnomalies(anomalyTracker, 3, bucket3, eventTimestamp3);
220 checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
221 {{keyA, eventTimestamp3}, {keyB, eventTimestamp2}, {keyC, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700222
223 // Adds bucket #3.
Yangster-mace2cd6d52017-11-09 20:38:30 -0800224 anomalyTracker.addPastBucket(bucket3, 3L);
225 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 3L);
226 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800227 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
228 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800229
230 // Event from bucket #4 occurs. New anomaly on keyB.
231 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 4, bucket4, {keyB}, {keyA, keyC}));
232 detectAndDeclareAnomalies(anomalyTracker, 4, bucket4, eventTimestamp4);
233 checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec,
234 {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700235
Yangster-mace2cd6d52017-11-09 20:38:30 -0800236 // Adds bucket #4.
237 anomalyTracker.addPastBucket(bucket4, 4);
238 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 4L);
239 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800240 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
Bookatz1bf94382018-01-04 11:43:20 -0800241 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
242
243 // Event from bucket #5 occurs. New anomaly on keyA, which is still in refractory.
244 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 5, bucket5, {keyA, keyB}, {keyC}));
245 detectAndDeclareAnomalies(anomalyTracker, 5, bucket5, eventTimestamp5);
246 checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
247 {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700248
Yangster-mace2cd6d52017-11-09 20:38:30 -0800249 // Adds bucket #5.
250 anomalyTracker.addPastBucket(bucket5, 5);
251 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 5L);
252 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800253 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
Bookatz1bf94382018-01-04 11:43:20 -0800254 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
255
256 // Event from bucket #6 occurs. New anomaly on keyA, which is now out of refractory.
257 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 6, bucket6, {keyA, keyB}, {keyC}));
258 detectAndDeclareAnomalies(anomalyTracker, 6, bucket6, eventTimestamp6);
259 checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
260 {{keyA, eventTimestamp6}, {keyB, eventTimestamp4}, {keyC, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700261}
262
263TEST(AnomalyTrackerTest, TestSparseBuckets) {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800264 const int64_t bucketSizeNs = 30 * NS_PER_SEC;
Bookatz1bf94382018-01-04 11:43:20 -0800265 const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC;
Yang Lu3eba6212017-10-25 19:54:45 -0700266 Alert alert;
Yangster-maca7fb12d2018-01-03 17:17:20 -0800267 alert.set_num_buckets(3);
Bookatz1bf94382018-01-04 11:43:20 -0800268 alert.set_refractory_period_secs(refractoryPeriodSec);
Yang Lu3eba6212017-10-25 19:54:45 -0700269 alert.set_trigger_if_sum_gt(2);
270
Bookatz8f2f3d82017-12-07 13:53:21 -0800271 AnomalyTracker anomalyTracker(alert, kConfigKey);
Yangster-mac93694462018-01-22 20:49:31 -0800272 MetricDimensionKey keyA = getMockMetricDimensionKey(1, "a");
273 MetricDimensionKey keyB = getMockMetricDimensionKey(1, "b");
274 MetricDimensionKey keyC = getMockMetricDimensionKey(1, "c");
275 MetricDimensionKey keyD = getMockMetricDimensionKey(1, "d");
276 MetricDimensionKey keyE = getMockMetricDimensionKey(1, "e");
Yang Lu3eba6212017-10-25 19:54:45 -0700277
Yao Chend5aa01b32017-12-19 16:46:36 -0800278 std::shared_ptr<DimToValMap> bucket9 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
279 std::shared_ptr<DimToValMap> bucket16 = MockBucket({{keyB, 4}});
280 std::shared_ptr<DimToValMap> bucket18 = MockBucket({{keyB, 1}, {keyC, 1}});
281 std::shared_ptr<DimToValMap> bucket20 = MockBucket({{keyB, 3}, {keyC, 1}});
282 std::shared_ptr<DimToValMap> bucket25 = MockBucket({{keyD, 1}});
283 std::shared_ptr<DimToValMap> bucket28 = MockBucket({{keyE, 2}});
Yang Lu3eba6212017-10-25 19:54:45 -0700284
Yangster-mace2cd6d52017-11-09 20:38:30 -0800285 int64_t eventTimestamp1 = bucketSizeNs * 8 + 1;
286 int64_t eventTimestamp2 = bucketSizeNs * 15 + 11;
287 int64_t eventTimestamp3 = bucketSizeNs * 17 + 1;
288 int64_t eventTimestamp4 = bucketSizeNs * 19 + 2;
289 int64_t eventTimestamp5 = bucketSizeNs * 24 + 3;
290 int64_t eventTimestamp6 = bucketSizeNs * 27 + 3;
Yang Lu3eba6212017-10-25 19:54:45 -0700291
Yangster-mace2cd6d52017-11-09 20:38:30 -0800292 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
293 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
Bookatz1bf94382018-01-04 11:43:20 -0800294 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 9, bucket9, {}, {keyA, keyB, keyC, keyD}));
295 detectAndDeclareAnomalies(anomalyTracker, 9, bucket9, eventTimestamp1);
296 checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
297 {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800298
299 // Add past bucket #9
300 anomalyTracker.addPastBucket(bucket9, 9);
301 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 9L);
302 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800303 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
304 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
305 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800306 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 16, bucket16, {keyB}, {keyA, keyC, keyD}));
307 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800308 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
Bookatz1bf94382018-01-04 11:43:20 -0800309 detectAndDeclareAnomalies(anomalyTracker, 16, bucket16, eventTimestamp2);
310 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800311 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
Bookatz1bf94382018-01-04 11:43:20 -0800312 checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
313 {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800314
315 // Add past bucket #16
316 anomalyTracker.addPastBucket(bucket16, 16);
317 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 16L);
318 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800319 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
Bookatz1bf94382018-01-04 11:43:20 -0800320 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 18, bucket18, {keyB}, {keyA, keyC, keyD}));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800321 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800322 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
Yang Lu3eba6212017-10-25 19:54:45 -0700323 // Within refractory period.
Bookatz1bf94382018-01-04 11:43:20 -0800324 detectAndDeclareAnomalies(anomalyTracker, 18, bucket18, eventTimestamp3);
325 checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
326 {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800327 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800328 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
Yang Lu3eba6212017-10-25 19:54:45 -0700329
Yangster-mace2cd6d52017-11-09 20:38:30 -0800330 // Add past bucket #18
331 anomalyTracker.addPastBucket(bucket18, 18);
332 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 18L);
333 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800334 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
335 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800336 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800337 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
338 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800339 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
340 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800341 detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4);
342 checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec,
343 {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700344
Yangster-mace2cd6d52017-11-09 20:38:30 -0800345 // Add bucket #18 again. Nothing changes.
346 anomalyTracker.addPastBucket(bucket18, 18);
347 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
348 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800349 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
350 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800351 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800352 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800353 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
354 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800355 detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4 + 1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800356 // Within refractory period.
Bookatz1bf94382018-01-04 11:43:20 -0800357 checkRefractoryTimes(anomalyTracker, eventTimestamp4 + 1, refractoryPeriodSec,
358 {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700359
Yangster-mace2cd6d52017-11-09 20:38:30 -0800360 // Add past bucket #20
361 anomalyTracker.addPastBucket(bucket20, 20);
362 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 20L);
363 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800364 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 3LL);
365 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800366 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 25, bucket25, {}, {keyA, keyB, keyC, keyD}));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800367 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
Bookatz1bf94382018-01-04 11:43:20 -0800368 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
369 detectAndDeclareAnomalies(anomalyTracker, 25, bucket25, eventTimestamp5);
370 checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
371 {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
Yang Lu3eba6212017-10-25 19:54:45 -0700372
Yangster-mace2cd6d52017-11-09 20:38:30 -0800373 // Add past bucket #25
374 anomalyTracker.addPastBucket(bucket25, 25);
375 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L);
Bookatz1bf94382018-01-04 11:43:20 -0800376 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
Yao Chend5aa01b32017-12-19 16:46:36 -0800377 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyD), 1LL);
Bookatz1bf94382018-01-04 11:43:20 -0800378 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {},
379 {keyA, keyB, keyC, keyD, keyE}));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800380 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
Bookatz1bf94382018-01-04 11:43:20 -0800381 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
382 detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6);
383 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
384 checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
385 {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800386
387 // Updates current bucket #28.
Yao Chend5aa01b32017-12-19 16:46:36 -0800388 (*bucket28)[keyE] = 5;
Bookatz1bf94382018-01-04 11:43:20 -0800389 EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {keyE},
390 {keyA, keyB, keyC, keyD}));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800391 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
Bookatz1bf94382018-01-04 11:43:20 -0800392 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
393 detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6 + 7);
394 // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
395 checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
396 {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, eventTimestamp6 + 7}});
Yang Lu3eba6212017-10-25 19:54:45 -0700397}
398
399} // namespace statsd
400} // namespace os
401} // namespace android
402#else
403GTEST_LOG_(INFO) << "This test does nothing.\n";
404#endif