blob: d34c85b92d8615389d9c3a35ae234f7328b6e887 [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 Chen5154a372017-10-30 22:57:06 -070016#include "src/condition/ConditionWizard.h"
Yangster-mac94e197c2018-01-02 16:03:03 -080017#include "metrics_test_helper.h"
18#include "tests/statsd_test_util.h"
Yao Chen5154a372017-10-30 22:57:06 -070019
Yao Chen93fe3a32017-11-02 13:52:59 -070020#include <gmock/gmock.h>
21#include <gtest/gtest.h>
Yao Chen5154a372017-10-30 22:57:06 -070022#include <stdio.h>
23#include <set>
24#include <unordered_map>
25#include <vector>
26
Yao Chen5154a372017-10-30 22:57:06 -070027using namespace testing;
28using android::sp;
29using std::set;
30using std::unordered_map;
31using std::vector;
32
33#ifdef __ANDROID__
Yao Chen93fe3a32017-11-02 13:52:59 -070034namespace android {
35namespace os {
36namespace statsd {
Yao Chen5154a372017-10-30 22:57:06 -070037
Yangster-mac94e197c2018-01-02 16:03:03 -080038const ConfigKey kConfigKey(0, 12345);
Yangster-mac20877162017-12-22 17:19:39 -080039const int TagId = 1;
Yangster-mac94e197c2018-01-02 16:03:03 -080040const int64_t metricId = 123;
Yangster-mac20877162017-12-22 17:19:39 -080041const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "event");
Yao Chend5aa01b32017-12-19 16:46:36 -080042
Yangster-mac20877162017-12-22 17:19:39 -080043const std::vector<HashableDimensionKey> kConditionKey1 = {getMockedDimensionKey(TagId, 1, "maps")};
44const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
45const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
Yao Chenb3561512017-11-21 18:07:17 -080046
Yao Chen5154a372017-10-30 22:57:06 -070047TEST(OringDurationTrackerTest, TestDurationOverlap) {
48 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
49
50 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -080051 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yao Chen5154a372017-10-30 22:57:06 -070052
Yao Chenf60e0ba2017-11-29 15:06:41 -080053 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen5154a372017-10-30 22:57:06 -070054
55 uint64_t bucketStartTimeNs = 10000000000;
56 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
57 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
Yangster-mace2cd6d52017-11-09 20:38:30 -080058 uint64_t durationTimeNs = 2 * 1000;
Yao Chen5154a372017-10-30 22:57:06 -070059
Yangster-mac94e197c2018-01-02 16:03:03 -080060 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
Yao Chenf60e0ba2017-11-29 15:06:41 -080061 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen5154a372017-10-30 22:57:06 -070062
Yao Chend5aa01b32017-12-19 16:46:36 -080063 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -080064 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chend5aa01b32017-12-19 16:46:36 -080065 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, key1); // overlapping wl
Yangster-mace2cd6d52017-11-09 20:38:30 -080066 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chen5154a372017-10-30 22:57:06 -070067
Yao Chend5aa01b32017-12-19 16:46:36 -080068 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -080069 tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1, &buckets);
70 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
71
72 EXPECT_EQ(1u, buckets[eventKey].size());
73 EXPECT_EQ(durationTimeNs, buckets[eventKey][0].mDuration);
Yao Chen5154a372017-10-30 22:57:06 -070074}
75
Yao Chen0ea19902017-11-15 15:44:45 -080076TEST(OringDurationTrackerTest, TestDurationNested) {
77 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
78
79 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -080080 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yao Chen0ea19902017-11-15 15:44:45 -080081
Yao Chenf60e0ba2017-11-29 15:06:41 -080082 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen0ea19902017-11-15 15:44:45 -080083
84 uint64_t bucketStartTimeNs = 10000000000;
85 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
86 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
87
Yangster-mac94e197c2018-01-02 16:03:03 -080088 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
Yao Chenf60e0ba2017-11-29 15:06:41 -080089 bucketSizeNs, {});
Yao Chen0ea19902017-11-15 15:44:45 -080090
Yao Chend5aa01b32017-12-19 16:46:36 -080091 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
92 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, key1); // overlapping wl
Yao Chen0ea19902017-11-15 15:44:45 -080093
Yao Chend5aa01b32017-12-19 16:46:36 -080094 tracker.noteStop(kEventKey1, eventStartTimeNs + 2000, false);
95 tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
Yao Chen0ea19902017-11-15 15:44:45 -080096
Yao Chenf60e0ba2017-11-29 15:06:41 -080097 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
98 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
99 EXPECT_EQ(1u, buckets[eventKey].size());
100 EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800101}
102
103TEST(OringDurationTrackerTest, TestStopAll) {
104 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
105
106 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800107 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800108
Yao Chenf60e0ba2017-11-29 15:06:41 -0800109 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800110
111 uint64_t bucketStartTimeNs = 10000000000;
112 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
113 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
114
Yangster-mac94e197c2018-01-02 16:03:03 -0800115 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800116 bucketSizeNs, {});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800117
Yao Chend5aa01b32017-12-19 16:46:36 -0800118 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
119 tracker.noteStart(kEventKey2, true, eventStartTimeNs + 10, key1); // overlapping wl
Yangster-mace2cd6d52017-11-09 20:38:30 -0800120
121 tracker.noteStopAll(eventStartTimeNs + 2003);
122
Yao Chenf60e0ba2017-11-29 15:06:41 -0800123 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
124 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
125 EXPECT_EQ(1u, buckets[eventKey].size());
126 EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800127}
128
129TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
130 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
131
132 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800133 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800134
Yao Chenf60e0ba2017-11-29 15:06:41 -0800135 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800136
137 uint64_t bucketStartTimeNs = 10000000000;
138 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
139 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
140 uint64_t durationTimeNs = 2 * 1000;
141
Yangster-mac94e197c2018-01-02 16:03:03 -0800142 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800143 bucketSizeNs, {});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800144
Yao Chend5aa01b32017-12-19 16:46:36 -0800145 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800146 EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800147 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800148 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2 * bucketSizeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800149 EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
150
Yao Chenf60e0ba2017-11-29 15:06:41 -0800151 EXPECT_EQ(2u, buckets[eventKey].size());
152 EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
153 EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800154
Yao Chend5aa01b32017-12-19 16:46:36 -0800155 tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 10, false);
156 tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 12, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800157 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12, &buckets);
158 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
159 EXPECT_EQ(2u, buckets[eventKey].size());
160 EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
161 EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
Yao Chen0ea19902017-11-15 15:44:45 -0800162}
163
Yao Chen5154a372017-10-30 22:57:06 -0700164TEST(OringDurationTrackerTest, TestDurationConditionChange) {
165 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
166
167 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800168 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yao Chen5154a372017-10-30 22:57:06 -0700169
170 EXPECT_CALL(*wizard, query(_, key1)) // #4
171 .WillOnce(Return(ConditionState::kFalse));
172
Yao Chenf60e0ba2017-11-29 15:06:41 -0800173 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen5154a372017-10-30 22:57:06 -0700174
175 uint64_t bucketStartTimeNs = 10000000000;
176 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
177 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800178 uint64_t durationTimeNs = 2 * 1000;
Yao Chen5154a372017-10-30 22:57:06 -0700179
Yangster-mac94e197c2018-01-02 16:03:03 -0800180 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800181 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen5154a372017-10-30 22:57:06 -0700182
Yao Chend5aa01b32017-12-19 16:46:36 -0800183 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yao Chen5154a372017-10-30 22:57:06 -0700184
Yao Chen09294ef2017-11-25 19:54:01 -0800185 tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
186
Yao Chend5aa01b32017-12-19 16:46:36 -0800187 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chen09294ef2017-11-25 19:54:01 -0800188
Yao Chenf60e0ba2017-11-29 15:06:41 -0800189 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
190 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
191 EXPECT_EQ(1u, buckets[eventKey].size());
192 EXPECT_EQ(5ULL, buckets[eventKey][0].mDuration);
Yao Chen09294ef2017-11-25 19:54:01 -0800193}
194
195TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
196 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
197
198 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800199 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yao Chen09294ef2017-11-25 19:54:01 -0800200
201 EXPECT_CALL(*wizard, query(_, key1))
202 .Times(2)
203 .WillOnce(Return(ConditionState::kFalse))
204 .WillOnce(Return(ConditionState::kTrue));
205
Yao Chenf60e0ba2017-11-29 15:06:41 -0800206 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen09294ef2017-11-25 19:54:01 -0800207
208 uint64_t bucketStartTimeNs = 10000000000;
209 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
210 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
211 uint64_t durationTimeNs = 2 * 1000;
212
Yangster-mac94e197c2018-01-02 16:03:03 -0800213 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800214 bucketStartTimeNs, bucketSizeNs, {});
Yao Chen09294ef2017-11-25 19:54:01 -0800215
Yao Chend5aa01b32017-12-19 16:46:36 -0800216 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
Yao Chen09294ef2017-11-25 19:54:01 -0800217 // condition to false; record duration 5n
218 tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
219 // condition to true.
220 tracker.onSlicedConditionMayChange(eventStartTimeNs + 1000);
221 // 2nd duration: 1000ns
Yao Chend5aa01b32017-12-19 16:46:36 -0800222 tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
Yao Chen09294ef2017-11-25 19:54:01 -0800223
Yao Chenf60e0ba2017-11-29 15:06:41 -0800224 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
225 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
226 EXPECT_EQ(1u, buckets[eventKey].size());
227 EXPECT_EQ(1005ULL, buckets[eventKey][0].mDuration);
Yao Chen5154a372017-10-30 22:57:06 -0700228}
Yao Chen0ea19902017-11-15 15:44:45 -0800229
230TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
231 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
232
233 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800234 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yao Chen0ea19902017-11-15 15:44:45 -0800235
236 EXPECT_CALL(*wizard, query(_, key1)) // #4
237 .WillOnce(Return(ConditionState::kFalse));
238
Yao Chenf60e0ba2017-11-29 15:06:41 -0800239 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yao Chen0ea19902017-11-15 15:44:45 -0800240
241 uint64_t bucketStartTimeNs = 10000000000;
242 uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
243 uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
244
Yangster-mac94e197c2018-01-02 16:03:03 -0800245 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800246 bucketSizeNs, {});
Yao Chen0ea19902017-11-15 15:44:45 -0800247
Yao Chend5aa01b32017-12-19 16:46:36 -0800248 tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
249 tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2, key1);
Yao Chen0ea19902017-11-15 15:44:45 -0800250
Yao Chend5aa01b32017-12-19 16:46:36 -0800251 tracker.noteStop(kEventKey1, eventStartTimeNs + 3, false);
Yao Chen0ea19902017-11-15 15:44:45 -0800252
253 tracker.onSlicedConditionMayChange(eventStartTimeNs + 15);
254
Yao Chend5aa01b32017-12-19 16:46:36 -0800255 tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
Yao Chen0ea19902017-11-15 15:44:45 -0800256
Yao Chenf60e0ba2017-11-29 15:06:41 -0800257 tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
258 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
259 EXPECT_EQ(1u, buckets[eventKey].size());
260 EXPECT_EQ(15ULL, buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800261}
262
263TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
264 Alert alert;
Yangster-mac94e197c2018-01-02 16:03:03 -0800265 alert.set_id(101);
266 alert.set_metric_id(1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800267 alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
268 alert.set_number_of_buckets(2);
269 alert.set_refractory_period_secs(1);
270
Yao Chenf60e0ba2017-11-29 15:06:41 -0800271 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800272 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
273 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800274 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800275 uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
276 uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
277 uint64_t bucketSizeNs = 30 * NS_PER_SEC;
278
Bookatz857aaa52017-12-19 15:29:06 -0800279 sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
Yangster-mac94e197c2018-01-02 16:03:03 -0800280 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800281 bucketSizeNs, {anomalyTracker});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800282
283 // Nothing in the past bucket.
Yao Chend5aa01b32017-12-19 16:46:36 -0800284 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800285 EXPECT_EQ((long long)(alert.trigger_if_sum_gt() + eventStartTimeNs),
286 tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
287
Yao Chend5aa01b32017-12-19 16:46:36 -0800288 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 3, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800289 EXPECT_EQ(0u, buckets[eventKey].size());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800290
291 uint64_t event1StartTimeNs = eventStartTimeNs + 10;
Yao Chend5aa01b32017-12-19 16:46:36 -0800292 tracker.noteStart(kEventKey1, true, event1StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800293 // No past buckets. The anomaly will happen in bucket #0.
294 EXPECT_EQ((long long)(event1StartTimeNs + alert.trigger_if_sum_gt() - 3),
295 tracker.predictAnomalyTimestampNs(*anomalyTracker, event1StartTimeNs));
296
297 uint64_t event1StopTimeNs = eventStartTimeNs + bucketSizeNs + 10;
Yao Chenf60e0ba2017-11-29 15:06:41 -0800298 tracker.flushIfNeeded(event1StopTimeNs, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800299 tracker.noteStop(kEventKey1, event1StopTimeNs, false);
Yao Chenf60e0ba2017-11-29 15:06:41 -0800300
301 EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
302 EXPECT_EQ(1u, buckets[eventKey].size());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800303 EXPECT_EQ(3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800304 buckets[eventKey][0].mDuration);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800305
306 const int64_t bucket0Duration = 3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10;
307 const int64_t bucket1Duration = eventStartTimeNs + 10 - bucketStartTimeNs;
308
309 // One past buckets. The anomaly will happen in bucket #1.
310 uint64_t event2StartTimeNs = eventStartTimeNs + bucketSizeNs + 15;
Yao Chend5aa01b32017-12-19 16:46:36 -0800311 tracker.noteStart(kEventKey1, true, event2StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800312 EXPECT_EQ((long long)(event2StartTimeNs + alert.trigger_if_sum_gt() - bucket0Duration -
313 bucket1Duration),
314 tracker.predictAnomalyTimestampNs(*anomalyTracker, event2StartTimeNs));
Yao Chend5aa01b32017-12-19 16:46:36 -0800315 tracker.noteStop(kEventKey1, event2StartTimeNs + 1, false);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800316
317 // Only one past buckets is applicable. Bucket +0 should be trashed. The anomaly will happen in
318 // bucket #2.
319 uint64_t event3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs - 9 * NS_PER_SEC;
Yao Chend5aa01b32017-12-19 16:46:36 -0800320 tracker.noteStart(kEventKey1, true, event3StartTimeNs, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800321 EXPECT_EQ((long long)(event3StartTimeNs + alert.trigger_if_sum_gt() - bucket1Duration - 1LL),
322 tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs));
323}
324
325TEST(OringDurationTrackerTest, TestAnomalyDetection) {
326 Alert alert;
Yangster-mac94e197c2018-01-02 16:03:03 -0800327 alert.set_id(101);
328 alert.set_metric_id(1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800329 alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
330 alert.set_number_of_buckets(2);
331 alert.set_refractory_period_secs(1);
332
Yao Chenf60e0ba2017-11-29 15:06:41 -0800333 unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800334 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
335 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800336 key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800337 uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
338 uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
339 uint64_t bucketSizeNs = 30 * NS_PER_SEC;
340
Bookatz857aaa52017-12-19 15:29:06 -0800341 sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
Yangster-mac94e197c2018-01-02 16:03:03 -0800342 OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true /*nesting*/,
Yao Chenf60e0ba2017-11-29 15:06:41 -0800343 bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
Yangster-mace2cd6d52017-11-09 20:38:30 -0800344
Yao Chend5aa01b32017-12-19 16:46:36 -0800345 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
346 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 10, false);
Bookatz857aaa52017-12-19 15:29:06 -0800347 EXPECT_EQ(anomalyTracker->mLastAnomalyTimestampNs, -1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800348 EXPECT_TRUE(tracker.mStarted.empty());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800349 EXPECT_EQ(10LL, tracker.mDuration);
350
351 EXPECT_EQ(0u, tracker.mStarted.size());
352
Yao Chend5aa01b32017-12-19 16:46:36 -0800353 tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs + 20, key1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800354 EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
355 EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
356 (long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
Yao Chenf60e0ba2017-11-29 15:06:41 -0800357 tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
Yao Chend5aa01b32017-12-19 16:46:36 -0800358 tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
359 EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
Yangster-mace2cd6d52017-11-09 20:38:30 -0800360 EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
Bookatz857aaa52017-12-19 15:29:06 -0800361 anomalyTracker->mLastAnomalyTimestampNs);
Yao Chen0ea19902017-11-15 15:44:45 -0800362}
363
Yao Chen93fe3a32017-11-02 13:52:59 -0700364} // namespace statsd
365} // namespace os
366} // namespace android
Yao Chen5154a372017-10-30 22:57:06 -0700367#else
368GTEST_LOG_(INFO) << "This test does nothing.\n";
369#endif