blob: 550b059e4d6988232a1a887c5f66ee621b046a9f [file] [log] [blame]
Yao Chen5154a372017-10-30 22:57:06 -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
Yao Chend5aa01b32017-12-19 16:46:36 -080015#include "src/metrics/duration_helper/OringDurationTracker.h"
Yao Chen93fe3a32017-11-02 13:52:59 -070016#include "metrics_test_helper.h"
Yao Chen5154a372017-10-30 22:57:06 -070017#include "src/condition/ConditionWizard.h"
Yao Chen5154a372017-10-30 22:57:06 -070018
Yao Chen93fe3a32017-11-02 13:52:59 -070019#include <gmock/gmock.h>
20#include <gtest/gtest.h>
Yao Chen5154a372017-10-30 22:57:06 -070021#include <stdio.h>
22#include <set>
23#include <unordered_map>
24#include <vector>
25
Yao Chen5154a372017-10-30 22:57:06 -070026using namespace testing;
27using android::sp;
28using std::set;
29using std::unordered_map;
30using std::vector;
31
32#ifdef __ANDROID__
Yao Chen93fe3a32017-11-02 13:52:59 -070033namespace android {
34namespace os {
35namespace statsd {
Yao Chen5154a372017-10-30 22:57:06 -070036
Yao Chenb3561512017-11-21 18:07:17 -080037const ConfigKey kConfigKey(0, "test");
Yangster-mac20877162017-12-22 17:19:39 -080038const int TagId = 1;
39const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "event");
Yao Chend5aa01b32017-12-19 16:46:36 -080040
Yangster-mac20877162017-12-22 17:19:39 -080041const std::vector<HashableDimensionKey> kConditionKey1 = {getMockedDimensionKey(TagId, 1, "maps")};
42const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
43const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
Yao Chenb3561512017-11-21 18:07:17 -080044
Yao Chen5154a372017-10-30 22:57:06 -070045TEST(OringDurationTrackerTest, TestDurationOverlap) {
46 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
47
48 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -080049 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen5154a372017-10-30 22:57:06 -070050
Yao Chenf60e0ba2017-11-29 15:06:41 -080051 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen5154a372017-10-30 22:57:06 -070052
53 uint64_t bucketStartTimeNs = 10000000000;
54 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
55 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
Yangster-mace2cd6d52017-11-09 20:38:30 -080056 uint64_t durationTimeNs = 2 * 1000;
Yao Chen5154a372017-10-30 22:57:06 -070057
Yao Chenf60e0ba2017-11-29 15:06:41 -080058 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
59 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen5154a372017-10-30 22:57:06 -070060
Yao Chend5aa01b32017-12-19 16:46:36 -080061 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -080062 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chend5aa01b32017-12-19 16:46:36 -080063 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, key1); // overlapping wl
Yangster-mace2cd6d52017-11-09 20:38:30 -080064 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chen5154a372017-10-30 22:57:06 -070065
Yao Chend5aa01b32017-12-19 16:46:36 -080066 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -080067 tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1, &buckets);
68 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
69
70 EXPECT_EQ(1u, buckets[eventKey].size());
71 EXPECT_EQ(durationTimeNs, buckets[eventKey][0].mDuration);
Yao Chen5154a372017-10-30 22:57:06 -070072}
73
Yao Chen0ea19902017-11-15 15:44:45 -080074TEST(OringDurationTrackerTest, TestDurationNested) {
75 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
76
77 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -080078 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen0ea19902017-11-15 15:44:45 -080079
Yao Chenf60e0ba2017-11-29 15:06:41 -080080 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen0ea19902017-11-15 15:44:45 -080081
82 uint64_t bucketStartTimeNs = 10000000000;
83 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
84 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
85
Yao Chenf60e0ba2017-11-29 15:06:41 -080086 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
87 bucketSizeNs, {});
Yao Chen0ea19902017-11-15 15:44:45 -080088
Yao Chend5aa01b32017-12-19 16:46:36 -080089 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
90 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, key1); // overlapping wl
Yao Chen0ea19902017-11-15 15:44:45 -080091
Yao Chend5aa01b32017-12-19 16:46:36 -080092 tracker.noteStop(kEventKey1, eventStartTimeNs + 2000, false);
93 tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
Yao Chen0ea19902017-11-15 15:44:45 -080094
Yao Chenf60e0ba2017-11-29 15:06:41 -080095 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
96 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
97 EXPECT_EQ(1u, buckets[eventKey].size());
98 EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -080099}
100
101TEST(OringDurationTrackerTest, TestStopAll) {
102 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
103
104 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800105 key1["APP_BACKGROUND"] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800106
Yao Chenf60e0ba2017-11-29 15:06:41 -0800107 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800108
109 uint64_t bucketStartTimeNs = 10000000000;
110 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
111 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
112
Yao Chenf60e0ba2017-11-29 15:06:41 -0800113 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
114 bucketSizeNs, {});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800115
Yao Chend5aa01b32017-12-19 16:46:36 -0800116 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
117 tracker.noteStart(kEventKey2, true, eventStartTimeNs + 10, key1); // overlapping wl
Yangster-mace2cd6d52017-11-09 20:38:30 -0800118
119 tracker.noteStopAll(eventStartTimeNs + 2003);
120
Yao Chenf60e0ba2017-11-29 15:06:41 -0800121 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
122 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
123 EXPECT_EQ(1u, buckets[eventKey].size());
124 EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800125}
126
127TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
128 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
129
130 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800131 key1["APP_BACKGROUND"] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800132
Yao Chenf60e0ba2017-11-29 15:06:41 -0800133 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800134
135 uint64_t bucketStartTimeNs = 10000000000;
136 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
137 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
138 uint64_t durationTimeNs = 2 * 1000;
139
Yao Chenf60e0ba2017-11-29 15:06:41 -0800140 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
141 bucketSizeNs, {});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800142
Yao Chend5aa01b32017-12-19 16:46:36 -0800143 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800144 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800145 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800146 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2 * bucketSizeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800147 EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
148
Yao Chenf60e0ba2017-11-29 15:06:41 -0800149 EXPECT_EQ(2u, buckets[eventKey].size());
150 EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
151 EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800152
Yao Chend5aa01b32017-12-19 16:46:36 -0800153 tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 10, false);
154 tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 12, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800155 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12, &buckets);
156 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
157 EXPECT_EQ(2u, buckets[eventKey].size());
158 EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
159 EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
Yao Chen0ea19902017-11-15 15:44:45 -0800160}
161
Yao Chen5154a372017-10-30 22:57:06 -0700162TEST(OringDurationTrackerTest, TestDurationConditionChange) {
163 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
164
165 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800166 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen5154a372017-10-30 22:57:06 -0700167
168 EXPECT_CALL(*wizard, query(_, key1)) // #4
169 .WillOnce(Return(ConditionState::kFalse));
170
Yao Chenf60e0ba2017-11-29 15:06:41 -0800171 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen5154a372017-10-30 22:57:06 -0700172
173 uint64_t bucketStartTimeNs = 10000000000;
174 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
175 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800176 uint64_t durationTimeNs = 2 * 1000;
Yao Chen5154a372017-10-30 22:57:06 -0700177
Yao Chenf60e0ba2017-11-29 15:06:41 -0800178 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
179 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen5154a372017-10-30 22:57:06 -0700180
Yao Chend5aa01b32017-12-19 16:46:36 -0800181 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yao Chen5154a372017-10-30 22:57:06 -0700182
Yao Chen09294ef2017-11-25 19:54:01 -0800183 tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
184
Yao Chend5aa01b32017-12-19 16:46:36 -0800185 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chen09294ef2017-11-25 19:54:01 -0800186
Yao Chenf60e0ba2017-11-29 15:06:41 -0800187 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
188 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
189 EXPECT_EQ(1u, buckets[eventKey].size());
190 EXPECT_EQ(5ULL, buckets[eventKey][0].mDuration);
Yao Chen09294ef2017-11-25 19:54:01 -0800191}
192
193TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
194 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
195
196 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800197 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen09294ef2017-11-25 19:54:01 -0800198
199 EXPECT_CALL(*wizard, query(_, key1))
200 .Times(2)
201 .WillOnce(Return(ConditionState::kFalse))
202 .WillOnce(Return(ConditionState::kTrue));
203
Yao Chenf60e0ba2017-11-29 15:06:41 -0800204 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen09294ef2017-11-25 19:54:01 -0800205
206 uint64_t bucketStartTimeNs = 10000000000;
207 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
208 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
209 uint64_t durationTimeNs = 2 * 1000;
210
Yao Chenf60e0ba2017-11-29 15:06:41 -0800211 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
212 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen09294ef2017-11-25 19:54:01 -0800213
Yao Chend5aa01b32017-12-19 16:46:36 -0800214 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yao Chen09294ef2017-11-25 19:54:01 -0800215 // condition to false; record duration 5n
216 tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
217 // condition to true.
218 tracker.onSlicedConditionMayChange(eventStartTimeNs + 1000);
219 // 2nd duration: 1000ns
Yao Chend5aa01b32017-12-19 16:46:36 -0800220 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chen09294ef2017-11-25 19:54:01 -0800221
Yao Chenf60e0ba2017-11-29 15:06:41 -0800222 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
223 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
224 EXPECT_EQ(1u, buckets[eventKey].size());
225 EXPECT_EQ(1005ULL, buckets[eventKey][0].mDuration);
Yao Chen5154a372017-10-30 22:57:06 -0700226}
Yao Chen0ea19902017-11-15 15:44:45 -0800227
228TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
229 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
230
231 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800232 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen0ea19902017-11-15 15:44:45 -0800233
234 EXPECT_CALL(*wizard, query(_, key1)) // #4
235 .WillOnce(Return(ConditionState::kFalse));
236
Yao Chenf60e0ba2017-11-29 15:06:41 -0800237 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen0ea19902017-11-15 15:44:45 -0800238
239 uint64_t bucketStartTimeNs = 10000000000;
240 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
241 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
242
Yao Chenf60e0ba2017-11-29 15:06:41 -0800243 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
244 bucketSizeNs, {});
Yao Chen0ea19902017-11-15 15:44:45 -0800245
Yao Chend5aa01b32017-12-19 16:46:36 -0800246 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
247 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2, key1);
Yao Chen0ea19902017-11-15 15:44:45 -0800248
Yao Chend5aa01b32017-12-19 16:46:36 -0800249 tracker.noteStop(kEventKey1, eventStartTimeNs + 3, false);
Yao Chen0ea19902017-11-15 15:44:45 -0800250
251 tracker.onSlicedConditionMayChange(eventStartTimeNs + 15);
252
Yao Chend5aa01b32017-12-19 16:46:36 -0800253 tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
Yao Chen0ea19902017-11-15 15:44:45 -0800254
Yao Chenf60e0ba2017-11-29 15:06:41 -0800255 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
256 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
257 EXPECT_EQ(1u, buckets[eventKey].size());
258 EXPECT_EQ(15ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800259}
260
261TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
262 Alert alert;
263 alert.set_name("alert");
264 alert.set_metric_name("1");
265 alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
266 alert.set_number_of_buckets(2);
267 alert.set_refractory_period_secs(1);
268
Yao Chenf60e0ba2017-11-29 15:06:41 -0800269 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800270 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
271 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800272 key1["APP_BACKGROUND"] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800273 uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
274 uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
275 uint64_t bucketSizeNs = 30 * NS_PER_SEC;
276
Bookatz857aaa52017-12-19 15:29:06 -0800277 sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800278 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
279 bucketSizeNs, {anomalyTracker});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800280
281 // Nothing in the past bucket.
Yao Chend5aa01b32017-12-19 16:46:36 -0800282 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800283 EXPECT_EQ((long long)(alert.trigger_if_sum_gt() + eventStartTimeNs),
284 tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
285
Yao Chend5aa01b32017-12-19 16:46:36 -0800286 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 3, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800287 EXPECT_EQ(0u, buckets[eventKey].size());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800288
289 uint64_t event1StartTimeNs = eventStartTimeNs + 10;
Yao Chend5aa01b32017-12-19 16:46:36 -0800290 tracker.noteStart(kEventKey1, true, event1StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800291 // No past buckets. The anomaly will happen in bucket #0.
292 EXPECT_EQ((long long)(event1StartTimeNs + alert.trigger_if_sum_gt() - 3),
293 tracker.predictAnomalyTimestampNs(*anomalyTracker, event1StartTimeNs));
294
295 uint64_t event1StopTimeNs = eventStartTimeNs + bucketSizeNs + 10;
Yao Chenf60e0ba2017-11-29 15:06:41 -0800296 tracker.flushIfNeeded(event1StopTimeNs, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800297 tracker.noteStop(kEventKey1, event1StopTimeNs, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800298
299 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
300 EXPECT_EQ(1u, buckets[eventKey].size());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800301 EXPECT_EQ(3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800302 buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800303
304 const int64_t bucket0Duration = 3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10;
305 const int64_t bucket1Duration = eventStartTimeNs + 10 - bucketStartTimeNs;
306
307 // One past buckets. The anomaly will happen in bucket #1.
308 uint64_t event2StartTimeNs = eventStartTimeNs + bucketSizeNs + 15;
Yao Chend5aa01b32017-12-19 16:46:36 -0800309 tracker.noteStart(kEventKey1, true, event2StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800310 EXPECT_EQ((long long)(event2StartTimeNs + alert.trigger_if_sum_gt() - bucket0Duration -
311 bucket1Duration),
312 tracker.predictAnomalyTimestampNs(*anomalyTracker, event2StartTimeNs));
Yao Chend5aa01b32017-12-19 16:46:36 -0800313 tracker.noteStop(kEventKey1, event2StartTimeNs + 1, false);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800314
315 // Only one past buckets is applicable. Bucket +0 should be trashed. The anomaly will happen in
316 // bucket #2.
317 uint64_t event3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs - 9 * NS_PER_SEC;
Yao Chend5aa01b32017-12-19 16:46:36 -0800318 tracker.noteStart(kEventKey1, true, event3StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800319 EXPECT_EQ((long long)(event3StartTimeNs + alert.trigger_if_sum_gt() - bucket1Duration - 1LL),
320 tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs));
321}
322
323TEST(OringDurationTrackerTest, TestAnomalyDetection) {
324 Alert alert;
325 alert.set_name("alert");
326 alert.set_metric_name("1");
327 alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
328 alert.set_number_of_buckets(2);
329 alert.set_refractory_period_secs(1);
330
Yao Chenf60e0ba2017-11-29 15:06:41 -0800331 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800332 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
333 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800334 key1["APP_BACKGROUND"] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800335 uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
336 uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
337 uint64_t bucketSizeNs = 30 * NS_PER_SEC;
338
Bookatz857aaa52017-12-19 15:29:06 -0800339 sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800340 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
341 bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800342
Yao Chend5aa01b32017-12-19 16:46:36 -0800343 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
344 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 10, false);
Bookatz857aaa52017-12-19 15:29:06 -0800345 EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs, -1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800346 EXPECT_TRUE(tracker.mStarted.empty());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800347 EXPECT_EQ(10LL, tracker.mDuration);
348
349 EXPECT_EQ(0u, tracker.mStarted.size());
350
Yao Chend5aa01b32017-12-19 16:46:36 -0800351 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs + 20, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800352 EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
353 EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
354 (long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
Yao Chenf60e0ba2017-11-29 15:06:41 -0800355 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800356 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
357 EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800358 EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
Bookatz857aaa52017-12-19 15:29:06 -0800359 anomalyTracker->mLastAnomalyTimestampNs);
Yao Chen0ea19902017-11-15 15:44:45 -0800360}
361
Yao Chen93fe3a32017-11-02 13:52:59 -0700362} // namespace statsd
363} // namespace os
364} // namespace android
Yao Chen5154a372017-10-30 22:57:06 -0700365#else
366GTEST_LOG_(INFO) << "This test does nothing.\n";
367#endif