blob: 74ecaac0f9e35c222b318c6f3bd0e30b63f00370 [file] [log] [blame]
Yao Chen93fe3a32017-11-02 13:52:59 -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 Chen93fe3a32017-11-02 13:52:59 -070015#include "src/metrics/CountMetricProducer.h"
16
17#include <gmock/gmock.h>
18#include <gtest/gtest.h>
Bookatz6bf98252018-03-14 10:44:24 -070019#include <math.h>
Yao Chen93fe3a32017-11-02 13:52:59 -070020#include <stdio.h>
tsaichristine7747d372020-02-28 17:36:59 -080021
Yao Chen93fe3a32017-11-02 13:52:59 -070022#include <vector>
23
tsaichristine7747d372020-02-28 17:36:59 -080024#include "metrics_test_helper.h"
25#include "src/stats_log_util.h"
26#include "stats_event.h"
27#include "tests/statsd_test_util.h"
28
Yao Chen93fe3a32017-11-02 13:52:59 -070029using namespace testing;
30using android::sp;
31using std::set;
32using std::unordered_map;
33using std::vector;
34
35#ifdef __ANDROID__
36
37namespace android {
38namespace os {
39namespace statsd {
40
Yao Chenb3561512017-11-21 18:07:17 -080041
tsaichristine7747d372020-02-28 17:36:59 -080042namespace {
Tej Singhe678cb72020-04-14 16:23:30 -070043const ConfigKey kConfigKey(0, 12345);
tsaichristine7747d372020-02-28 17:36:59 -080044
45void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
46 AStatsEvent* statsEvent = AStatsEvent_obtain();
47 AStatsEvent_setAtomId(statsEvent, atomId);
48 AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
tsaichristine7747d372020-02-28 17:36:59 -080049
tsaichristine8dca82e2020-04-07 09:40:03 -070050 parseStatsEventToLogEvent(statsEvent, logEvent);
tsaichristine7747d372020-02-28 17:36:59 -080051}
52
53void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId, string uid) {
54 AStatsEvent* statsEvent = AStatsEvent_obtain();
55 AStatsEvent_setAtomId(statsEvent, atomId);
56 AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
tsaichristine7747d372020-02-28 17:36:59 -080057 AStatsEvent_writeString(statsEvent, uid.c_str());
tsaichristine7747d372020-02-28 17:36:59 -080058
tsaichristine8dca82e2020-04-07 09:40:03 -070059 parseStatsEventToLogEvent(statsEvent, logEvent);
tsaichristine7747d372020-02-28 17:36:59 -080060}
61
62} // namespace
63
Tej Singhe678cb72020-04-14 16:23:30 -070064// Setup for parameterized tests.
65class CountMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
66
67INSTANTIATE_TEST_SUITE_P(CountMetricProducerTest_PartialBucket,
68 CountMetricProducerTest_PartialBucket,
69 testing::Values(APP_UPGRADE, BOOT_COMPLETE));
70
tsaichristine7747d372020-02-28 17:36:59 -080071TEST(CountMetricProducerTest, TestFirstBucket) {
72 CountMetric metric;
73 metric.set_id(1);
74 metric.set_bucket(ONE_MINUTE);
75 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
76
77 CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5,
78 600 * NS_PER_SEC + NS_PER_SEC / 2);
79 EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
80 EXPECT_EQ(10, countProducer.mCurrentBucketNum);
81 EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
82}
83
84TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
85 int64_t bucketStartTimeNs = 10000000000;
86 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
87 int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
88 int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
89 int tagId = 1;
90
91 CountMetric metric;
92 metric.set_id(1);
93 metric.set_bucket(ONE_MINUTE);
94
95 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
96
97 CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
98 bucketStartTimeNs, bucketStartTimeNs);
99
100 // 2 events in bucket 1.
101 LogEvent event1(/*uid=*/0, /*pid=*/0);
102 makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
103 LogEvent event2(/*uid=*/0, /*pid=*/0);
104 makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
105
106 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
107 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
108
109 // Flushes at event #2.
110 countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700111 ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800112
113 // Flushes.
114 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700115 ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800116 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
117 countProducer.mPastBuckets.end());
118 const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700119 ASSERT_EQ(1UL, buckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800120 EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
121 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
122 EXPECT_EQ(2LL, buckets[0].mCount);
123
124 // 1 matched event happens in bucket 2.
125 LogEvent event3(/*uid=*/0, /*pid=*/0);
126 makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 2, tagId);
127
128 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
129
130 countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700131 ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800132 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
133 countProducer.mPastBuckets.end());
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700134 ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
tsaichristine7747d372020-02-28 17:36:59 -0800135 const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
136 EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
137 EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
138 EXPECT_EQ(1LL, bucketInfo2.mCount);
139
140 // nothing happens in bucket 3. we should not record anything for bucket 3.
141 countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700142 ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800143 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
144 countProducer.mPastBuckets.end());
145 const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700146 ASSERT_EQ(2UL, buckets3.size());
tsaichristine7747d372020-02-28 17:36:59 -0800147}
148
149TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
150 int64_t bucketStartTimeNs = 10000000000;
151 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
152
153 CountMetric metric;
154 metric.set_id(1);
155 metric.set_bucket(ONE_MINUTE);
156 metric.set_condition(StringToId("SCREEN_ON"));
157
158 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
159
160 CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs,
161 bucketStartTimeNs);
162
163 countProducer.onConditionChanged(true, bucketStartTimeNs);
164
165 LogEvent event1(/*uid=*/0, /*pid=*/0);
166 makeLogEvent(&event1, bucketStartTimeNs + 1, /*atomId=*/1);
167 countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
168
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700169 ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800170
171 countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
172
173 // Upon this match event, the matched event1 is flushed.
174 LogEvent event2(/*uid=*/0, /*pid=*/0);
175 makeLogEvent(&event2, bucketStartTimeNs + 10, /*atomId=*/1);
176 countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700177 ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800178
179 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700180 ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800181 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
182 countProducer.mPastBuckets.end());
183
184 const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700185 ASSERT_EQ(1UL, buckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800186 const auto& bucketInfo = buckets[0];
187 EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
188 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
189 EXPECT_EQ(1LL, bucketInfo.mCount);
190}
191
192TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
193 int64_t bucketStartTimeNs = 10000000000;
194 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
195
196 int tagId = 1;
197 int conditionTagId = 2;
198
199 CountMetric metric;
200 metric.set_id(1);
201 metric.set_bucket(ONE_MINUTE);
202 metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
203 MetricConditionLink* link = metric.add_links();
204 link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
205 buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
206 buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
207
208 LogEvent event1(/*uid=*/0, /*pid=*/0);
209 makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
210
211 LogEvent event2(/*uid=*/0, /*pid=*/0);
212 makeLogEvent(&event2, bucketStartTimeNs + 10, tagId, /*uid=*/"222");
213
214 ConditionKey key1;
215 key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
216 getMockedDimensionKey(conditionTagId, 2, "111")};
217
218 ConditionKey key2;
219 key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
220 getMockedDimensionKey(conditionTagId, 2, "222")};
221
222 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
223 EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
224
225 EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
226
227 CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
228 bucketStartTimeNs, bucketStartTimeNs);
229
230 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
231 countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700232 ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800233
234 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
235 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700236 ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800237 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
238 countProducer.mPastBuckets.end());
239 const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700240 ASSERT_EQ(1UL, buckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800241 const auto& bucketInfo = buckets[0];
242 EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
243 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
244 EXPECT_EQ(1LL, bucketInfo.mCount);
245}
246
Tej Singhe678cb72020-04-14 16:23:30 -0700247TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInCurrentBucket) {
tsaichristine7747d372020-02-28 17:36:59 -0800248 sp<AlarmMonitor> alarmMonitor;
249 int64_t bucketStartTimeNs = 10000000000;
250 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
Tej Singhe678cb72020-04-14 16:23:30 -0700251 int64_t eventTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
tsaichristine7747d372020-02-28 17:36:59 -0800252
253 int tagId = 1;
254 int conditionTagId = 2;
255
256 CountMetric metric;
257 metric.set_id(1);
258 metric.set_bucket(ONE_MINUTE);
259 Alert alert;
260 alert.set_num_buckets(3);
261 alert.set_trigger_if_sum_gt(2);
262
263 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
264 CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
265 bucketStartTimeNs, bucketStartTimeNs);
266
267 sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
268 EXPECT_TRUE(anomalyTracker != nullptr);
269
Tej Singhe678cb72020-04-14 16:23:30 -0700270 // Bucket is not flushed yet.
tsaichristine7747d372020-02-28 17:36:59 -0800271 LogEvent event1(/*uid=*/0, /*pid=*/0);
272 makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
273 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700274 ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800275 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
276
Tej Singhe678cb72020-04-14 16:23:30 -0700277 // App upgrade or boot complete forces bucket flush.
tsaichristine7747d372020-02-28 17:36:59 -0800278 // Check that there's a past bucket and the bucket end is not adjusted.
Tej Singhe678cb72020-04-14 16:23:30 -0700279 switch (GetParam()) {
280 case APP_UPGRADE:
281 countProducer.notifyAppUpgrade(eventTimeNs);
282 break;
283 case BOOT_COMPLETE:
284 countProducer.onStatsdInitCompleted(eventTimeNs);
285 break;
286 }
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700287 ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700288 EXPECT_EQ(bucketStartTimeNs,
tsaichristine7747d372020-02-28 17:36:59 -0800289 countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
Tej Singhe678cb72020-04-14 16:23:30 -0700290 EXPECT_EQ(eventTimeNs,
tsaichristine7747d372020-02-28 17:36:59 -0800291 countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
Tej Singhe678cb72020-04-14 16:23:30 -0700292 EXPECT_EQ(0, countProducer.getCurrentBucketNum());
293 EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
tsaichristine7747d372020-02-28 17:36:59 -0800294 // Anomaly tracker only contains full buckets.
295 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
296
297 int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
298 // Next event occurs in same bucket as partial bucket created.
299 LogEvent event2(/*uid=*/0, /*pid=*/0);
300 makeLogEvent(&event2, bucketStartTimeNs + 59 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
301 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700302 ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700303 EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
304 EXPECT_EQ(0, countProducer.getCurrentBucketNum());
tsaichristine7747d372020-02-28 17:36:59 -0800305 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
306
307 // Third event in following bucket.
308 LogEvent event3(/*uid=*/0, /*pid=*/0);
309 makeLogEvent(&event3, bucketStartTimeNs + 62 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
310 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700311 ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
tsaichristine7747d372020-02-28 17:36:59 -0800312 EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
Tej Singhe678cb72020-04-14 16:23:30 -0700313 EXPECT_EQ(1, countProducer.getCurrentBucketNum());
tsaichristine7747d372020-02-28 17:36:59 -0800314 EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
315}
316
Tej Singhe678cb72020-04-14 16:23:30 -0700317TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInNextBucket) {
tsaichristine7747d372020-02-28 17:36:59 -0800318 int64_t bucketStartTimeNs = 10000000000;
319 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
Tej Singhe678cb72020-04-14 16:23:30 -0700320 int64_t eventTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
tsaichristine7747d372020-02-28 17:36:59 -0800321
322 int tagId = 1;
323 int conditionTagId = 2;
324
325 CountMetric metric;
326 metric.set_id(1);
327 metric.set_bucket(ONE_MINUTE);
328
329 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
330 CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
331 bucketStartTimeNs, bucketStartTimeNs);
332
333 // Bucket is flushed yet.
334 LogEvent event1(/*uid=*/0, /*pid=*/0);
335 makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
336 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700337 ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
tsaichristine7747d372020-02-28 17:36:59 -0800338
Tej Singhe678cb72020-04-14 16:23:30 -0700339 // App upgrade or boot complete forces bucket flush.
340 // Check that there's a past bucket and the bucket end is not adjusted since the upgrade
341 // occurred after the bucket end time.
342 switch (GetParam()) {
343 case APP_UPGRADE:
344 countProducer.notifyAppUpgrade(eventTimeNs);
345 break;
346 case BOOT_COMPLETE:
347 countProducer.onStatsdInitCompleted(eventTimeNs);
348 break;
349 }
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700350 ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700351 EXPECT_EQ(bucketStartTimeNs,
tsaichristine7747d372020-02-28 17:36:59 -0800352 countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
353 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
354 countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
Tej Singhe678cb72020-04-14 16:23:30 -0700355 EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
tsaichristine7747d372020-02-28 17:36:59 -0800356
357 // Next event occurs in same bucket as partial bucket created.
358 LogEvent event2(/*uid=*/0, /*pid=*/0);
359 makeLogEvent(&event2, bucketStartTimeNs + 70 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
360 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700361 ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
tsaichristine7747d372020-02-28 17:36:59 -0800362
363 // Third event in following bucket.
364 LogEvent event3(/*uid=*/0, /*pid=*/0);
365 makeLogEvent(&event3, bucketStartTimeNs + 121 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
366 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700367 ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700368 EXPECT_EQ((int64_t)eventTimeNs,
tsaichristine7747d372020-02-28 17:36:59 -0800369 countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
370 EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
371 countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
372}
373
374TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
375 sp<AlarmMonitor> alarmMonitor;
376 Alert alert;
377 alert.set_id(11);
378 alert.set_metric_id(1);
379 alert.set_trigger_if_sum_gt(2);
380 alert.set_num_buckets(2);
381 const int32_t refPeriodSec = 1;
382 alert.set_refractory_period_secs(refPeriodSec);
383
384 int64_t bucketStartTimeNs = 10000000000;
385 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
386 int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
387 int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
388
389 CountMetric metric;
390 metric.set_id(1);
391 metric.set_bucket(ONE_MINUTE);
392
393 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
394 CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
395 bucketStartTimeNs, bucketStartTimeNs);
396
397 sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
398
399 int tagId = 1;
400 LogEvent event1(/*uid=*/0, /*pid=*/0);
401 makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
402 LogEvent event2(/*uid=*/0, /*pid=*/0);
403 makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
404 LogEvent event3(/*uid=*/0, /*pid=*/0);
405 makeLogEvent(&event3, bucketStartTimeNs + 2 * bucketSizeNs + 1, tagId);
406 LogEvent event4(/*uid=*/0, /*pid=*/0);
407 makeLogEvent(&event4, bucketStartTimeNs + 3 * bucketSizeNs + 1, tagId);
408 LogEvent event5(/*uid=*/0, /*pid=*/0);
409 makeLogEvent(&event5, bucketStartTimeNs + 3 * bucketSizeNs + 2, tagId);
410 LogEvent event6(/*uid=*/0, /*pid=*/0);
411 makeLogEvent(&event6, bucketStartTimeNs + 3 * bucketSizeNs + 3, tagId);
412 LogEvent event7(/*uid=*/0, /*pid=*/0);
413 makeLogEvent(&event7, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, tagId);
414
415 // Two events in bucket #0.
416 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
417 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
418
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700419 ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
tsaichristine7747d372020-02-28 17:36:59 -0800420 EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
421 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
422
423 // One event in bucket #2. No alarm as bucket #0 is trashed out.
424 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700425 ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
tsaichristine7747d372020-02-28 17:36:59 -0800426 EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
427 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
428
429 // Two events in bucket #3.
430 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
431 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
432 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700433 ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
tsaichristine7747d372020-02-28 17:36:59 -0800434 EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
435 // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
436 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
437 std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
438
439 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700440 ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
tsaichristine7747d372020-02-28 17:36:59 -0800441 EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
442 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
443 std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
444}
Yangster-mace2cd6d52017-11-09 20:38:30 -0800445
Ruchir Rastogi060fbfc2019-10-11 13:16:51 -0700446TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
447 CountMetric metric;
448 metric.set_id(1);
449 metric.set_bucket(ONE_WEEK);
450
451 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
452
453 int64_t oneDayNs = 24 * 60 * 60 * 1e9;
454 int64_t fiveWeeksNs = 5 * 7 * oneDayNs;
455
456 CountMetricProducer countProducer(
457 kConfigKey, metric, -1 /* meaning no condition */, wizard, oneDayNs, fiveWeeksNs);
458
459 int64_t fiveWeeksOneDayNs = fiveWeeksNs + oneDayNs;
460
461 EXPECT_EQ(fiveWeeksNs, countProducer.mCurrentBucketStartTimeNs);
462 EXPECT_EQ(4, countProducer.mCurrentBucketNum);
463 EXPECT_EQ(fiveWeeksOneDayNs, countProducer.getCurrentBucketEndTimeNs());
464}
465
Yao Chen93fe3a32017-11-02 13:52:59 -0700466} // namespace statsd
467} // namespace os
468} // namespace android
469#else
470GTEST_LOG_(INFO) << "This test does nothing.\n";
471#endif