blob: e0f554d6391e1d8963d759afa86ef0a6f43c3f7e [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");
Yao Chend5aa01b32017-12-19 16:46:36 -080038const HashableDimensionKey eventKey = getMockedDimensionKey(0, "event");
39
40const HashableDimensionKey kConditionKey1 = getMockedDimensionKey(1, "maps");
41const HashableDimensionKey kEventKey1 = getMockedDimensionKey(2, "maps");
42const HashableDimensionKey kEventKey2 = getMockedDimensionKey(3, "maps");
Yao Chenb3561512017-11-21 18:07:17 -080043
Yao Chen5154a372017-10-30 22:57:06 -070044TEST(OringDurationTrackerTest, TestDurationOverlap) {
45 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
46
47 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -080048 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen5154a372017-10-30 22:57:06 -070049
Yao Chenf60e0ba2017-11-29 15:06:41 -080050 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen5154a372017-10-30 22:57:06 -070051
52 uint64_t bucketStartTimeNs = 10000000000;
53 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
54 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
Yangster-mace2cd6d52017-11-09 20:38:30 -080055 uint64_t durationTimeNs = 2 * 1000;
Yao Chen5154a372017-10-30 22:57:06 -070056
Yao Chenf60e0ba2017-11-29 15:06:41 -080057 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
58 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen5154a372017-10-30 22:57:06 -070059
Yao Chend5aa01b32017-12-19 16:46:36 -080060 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -080061 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chend5aa01b32017-12-19 16:46:36 -080062 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, key1); // overlapping wl
Yangster-mace2cd6d52017-11-09 20:38:30 -080063 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chen5154a372017-10-30 22:57:06 -070064
Yao Chend5aa01b32017-12-19 16:46:36 -080065 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -080066 tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1, &buckets);
67 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
68
69 EXPECT_EQ(1u, buckets[eventKey].size());
70 EXPECT_EQ(durationTimeNs, buckets[eventKey][0].mDuration);
Yao Chen5154a372017-10-30 22:57:06 -070071}
72
Yao Chen0ea19902017-11-15 15:44:45 -080073TEST(OringDurationTrackerTest, TestDurationNested) {
74 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
75
76 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -080077 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen0ea19902017-11-15 15:44:45 -080078
Yao Chenf60e0ba2017-11-29 15:06:41 -080079 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen0ea19902017-11-15 15:44:45 -080080
81 uint64_t bucketStartTimeNs = 10000000000;
82 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
83 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
84
Yao Chenf60e0ba2017-11-29 15:06:41 -080085 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
86 bucketSizeNs, {});
Yao Chen0ea19902017-11-15 15:44:45 -080087
Yao Chend5aa01b32017-12-19 16:46:36 -080088 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
89 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, key1); // overlapping wl
Yao Chen0ea19902017-11-15 15:44:45 -080090
Yao Chend5aa01b32017-12-19 16:46:36 -080091 tracker.noteStop(kEventKey1, eventStartTimeNs + 2000, false);
92 tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
Yao Chen0ea19902017-11-15 15:44:45 -080093
Yao Chenf60e0ba2017-11-29 15:06:41 -080094 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
95 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
96 EXPECT_EQ(1u, buckets[eventKey].size());
97 EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -080098}
99
100TEST(OringDurationTrackerTest, TestStopAll) {
101 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
102
103 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800104 key1["APP_BACKGROUND"] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800105
Yao Chenf60e0ba2017-11-29 15:06:41 -0800106 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800107
108 uint64_t bucketStartTimeNs = 10000000000;
109 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
110 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
111
Yao Chenf60e0ba2017-11-29 15:06:41 -0800112 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
113 bucketSizeNs, {});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800114
Yao Chend5aa01b32017-12-19 16:46:36 -0800115 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
116 tracker.noteStart(kEventKey2, true, eventStartTimeNs + 10, key1); // overlapping wl
Yangster-mace2cd6d52017-11-09 20:38:30 -0800117
118 tracker.noteStopAll(eventStartTimeNs + 2003);
119
Yao Chenf60e0ba2017-11-29 15:06:41 -0800120 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
121 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
122 EXPECT_EQ(1u, buckets[eventKey].size());
123 EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800124}
125
126TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
127 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
128
129 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800130 key1["APP_BACKGROUND"] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800131
Yao Chenf60e0ba2017-11-29 15:06:41 -0800132 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800133
134 uint64_t bucketStartTimeNs = 10000000000;
135 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
136 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
137 uint64_t durationTimeNs = 2 * 1000;
138
Yao Chenf60e0ba2017-11-29 15:06:41 -0800139 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
140 bucketSizeNs, {});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800141
Yao Chend5aa01b32017-12-19 16:46:36 -0800142 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800143 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800144 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800145 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2 * bucketSizeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800146 EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
147
Yao Chenf60e0ba2017-11-29 15:06:41 -0800148 EXPECT_EQ(2u, buckets[eventKey].size());
149 EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
150 EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800151
Yao Chend5aa01b32017-12-19 16:46:36 -0800152 tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 10, false);
153 tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 12, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800154 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12, &buckets);
155 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
156 EXPECT_EQ(2u, buckets[eventKey].size());
157 EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
158 EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
Yao Chen0ea19902017-11-15 15:44:45 -0800159}
160
Yao Chen5154a372017-10-30 22:57:06 -0700161TEST(OringDurationTrackerTest, TestDurationConditionChange) {
162 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
163
164 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800165 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen5154a372017-10-30 22:57:06 -0700166
167 EXPECT_CALL(*wizard, query(_, key1)) // #4
168 .WillOnce(Return(ConditionState::kFalse));
169
Yao Chenf60e0ba2017-11-29 15:06:41 -0800170 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen5154a372017-10-30 22:57:06 -0700171
172 uint64_t bucketStartTimeNs = 10000000000;
173 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
174 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800175 uint64_t durationTimeNs = 2 * 1000;
Yao Chen5154a372017-10-30 22:57:06 -0700176
Yao Chenf60e0ba2017-11-29 15:06:41 -0800177 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
178 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen5154a372017-10-30 22:57:06 -0700179
Yao Chend5aa01b32017-12-19 16:46:36 -0800180 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yao Chen5154a372017-10-30 22:57:06 -0700181
Yao Chen09294ef2017-11-25 19:54:01 -0800182 tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
183
Yao Chend5aa01b32017-12-19 16:46:36 -0800184 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chen09294ef2017-11-25 19:54:01 -0800185
Yao Chenf60e0ba2017-11-29 15:06:41 -0800186 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
187 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
188 EXPECT_EQ(1u, buckets[eventKey].size());
189 EXPECT_EQ(5ULL, buckets[eventKey][0].mDuration);
Yao Chen09294ef2017-11-25 19:54:01 -0800190}
191
192TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
193 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
194
195 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800196 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen09294ef2017-11-25 19:54:01 -0800197
198 EXPECT_CALL(*wizard, query(_, key1))
199 .Times(2)
200 .WillOnce(Return(ConditionState::kFalse))
201 .WillOnce(Return(ConditionState::kTrue));
202
Yao Chenf60e0ba2017-11-29 15:06:41 -0800203 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen09294ef2017-11-25 19:54:01 -0800204
205 uint64_t bucketStartTimeNs = 10000000000;
206 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
207 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
208 uint64_t durationTimeNs = 2 * 1000;
209
Yao Chenf60e0ba2017-11-29 15:06:41 -0800210 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
211 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen09294ef2017-11-25 19:54:01 -0800212
Yao Chend5aa01b32017-12-19 16:46:36 -0800213 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yao Chen09294ef2017-11-25 19:54:01 -0800214 // condition to false; record duration 5n
215 tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
216 // condition to true.
217 tracker.onSlicedConditionMayChange(eventStartTimeNs + 1000);
218 // 2nd duration: 1000ns
Yao Chend5aa01b32017-12-19 16:46:36 -0800219 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chen09294ef2017-11-25 19:54:01 -0800220
Yao Chenf60e0ba2017-11-29 15:06:41 -0800221 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
222 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
223 EXPECT_EQ(1u, buckets[eventKey].size());
224 EXPECT_EQ(1005ULL, buckets[eventKey][0].mDuration);
Yao Chen5154a372017-10-30 22:57:06 -0700225}
Yao Chen0ea19902017-11-15 15:44:45 -0800226
227TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
228 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
229
230 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800231 key1["APP_BACKGROUND"] = kConditionKey1;
Yao Chen0ea19902017-11-15 15:44:45 -0800232
233 EXPECT_CALL(*wizard, query(_, key1)) // #4
234 .WillOnce(Return(ConditionState::kFalse));
235
Yao Chenf60e0ba2017-11-29 15:06:41 -0800236 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen0ea19902017-11-15 15:44:45 -0800237
238 uint64_t bucketStartTimeNs = 10000000000;
239 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
240 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
241
Yao Chenf60e0ba2017-11-29 15:06:41 -0800242 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
243 bucketSizeNs, {});
Yao Chen0ea19902017-11-15 15:44:45 -0800244
Yao Chend5aa01b32017-12-19 16:46:36 -0800245 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
246 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2, key1);
Yao Chen0ea19902017-11-15 15:44:45 -0800247
Yao Chend5aa01b32017-12-19 16:46:36 -0800248 tracker.noteStop(kEventKey1, eventStartTimeNs + 3, false);
Yao Chen0ea19902017-11-15 15:44:45 -0800249
250 tracker.onSlicedConditionMayChange(eventStartTimeNs + 15);
251
Yao Chend5aa01b32017-12-19 16:46:36 -0800252 tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
Yao Chen0ea19902017-11-15 15:44:45 -0800253
Yao Chenf60e0ba2017-11-29 15:06:41 -0800254 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
255 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
256 EXPECT_EQ(1u, buckets[eventKey].size());
257 EXPECT_EQ(15ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800258}
259
260TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
261 Alert alert;
262 alert.set_name("alert");
263 alert.set_metric_name("1");
264 alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
265 alert.set_number_of_buckets(2);
266 alert.set_refractory_period_secs(1);
267
Yao Chenf60e0ba2017-11-29 15:06:41 -0800268 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800269 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
270 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800271 key1["APP_BACKGROUND"] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800272 uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
273 uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
274 uint64_t bucketSizeNs = 30 * NS_PER_SEC;
275
Bookatz857aaa52017-12-19 15:29:06 -0800276 sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800277 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
278 bucketSizeNs, {anomalyTracker});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800279
280 // Nothing in the past bucket.
Yao Chend5aa01b32017-12-19 16:46:36 -0800281 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800282 EXPECT_EQ((long long)(alert.trigger_if_sum_gt() + eventStartTimeNs),
283 tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
284
Yao Chend5aa01b32017-12-19 16:46:36 -0800285 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 3, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800286 EXPECT_EQ(0u, buckets[eventKey].size());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800287
288 uint64_t event1StartTimeNs = eventStartTimeNs + 10;
Yao Chend5aa01b32017-12-19 16:46:36 -0800289 tracker.noteStart(kEventKey1, true, event1StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800290 // No past buckets. The anomaly will happen in bucket #0.
291 EXPECT_EQ((long long)(event1StartTimeNs + alert.trigger_if_sum_gt() - 3),
292 tracker.predictAnomalyTimestampNs(*anomalyTracker, event1StartTimeNs));
293
294 uint64_t event1StopTimeNs = eventStartTimeNs + bucketSizeNs + 10;
Yao Chenf60e0ba2017-11-29 15:06:41 -0800295 tracker.flushIfNeeded(event1StopTimeNs, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800296 tracker.noteStop(kEventKey1, event1StopTimeNs, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800297
298 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
299 EXPECT_EQ(1u, buckets[eventKey].size());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800300 EXPECT_EQ(3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800301 buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800302
303 const int64_t bucket0Duration = 3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10;
304 const int64_t bucket1Duration = eventStartTimeNs + 10 - bucketStartTimeNs;
305
306 // One past buckets. The anomaly will happen in bucket #1.
307 uint64_t event2StartTimeNs = eventStartTimeNs + bucketSizeNs + 15;
Yao Chend5aa01b32017-12-19 16:46:36 -0800308 tracker.noteStart(kEventKey1, true, event2StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800309 EXPECT_EQ((long long)(event2StartTimeNs + alert.trigger_if_sum_gt() - bucket0Duration -
310 bucket1Duration),
311 tracker.predictAnomalyTimestampNs(*anomalyTracker, event2StartTimeNs));
Yao Chend5aa01b32017-12-19 16:46:36 -0800312 tracker.noteStop(kEventKey1, event2StartTimeNs + 1, false);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800313
314 // Only one past buckets is applicable. Bucket +0 should be trashed. The anomaly will happen in
315 // bucket #2.
316 uint64_t event3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs - 9 * NS_PER_SEC;
Yao Chend5aa01b32017-12-19 16:46:36 -0800317 tracker.noteStart(kEventKey1, true, event3StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800318 EXPECT_EQ((long long)(event3StartTimeNs + alert.trigger_if_sum_gt() - bucket1Duration - 1LL),
319 tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs));
320}
321
322TEST(OringDurationTrackerTest, TestAnomalyDetection) {
323 Alert alert;
324 alert.set_name("alert");
325 alert.set_metric_name("1");
326 alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
327 alert.set_number_of_buckets(2);
328 alert.set_refractory_period_secs(1);
329
Yao Chenf60e0ba2017-11-29 15:06:41 -0800330 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800331 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
332 ConditionKey key1;
Yao Chend5aa01b32017-12-19 16:46:36 -0800333 key1["APP_BACKGROUND"] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800334 uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
335 uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
336 uint64_t bucketSizeNs = 30 * NS_PER_SEC;
337
Bookatz857aaa52017-12-19 15:29:06 -0800338 sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800339 OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
340 bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800341
Yao Chend5aa01b32017-12-19 16:46:36 -0800342 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
343 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 10, false);
Bookatz857aaa52017-12-19 15:29:06 -0800344 EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs, -1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800345 EXPECT_TRUE(tracker.mStarted.empty());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800346 EXPECT_EQ(10LL, tracker.mDuration);
347
348 EXPECT_EQ(0u, tracker.mStarted.size());
349
Yao Chend5aa01b32017-12-19 16:46:36 -0800350 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs + 20, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800351 EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
352 EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
353 (long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
Yao Chenf60e0ba2017-11-29 15:06:41 -0800354 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800355 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
356 EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800357 EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
Bookatz857aaa52017-12-19 15:29:06 -0800358 anomalyTracker->mLastAnomalyTimestampNs);
Yao Chen0ea19902017-11-15 15:44:45 -0800359}
360
Yao Chen93fe3a32017-11-02 13:52:59 -0700361} // namespace statsd
362} // namespace os
363} // namespace android
Yao Chen5154a372017-10-30 22:57:06 -0700364#else
365GTEST_LOG_(INFO) << "This test does nothing.\n";
366#endif