blob: f38576398f11638919dd4ca10ae4b5ecf3e22316 [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"
Yang Lu3eba6212017-10-25 19:54:45 -070016
17#include <gtest/gtest.h>
18#include <stdio.h>
19#include <vector>
20
21using namespace testing;
22using android::sp;
23using std::set;
24using std::unordered_map;
25using std::vector;
26
27#ifdef __ANDROID__
28
29namespace android {
30namespace os {
31namespace statsd {
32
Bookatz8f2f3d82017-12-07 13:53:21 -080033const ConfigKey kConfigKey(0, "test");
34
Yang Lu3eba6212017-10-25 19:54:45 -070035void AddValueToBucket(const std::vector<std::pair<string, long>>& key_value_pair_list,
36 std::shared_ptr<DimToValMap> bucket) {
37 for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
38 (*bucket)[itr->first] += itr->second;
39 }
40}
41
Yangster-mace2cd6d52017-11-09 20:38:30 -080042std::shared_ptr<DimToValMap> MockBucket(
Yang Lu3eba6212017-10-25 19:54:45 -070043 const std::vector<std::pair<string, long>>& key_value_pair_list) {
44 std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
45 AddValueToBucket(key_value_pair_list, bucket);
46 return bucket;
47}
48
49TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
Yangster-mace2cd6d52017-11-09 20:38:30 -080050 const int64_t bucketSizeNs = 30 * NS_PER_SEC;
Yang Lu3eba6212017-10-25 19:54:45 -070051 Alert alert;
52 alert.set_number_of_buckets(3);
Yangster-mace2cd6d52017-11-09 20:38:30 -080053 alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
Yang Lu3eba6212017-10-25 19:54:45 -070054 alert.set_trigger_if_sum_gt(2);
55
Bookatz8f2f3d82017-12-07 13:53:21 -080056 AnomalyTracker anomalyTracker(alert, kConfigKey);
Yang Lu3eba6212017-10-25 19:54:45 -070057
Yangster-mace2cd6d52017-11-09 20:38:30 -080058 std::shared_ptr<DimToValMap> bucket0 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
59 int64_t eventTimestamp0 = 10;
60 std::shared_ptr<DimToValMap> bucket1 = MockBucket({{"a", 1}});
61 int64_t eventTimestamp1 = bucketSizeNs + 11;
62 std::shared_ptr<DimToValMap> bucket2 = MockBucket({{"b", 1}});
63 int64_t eventTimestamp2 = 2 * bucketSizeNs + 12;
64 std::shared_ptr<DimToValMap> bucket3 = MockBucket({{"a", 2}});
65 int64_t eventTimestamp3 = 3 * bucketSizeNs + 13;
66 std::shared_ptr<DimToValMap> bucket4 = MockBucket({{"b", 1}});
67 int64_t eventTimestamp4 = 4 * bucketSizeNs + 14;
68 std::shared_ptr<DimToValMap> bucket5 = MockBucket({{"a", 2}});
69 int64_t eventTimestamp5 = 5 * bucketSizeNs + 15;
70 std::shared_ptr<DimToValMap> bucket6 = MockBucket({{"a", 2}});
71 int64_t eventTimestamp6 = 6 * bucketSizeNs + 16;
Yang Lu3eba6212017-10-25 19:54:45 -070072
Yangster-mace2cd6d52017-11-09 20:38:30 -080073 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u);
74 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
75 EXPECT_FALSE(anomalyTracker.detectAnomaly(0, *bucket0));
76 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp0, 0, *bucket0);
77 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, -1L);
Yang Lu3eba6212017-10-25 19:54:45 -070078
Yangster-mace2cd6d52017-11-09 20:38:30 -080079 // Adds past bucket #0
80 anomalyTracker.addPastBucket(bucket0, 0);
81 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
82 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 1LL);
83 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
84 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
85 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
86 EXPECT_FALSE(anomalyTracker.detectAnomaly(1, *bucket1));
87 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1, 1, *bucket1);
88 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, -1L);
Yang Lu3eba6212017-10-25 19:54:45 -070089
Yangster-mace2cd6d52017-11-09 20:38:30 -080090 // Adds past bucket #0 again. The sum does not change.
91 anomalyTracker.addPastBucket(bucket0, 0);
92 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
93 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 1LL);
94 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
95 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
96 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
97 EXPECT_FALSE(anomalyTracker.detectAnomaly(1, *bucket1));
98 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1 + 1, 1, *bucket1);
99 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, -1L);
Yang Lu3eba6212017-10-25 19:54:45 -0700100
Yangster-mace2cd6d52017-11-09 20:38:30 -0800101 // Adds past bucket #1.
102 anomalyTracker.addPastBucket(bucket1, 1);
103 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
104 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
105 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
106 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
107 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
108 EXPECT_TRUE(anomalyTracker.detectAnomaly(2, *bucket2));
109 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2, 2, *bucket2);
110 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
111
112 // Adds past bucket #1 again. Nothing changes.
113 anomalyTracker.addPastBucket(bucket1, 1);
114 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
115 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
116 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
117 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
118 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
119 EXPECT_TRUE(anomalyTracker.detectAnomaly(2, *bucket2));
120 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2 + 1, 2, *bucket2);
121 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
122
123 // Adds past bucket #2.
124 anomalyTracker.addPastBucket(bucket2, 2);
125 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 2L);
126 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
127 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 1LL);
128 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
129 EXPECT_TRUE(anomalyTracker.detectAnomaly(3, *bucket3));
130 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp3, 3, *bucket3);
Yang Lu3eba6212017-10-25 19:54:45 -0700131 // Within refractory period.
Yangster-mace2cd6d52017-11-09 20:38:30 -0800132 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
Yang Lu3eba6212017-10-25 19:54:45 -0700133
134 // Adds bucket #3.
Yangster-mace2cd6d52017-11-09 20:38:30 -0800135 anomalyTracker.addPastBucket(bucket3, 3L);
136 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 3L);
137 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
138 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
139 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
140 EXPECT_FALSE(anomalyTracker.detectAnomaly(4, *bucket4));
141 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4, 4, *bucket4);
142 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
Yang Lu3eba6212017-10-25 19:54:45 -0700143
Yangster-mace2cd6d52017-11-09 20:38:30 -0800144 // Adds bucket #4.
145 anomalyTracker.addPastBucket(bucket4, 4);
146 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 4L);
147 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
148 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
149 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
150 EXPECT_TRUE(anomalyTracker.detectAnomaly(5, *bucket5));
151 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp5, 5, *bucket5);
152 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp5);
Yang Lu3eba6212017-10-25 19:54:45 -0700153
Yangster-mace2cd6d52017-11-09 20:38:30 -0800154 // Adds bucket #5.
155 anomalyTracker.addPastBucket(bucket5, 5);
156 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 5L);
157 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
158 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 2LL);
159 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
160 EXPECT_TRUE(anomalyTracker.detectAnomaly(6, *bucket6));
Yang Lu3eba6212017-10-25 19:54:45 -0700161 // Within refractory period.
Yangster-mace2cd6d52017-11-09 20:38:30 -0800162 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6, 6, *bucket6);
163 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp5);
Yang Lu3eba6212017-10-25 19:54:45 -0700164}
165
166TEST(AnomalyTrackerTest, TestSparseBuckets) {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800167 const int64_t bucketSizeNs = 30 * NS_PER_SEC;
Yang Lu3eba6212017-10-25 19:54:45 -0700168 Alert alert;
169 alert.set_number_of_buckets(3);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800170 alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
Yang Lu3eba6212017-10-25 19:54:45 -0700171 alert.set_trigger_if_sum_gt(2);
172
Bookatz8f2f3d82017-12-07 13:53:21 -0800173 AnomalyTracker anomalyTracker(alert, kConfigKey);
Yang Lu3eba6212017-10-25 19:54:45 -0700174
Yangster-mace2cd6d52017-11-09 20:38:30 -0800175 std::shared_ptr<DimToValMap> bucket9 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
176 std::shared_ptr<DimToValMap> bucket16 = MockBucket({{"b", 4}});
177 std::shared_ptr<DimToValMap> bucket18 = MockBucket({{"b", 1}, {"c", 1}});
178 std::shared_ptr<DimToValMap> bucket20 = MockBucket({{"b", 3}, {"c", 1}});
179 std::shared_ptr<DimToValMap> bucket25 = MockBucket({{"d", 1}});
180 std::shared_ptr<DimToValMap> bucket28 = MockBucket({{"e", 2}});
Yang Lu3eba6212017-10-25 19:54:45 -0700181
Yangster-mace2cd6d52017-11-09 20:38:30 -0800182 int64_t eventTimestamp1 = bucketSizeNs * 8 + 1;
183 int64_t eventTimestamp2 = bucketSizeNs * 15 + 11;
184 int64_t eventTimestamp3 = bucketSizeNs * 17 + 1;
185 int64_t eventTimestamp4 = bucketSizeNs * 19 + 2;
186 int64_t eventTimestamp5 = bucketSizeNs * 24 + 3;
187 int64_t eventTimestamp6 = bucketSizeNs * 27 + 3;
Yang Lu3eba6212017-10-25 19:54:45 -0700188
Yangster-mace2cd6d52017-11-09 20:38:30 -0800189 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
190 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
191 EXPECT_FALSE(anomalyTracker.detectAnomaly(9, *bucket9));
192 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp1, 9, *bucket9);
193 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, -1);
194
195 // Add past bucket #9
196 anomalyTracker.addPastBucket(bucket9, 9);
197 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 9L);
198 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
199 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("a"), 1LL);
200 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 2LL);
201 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
202 EXPECT_TRUE(anomalyTracker.detectAnomaly(16, *bucket16));
203 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
204 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
205 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp2, 16, *bucket16);
206 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
207 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
208 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
209
210 // Add past bucket #16
211 anomalyTracker.addPastBucket(bucket16, 16);
212 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 16L);
213 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
214 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 4LL);
215 EXPECT_TRUE(anomalyTracker.detectAnomaly(18, *bucket18));
216 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
217 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 4LL);
Yang Lu3eba6212017-10-25 19:54:45 -0700218 // Within refractory period.
Yangster-mace2cd6d52017-11-09 20:38:30 -0800219 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp3, 18, *bucket18);
220 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp2);
221 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
222 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 4LL);
Yang Lu3eba6212017-10-25 19:54:45 -0700223
Yangster-mace2cd6d52017-11-09 20:38:30 -0800224 // Add past bucket #18
225 anomalyTracker.addPastBucket(bucket18, 18);
226 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 18L);
227 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
228 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
229 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
230 EXPECT_TRUE(anomalyTracker.detectAnomaly(20, *bucket20));
231 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
232 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
233 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
234 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
235 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4, 20, *bucket20);
236 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
Yang Lu3eba6212017-10-25 19:54:45 -0700237
Yangster-mace2cd6d52017-11-09 20:38:30 -0800238 // Add bucket #18 again. Nothing changes.
239 anomalyTracker.addPastBucket(bucket18, 18);
240 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
241 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
242 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
243 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
244 EXPECT_TRUE(anomalyTracker.detectAnomaly(20, *bucket20));
245 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
246 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 1LL);
247 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
248 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp4 + 1, 20, *bucket20);
249 // Within refractory period.
250 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
Yang Lu3eba6212017-10-25 19:54:45 -0700251
Yangster-mace2cd6d52017-11-09 20:38:30 -0800252 // Add past bucket #20
253 anomalyTracker.addPastBucket(bucket20, 20);
254 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 20L);
255 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
256 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("b"), 3LL);
257 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("c"), 1LL);
258 EXPECT_FALSE(anomalyTracker.detectAnomaly(25, *bucket25));
259 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
260 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
261 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp5, 25, *bucket25);
262 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
Yang Lu3eba6212017-10-25 19:54:45 -0700263
Yangster-mace2cd6d52017-11-09 20:38:30 -0800264 // Add past bucket #25
265 anomalyTracker.addPastBucket(bucket25, 25);
266 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L);
267 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
268 EXPECT_EQ(anomalyTracker.getSumOverPastBuckets("d"), 1LL);
269 EXPECT_FALSE(anomalyTracker.detectAnomaly(28, *bucket28));
270 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
271 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
272 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6, 28, *bucket28);
273 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
274 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp4);
275
276 // Updates current bucket #28.
277 (*bucket28)["e"] = 5;
278 EXPECT_TRUE(anomalyTracker.detectAnomaly(28, *bucket28));
279 EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
280 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
281 anomalyTracker.detectAndDeclareAnomaly(eventTimestamp6 + 7, 28, *bucket28);
282 EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
283 EXPECT_EQ(anomalyTracker.mLastAlarmTimestampNs, eventTimestamp6 + 7);
Yang Lu3eba6212017-10-25 19:54:45 -0700284}
285
286} // namespace statsd
287} // namespace os
288} // namespace android
289#else
290GTEST_LOG_(INFO) << "This test does nothing.\n";
291#endif