blob: 8ef251952db71ea70b891906240bd0543d9dbaeb [file] [log] [blame]
Yangsterf2bee6f2017-11-29 12:01:05 -08001// 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
15#include "src/metrics/DurationMetricProducer.h"
Yangsterf2bee6f2017-11-29 12:01:05 -080016
17#include <gmock/gmock.h>
18#include <gtest/gtest.h>
19#include <stdio.h>
tsaichristine7747d372020-02-28 17:36:59 -080020
Yangsterf2bee6f2017-11-29 12:01:05 -080021#include <set>
22#include <unordered_map>
23#include <vector>
24
tsaichristine7747d372020-02-28 17:36:59 -080025#include "metrics_test_helper.h"
26#include "src/condition/ConditionWizard.h"
27#include "src/stats_log_util.h"
28#include "stats_event.h"
tsaichristine8dca82e2020-04-07 09:40:03 -070029#include "tests/statsd_test_util.h"
tsaichristine7747d372020-02-28 17:36:59 -080030
Yangsterf2bee6f2017-11-29 12:01:05 -080031using namespace android::os::statsd;
32using namespace testing;
33using android::sp;
34using std::set;
35using std::unordered_map;
36using std::vector;
37
38#ifdef __ANDROID__
39
40namespace android {
41namespace os {
42namespace statsd {
43
Yangsterf2bee6f2017-11-29 12:01:05 -080044
tsaichristine7747d372020-02-28 17:36:59 -080045namespace {
46
Tej Singhe678cb72020-04-14 16:23:30 -070047const ConfigKey kConfigKey(0, 12345);
tsaichristine7747d372020-02-28 17:36:59 -080048void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
49 AStatsEvent* statsEvent = AStatsEvent_obtain();
50 AStatsEvent_setAtomId(statsEvent, atomId);
51 AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
tsaichristine7747d372020-02-28 17:36:59 -080052
tsaichristine8dca82e2020-04-07 09:40:03 -070053 parseStatsEventToLogEvent(statsEvent, logEvent);
tsaichristine7747d372020-02-28 17:36:59 -080054}
55
56} // namespace
57
Tej Singhe678cb72020-04-14 16:23:30 -070058// Setup for parameterized tests.
59class DurationMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
60
61INSTANTIATE_TEST_SUITE_P(DurationMetricProducerTest_PartialBucket,
62 DurationMetricProducerTest_PartialBucket,
63 testing::Values(APP_UPGRADE, BOOT_COMPLETE));
64
Chenjie Yue1361ed2018-07-23 17:33:09 -070065TEST(DurationMetricTrackerTest, TestFirstBucket) {
66 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
67 DurationMetric metric;
68 metric.set_id(1);
69 metric.set_bucket(ONE_MINUTE);
70 metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
71
72 FieldMatcher dimensions;
73 DurationMetricProducer durationProducer(
74 kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
75 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC/2);
76
77 EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs);
78 EXPECT_EQ(10, durationProducer.mCurrentBucketNum);
79 EXPECT_EQ(660000000005, durationProducer.getCurrentBucketEndTimeNs());
80}
81
tsaichristine7747d372020-02-28 17:36:59 -080082TEST(DurationMetricTrackerTest, TestNoCondition) {
83 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
84 int64_t bucketStartTimeNs = 10000000000;
85 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
86
87 DurationMetric metric;
88 metric.set_id(1);
89 metric.set_bucket(ONE_MINUTE);
90 metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
91
92 int tagId = 1;
93 LogEvent event1(/*uid=*/0, /*pid=*/0);
94 makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
95 LogEvent event2(/*uid=*/0, /*pid=*/0);
96 makeLogEvent(&event2, bucketStartTimeNs + bucketSizeNs + 2, tagId);
97
98 FieldMatcher dimensions;
99 DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/,
100 1 /* start index */, 2 /* stop index */,
101 3 /* stop_all index */, false /*nesting*/, wizard,
102 dimensions, bucketStartTimeNs, bucketStartTimeNs);
103
104 durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
105 durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
106 durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
107 EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
108 EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
109 durationProducer.mPastBuckets.end());
110 const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
111 EXPECT_EQ(2UL, buckets.size());
112 EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
113 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
114 EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
115 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
116 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
117 EXPECT_EQ(2LL, buckets[1].mDuration);
118}
119
120TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
121 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
122 int64_t bucketStartTimeNs = 10000000000;
123 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
124
125 DurationMetric metric;
126 metric.set_id(1);
127 metric.set_bucket(ONE_MINUTE);
128 metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
129
130 int tagId = 1;
131 LogEvent event1(/*uid=*/0, /*pid=*/0);
132 makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
133 LogEvent event2(/*uid=*/0, /*pid=*/0);
134 makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
135 LogEvent event3(/*uid=*/0, /*pid=*/0);
136 makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
137 LogEvent event4(/*uid=*/0, /*pid=*/0);
138 makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
139
140 FieldMatcher dimensions;
141 DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
142 1 /* start index */, 2 /* stop index */,
143 3 /* stop_all index */, false /*nesting*/, wizard,
144 dimensions, bucketStartTimeNs, bucketStartTimeNs);
145 durationProducer.mCondition = ConditionState::kFalse;
146
147 EXPECT_FALSE(durationProducer.mCondition);
148 EXPECT_FALSE(durationProducer.isConditionSliced());
149
150 durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
151 durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
152 durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
153 EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
154
155 durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
156 durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
157 durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
158 durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
159 EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
160 EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
161 durationProducer.mPastBuckets.end());
162 const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
163 EXPECT_EQ(1UL, buckets2.size());
164 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
165 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
166 EXPECT_EQ(1LL, buckets2[0].mDuration);
167}
168
169TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
170 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
171 int64_t bucketStartTimeNs = 10000000000;
172 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
173
174 DurationMetric metric;
175 metric.set_id(1);
176 metric.set_bucket(ONE_MINUTE);
177 metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
178
179 int tagId = 1;
180 LogEvent event1(/*uid=*/0, /*pid=*/0);
181 makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
182 LogEvent event2(/*uid=*/0, /*pid=*/0);
183 makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
184 LogEvent event3(/*uid=*/0, /*pid=*/0);
185 makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
186 LogEvent event4(/*uid=*/0, /*pid=*/0);
187 makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
188
189 FieldMatcher dimensions;
190 DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
191 1 /* start index */, 2 /* stop index */,
192 3 /* stop_all index */, false /*nesting*/, wizard,
193 dimensions, bucketStartTimeNs, bucketStartTimeNs);
194
195 EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
196 EXPECT_FALSE(durationProducer.isConditionSliced());
197
198 durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
199 durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
200 durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
201 EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
202
203 durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
204 durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
205 durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
206 durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
207 EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
208 const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
209 EXPECT_EQ(1UL, buckets2.size());
210 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
211 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
212 EXPECT_EQ(1LL, buckets2[0].mDuration);
213}
214
Tej Singhe678cb72020-04-14 16:23:30 -0700215TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDuration) {
tsaichristine7747d372020-02-28 17:36:59 -0800216 /**
217 * The duration starts from the first bucket, through the two partial buckets (10-70sec),
218 * another bucket, and ends at the beginning of the next full bucket.
219 * Expected buckets:
220 * - [10,25]: 14 secs
221 * - [25,70]: All 45 secs
222 * - [70,130]: All 60 secs
223 * - [130, 210]: Only 5 secs (event ended at 135sec)
224 */
225 int64_t bucketStartTimeNs = 10000000000;
226 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
tsaichristine7747d372020-02-28 17:36:59 -0800227 int tagId = 1;
tsaichristine7747d372020-02-28 17:36:59 -0800228
229 DurationMetric metric;
230 metric.set_id(1);
231 metric.set_bucket(ONE_MINUTE);
232 metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
233 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
234 FieldMatcher dimensions;
235 DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
236 1 /* start index */, 2 /* stop index */,
237 3 /* stop_all index */, false /*nesting*/, wizard,
238 dimensions, bucketStartTimeNs, bucketStartTimeNs);
239
Tej Singhe678cb72020-04-14 16:23:30 -0700240 int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
241 LogEvent event1(/*uid=*/0, /*pid=*/0);
242 makeLogEvent(&event1, startTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800243 durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
244 EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
245 EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
246
Tej Singhe678cb72020-04-14 16:23:30 -0700247 int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
248 switch (GetParam()) {
249 case APP_UPGRADE:
250 durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
251 break;
252 case BOOT_COMPLETE:
253 durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
254 break;
255 }
tsaichristine7747d372020-02-28 17:36:59 -0800256 EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
257 std::vector<DurationBucket> buckets =
258 durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
259 EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
Tej Singhe678cb72020-04-14 16:23:30 -0700260 EXPECT_EQ(partialBucketSplitTimeNs, buckets[0].mBucketEndNs);
261 EXPECT_EQ(partialBucketSplitTimeNs - startTimeNs, buckets[0].mDuration);
262 EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
263 EXPECT_EQ(0, durationProducer.getCurrentBucketNum());
tsaichristine7747d372020-02-28 17:36:59 -0800264
265 // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
Tej Singhe678cb72020-04-14 16:23:30 -0700266 int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
267 LogEvent event2(/*uid=*/0, /*pid=*/0);
268 makeLogEvent(&event2, endTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800269 durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
270 buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
271 EXPECT_EQ(3UL, buckets.size());
Tej Singhe678cb72020-04-14 16:23:30 -0700272 EXPECT_EQ(partialBucketSplitTimeNs, buckets[1].mBucketStartNs);
tsaichristine7747d372020-02-28 17:36:59 -0800273 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
Tej Singhe678cb72020-04-14 16:23:30 -0700274 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - partialBucketSplitTimeNs, buckets[1].mDuration);
tsaichristine7747d372020-02-28 17:36:59 -0800275 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
276 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
277 EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
278}
279
Tej Singhe678cb72020-04-14 16:23:30 -0700280TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationWithSplitInFollowingBucket) {
tsaichristine7747d372020-02-28 17:36:59 -0800281 /**
282 * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
283 * - [10,70]: 59 secs
284 * - [70,75]: 5 sec
285 * - [75,130]: 55 secs
286 */
287 int64_t bucketStartTimeNs = 10000000000;
288 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
tsaichristine7747d372020-02-28 17:36:59 -0800289 int tagId = 1;
tsaichristine7747d372020-02-28 17:36:59 -0800290
291 DurationMetric metric;
292 metric.set_id(1);
293 metric.set_bucket(ONE_MINUTE);
294 metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
295 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
296 FieldMatcher dimensions;
297 DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
298 1 /* start index */, 2 /* stop index */,
299 3 /* stop_all index */, false /*nesting*/, wizard,
300 dimensions, bucketStartTimeNs, bucketStartTimeNs);
301
Tej Singhe678cb72020-04-14 16:23:30 -0700302 int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
303 LogEvent event1(/*uid=*/0, /*pid=*/0);
304 makeLogEvent(&event1, startTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800305 durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
306 EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
307 EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
308
Tej Singhe678cb72020-04-14 16:23:30 -0700309 int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
310 switch (GetParam()) {
311 case APP_UPGRADE:
312 durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
313 break;
314 case BOOT_COMPLETE:
315 durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
316 break;
317 }
tsaichristine7747d372020-02-28 17:36:59 -0800318 EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
319 std::vector<DurationBucket> buckets =
320 durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
321 EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
322 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
323 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
324 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
Tej Singhe678cb72020-04-14 16:23:30 -0700325 EXPECT_EQ(partialBucketSplitTimeNs, buckets[1].mBucketEndNs);
326 EXPECT_EQ(partialBucketSplitTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
327 EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
328 EXPECT_EQ(1, durationProducer.getCurrentBucketNum());
tsaichristine7747d372020-02-28 17:36:59 -0800329
330 // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
Tej Singhe678cb72020-04-14 16:23:30 -0700331 int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
332 LogEvent event2(/*uid=*/0, /*pid=*/0);
333 makeLogEvent(&event2, endTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800334 durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
335 buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
336 EXPECT_EQ(3UL, buckets.size());
Tej Singhe678cb72020-04-14 16:23:30 -0700337 EXPECT_EQ(partialBucketSplitTimeNs, buckets[2].mBucketStartNs);
tsaichristine7747d372020-02-28 17:36:59 -0800338 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
Tej Singhe678cb72020-04-14 16:23:30 -0700339 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - partialBucketSplitTimeNs,
340 buckets[2].mDuration);
tsaichristine7747d372020-02-28 17:36:59 -0800341}
342
Tej Singhe678cb72020-04-14 16:23:30 -0700343TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationAnomaly) {
tsaichristine7747d372020-02-28 17:36:59 -0800344 sp<AlarmMonitor> alarmMonitor;
345 int64_t bucketStartTimeNs = 10000000000;
346 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
tsaichristine7747d372020-02-28 17:36:59 -0800347 int tagId = 1;
tsaichristine7747d372020-02-28 17:36:59 -0800348
349 // Setup metric with alert.
350 DurationMetric metric;
351 metric.set_id(1);
352 metric.set_bucket(ONE_MINUTE);
353 metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
354 Alert alert;
355 alert.set_num_buckets(3);
356 alert.set_trigger_if_sum_gt(2);
357
358 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
359 FieldMatcher dimensions;
360 DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
361 1 /* start index */, 2 /* stop index */,
362 3 /* stop_all index */, false /*nesting*/, wizard,
363 dimensions, bucketStartTimeNs, bucketStartTimeNs);
364
365 sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
366 EXPECT_TRUE(anomalyTracker != nullptr);
367
Tej Singhe678cb72020-04-14 16:23:30 -0700368 int64_t startTimeNs = bucketStartTimeNs + 1;
369 LogEvent event1(/*uid=*/0, /*pid=*/0);
370 makeLogEvent(&event1, startTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800371 durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
Tej Singhe678cb72020-04-14 16:23:30 -0700372
373 int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
374 switch (GetParam()) {
375 case APP_UPGRADE:
376 durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
377 break;
378 case BOOT_COMPLETE:
379 durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
380 break;
381 }
tsaichristine7747d372020-02-28 17:36:59 -0800382
383 // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
Tej Singhe678cb72020-04-14 16:23:30 -0700384 int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
385 LogEvent event2(/*uid=*/0, /*pid=*/0);
386 makeLogEvent(&event2, endTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800387 durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
Tej Singhe678cb72020-04-14 16:23:30 -0700388
tsaichristine7747d372020-02-28 17:36:59 -0800389 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
390 anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
391}
392
Tej Singhe678cb72020-04-14 16:23:30 -0700393TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDuration) {
tsaichristine7747d372020-02-28 17:36:59 -0800394 int64_t bucketStartTimeNs = 10000000000;
395 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
tsaichristine7747d372020-02-28 17:36:59 -0800396 int tagId = 1;
tsaichristine7747d372020-02-28 17:36:59 -0800397
398 DurationMetric metric;
399 metric.set_id(1);
400 metric.set_bucket(ONE_MINUTE);
401 metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
402
403 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
404 FieldMatcher dimensions;
405 DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
406 1 /* start index */, 2 /* stop index */,
407 3 /* stop_all index */, false /*nesting*/, wizard,
408 dimensions, bucketStartTimeNs, bucketStartTimeNs);
409
Tej Singhe678cb72020-04-14 16:23:30 -0700410 int64_t startTimeNs = bucketStartTimeNs + 1;
411 LogEvent event1(/*uid=*/0, /*pid=*/0);
412 makeLogEvent(&event1, startTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800413 durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
414 EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
415 EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
416
Tej Singhe678cb72020-04-14 16:23:30 -0700417 int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
418 switch (GetParam()) {
419 case APP_UPGRADE:
420 durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
421 break;
422 case BOOT_COMPLETE:
423 durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
424 break;
425 }
tsaichristine7747d372020-02-28 17:36:59 -0800426 EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700427 EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
428 EXPECT_EQ(0, durationProducer.getCurrentBucketNum());
tsaichristine7747d372020-02-28 17:36:59 -0800429
430 // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
Tej Singhe678cb72020-04-14 16:23:30 -0700431 int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
432 LogEvent event2(/*uid=*/0, /*pid=*/0);
433 makeLogEvent(&event2, endTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800434 durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
435 EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
436
437 durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
438 std::vector<DurationBucket> buckets =
439 durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
440 EXPECT_EQ(1UL, buckets.size());
441 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
442 EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
443 EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
444}
445
Tej Singhe678cb72020-04-14 16:23:30 -0700446TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextBucket) {
tsaichristine7747d372020-02-28 17:36:59 -0800447 int64_t bucketStartTimeNs = 10000000000;
448 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
tsaichristine7747d372020-02-28 17:36:59 -0800449 int tagId = 1;
tsaichristine7747d372020-02-28 17:36:59 -0800450
451 DurationMetric metric;
452 metric.set_id(1);
453 metric.set_bucket(ONE_MINUTE);
454 metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
455
456 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
457 FieldMatcher dimensions;
458 DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
459 1 /* start index */, 2 /* stop index */,
460 3 /* stop_all index */, false /*nesting*/, wizard,
461 dimensions, bucketStartTimeNs, bucketStartTimeNs);
462
Tej Singhe678cb72020-04-14 16:23:30 -0700463 int64_t startTimeNs = bucketStartTimeNs + 1;
464 LogEvent event1(/*uid=*/0, /*pid=*/0);
465 makeLogEvent(&event1, startTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800466 durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
467 EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
468 EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
469
Tej Singhe678cb72020-04-14 16:23:30 -0700470 int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
471 switch (GetParam()) {
472 case APP_UPGRADE:
473 durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
474 break;
475 case BOOT_COMPLETE:
476 durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
477 break;
478 }
tsaichristine7747d372020-02-28 17:36:59 -0800479 EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700480 EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
481 EXPECT_EQ(1, durationProducer.getCurrentBucketNum());
tsaichristine7747d372020-02-28 17:36:59 -0800482
483 // Stop occurs in the same partial bucket as created for the app upgrade.
Tej Singhe678cb72020-04-14 16:23:30 -0700484 int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
485 LogEvent event2(/*uid=*/0, /*pid=*/0);
486 makeLogEvent(&event2, endTimeNs, tagId);
tsaichristine7747d372020-02-28 17:36:59 -0800487 durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
488 EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700489 EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
tsaichristine7747d372020-02-28 17:36:59 -0800490
491 durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
492 std::vector<DurationBucket> buckets =
493 durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
494 EXPECT_EQ(1UL, buckets.size());
Tej Singhe678cb72020-04-14 16:23:30 -0700495 EXPECT_EQ(partialBucketSplitTimeNs, buckets[0].mBucketStartNs);
tsaichristine7747d372020-02-28 17:36:59 -0800496 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
497 EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
498}
David Chen27785a82018-01-19 17:06:45 -0800499
Yangsterf2bee6f2017-11-29 12:01:05 -0800500} // namespace statsd
501} // namespace os
502} // namespace android
503#else
504GTEST_LOG_(INFO) << "This test does nothing.\n";
505#endif