• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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/CountMetricProducer.h"
16 
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 #include <math.h>
20 #include <stdio.h>
21 
22 #include <vector>
23 
24 #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 
29 using namespace testing;
30 using android::sp;
31 using std::set;
32 using std::unordered_map;
33 using std::vector;
34 
35 #ifdef __ANDROID__
36 
37 namespace android {
38 namespace os {
39 namespace statsd {
40 
41 
42 namespace {
43 const ConfigKey kConfigKey(0, 12345);
44 const uint64_t protoHash = 0x1234567890;
45 
makeLogEvent(LogEvent * logEvent,int64_t timestampNs,int atomId)46 void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
47     AStatsEvent* statsEvent = AStatsEvent_obtain();
48     AStatsEvent_setAtomId(statsEvent, atomId);
49     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
50 
51     parseStatsEventToLogEvent(statsEvent, logEvent);
52 }
53 
makeLogEvent(LogEvent * logEvent,int64_t timestampNs,int atomId,string uid)54 void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId, string uid) {
55     AStatsEvent* statsEvent = AStatsEvent_obtain();
56     AStatsEvent_setAtomId(statsEvent, atomId);
57     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
58     AStatsEvent_writeString(statsEvent, uid.c_str());
59 
60     parseStatsEventToLogEvent(statsEvent, logEvent);
61 }
62 
63 }  // namespace
64 
65 // Setup for parameterized tests.
66 class CountMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
67 
68 INSTANTIATE_TEST_SUITE_P(CountMetricProducerTest_PartialBucket,
69                          CountMetricProducerTest_PartialBucket,
70                          testing::Values(APP_UPGRADE, BOOT_COMPLETE));
71 
TEST(CountMetricProducerTest,TestFirstBucket)72 TEST(CountMetricProducerTest, TestFirstBucket) {
73     CountMetric metric;
74     metric.set_id(1);
75     metric.set_bucket(ONE_MINUTE);
76     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
77 
78     CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
79                                       wizard, protoHash, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
80     EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
81     EXPECT_EQ(10, countProducer.mCurrentBucketNum);
82     EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
83 }
84 
TEST(CountMetricProducerTest,TestNonDimensionalEvents)85 TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
86     int64_t bucketStartTimeNs = 10000000000;
87     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
88     int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
89     int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
90     int tagId = 1;
91 
92     CountMetric metric;
93     metric.set_id(1);
94     metric.set_bucket(ONE_MINUTE);
95 
96     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
97 
98     CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
99                                       wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs);
100 
101     // 2 events in bucket 1.
102     LogEvent event1(/*uid=*/0, /*pid=*/0);
103     makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
104     LogEvent event2(/*uid=*/0, /*pid=*/0);
105     makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
106 
107     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
108     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
109 
110     // Flushes at event #2.
111     countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
112     ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
113 
114     // Flushes.
115     countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
116     ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
117     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
118                 countProducer.mPastBuckets.end());
119     const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
120     ASSERT_EQ(1UL, buckets.size());
121     EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
122     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
123     EXPECT_EQ(2LL, buckets[0].mCount);
124 
125     // 1 matched event happens in bucket 2.
126     LogEvent event3(/*uid=*/0, /*pid=*/0);
127     makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 2, tagId);
128 
129     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
130 
131     countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
132     ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
133     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
134                 countProducer.mPastBuckets.end());
135     ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
136     const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
137     EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
138     EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
139     EXPECT_EQ(1LL, bucketInfo2.mCount);
140 
141     // nothing happens in bucket 3. we should not record anything for bucket 3.
142     countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
143     ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
144     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
145                 countProducer.mPastBuckets.end());
146     const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
147     ASSERT_EQ(2UL, buckets3.size());
148 }
149 
TEST(CountMetricProducerTest,TestEventsWithNonSlicedCondition)150 TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
151     int64_t bucketStartTimeNs = 10000000000;
152     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
153 
154     CountMetric metric;
155     metric.set_id(1);
156     metric.set_bucket(ONE_MINUTE);
157     metric.set_condition(StringToId("SCREEN_ON"));
158 
159     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
160 
161     CountMetricProducer countProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
162                                       protoHash, bucketStartTimeNs, bucketStartTimeNs);
163 
164     countProducer.onConditionChanged(true, bucketStartTimeNs);
165 
166     LogEvent event1(/*uid=*/0, /*pid=*/0);
167     makeLogEvent(&event1, bucketStartTimeNs + 1, /*atomId=*/1);
168     countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
169 
170     ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
171 
172     countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
173 
174     // Upon this match event, the matched event1 is flushed.
175     LogEvent event2(/*uid=*/0, /*pid=*/0);
176     makeLogEvent(&event2, bucketStartTimeNs + 10, /*atomId=*/1);
177     countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
178     ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
179 
180     countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
181     ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
182     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
183                 countProducer.mPastBuckets.end());
184 
185     const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
186     ASSERT_EQ(1UL, buckets.size());
187     const auto& bucketInfo = buckets[0];
188     EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
189     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
190     EXPECT_EQ(1LL, bucketInfo.mCount);
191 }
192 
TEST(CountMetricProducerTest,TestEventsWithSlicedCondition)193 TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
194     int64_t bucketStartTimeNs = 10000000000;
195     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
196 
197     int tagId = 1;
198     int conditionTagId = 2;
199 
200     CountMetric metric;
201     metric.set_id(1);
202     metric.set_bucket(ONE_MINUTE);
203     metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
204     MetricConditionLink* link = metric.add_links();
205     link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
206     buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
207     buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
208 
209     LogEvent event1(/*uid=*/0, /*pid=*/0);
210     makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
211 
212     LogEvent event2(/*uid=*/0, /*pid=*/0);
213     makeLogEvent(&event2, bucketStartTimeNs + 10, tagId, /*uid=*/"222");
214 
215     ConditionKey key1;
216     key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
217             getMockedDimensionKey(conditionTagId, 2, "111")};
218 
219     ConditionKey key2;
220     key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
221             getMockedDimensionKey(conditionTagId, 2, "222")};
222 
223     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
224 
225     EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
226 
227     EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
228 
229     CountMetricProducer countProducer(kConfigKey, metric, 0 /*condition tracker index*/,
230                                       {ConditionState::kUnknown}, wizard, protoHash,
231                                       bucketStartTimeNs, bucketStartTimeNs);
232 
233     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
234     countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
235     ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
236 
237     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
238     countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
239     ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
240     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
241                 countProducer.mPastBuckets.end());
242     const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
243     ASSERT_EQ(1UL, buckets.size());
244     const auto& bucketInfo = buckets[0];
245     EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
246     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
247     EXPECT_EQ(1LL, bucketInfo.mCount);
248 }
249 
TEST_P(CountMetricProducerTest_PartialBucket,TestSplitInCurrentBucket)250 TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInCurrentBucket) {
251     sp<AlarmMonitor> alarmMonitor;
252     int64_t bucketStartTimeNs = 10000000000;
253     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
254     int64_t eventTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
255 
256     int tagId = 1;
257     int conditionTagId = 2;
258 
259     CountMetric metric;
260     metric.set_id(1);
261     metric.set_bucket(ONE_MINUTE);
262     Alert alert;
263     alert.set_num_buckets(3);
264     alert.set_trigger_if_sum_gt(2);
265 
266     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
267 
268     CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
269                                       protoHash, bucketStartTimeNs, bucketStartTimeNs);
270 
271     sp<AnomalyTracker> anomalyTracker =
272             countProducer.addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
273     EXPECT_TRUE(anomalyTracker != nullptr);
274 
275     // Bucket is not flushed yet.
276     LogEvent event1(/*uid=*/0, /*pid=*/0);
277     makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
278     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
279     ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
280     EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
281 
282     // App upgrade or boot complete forces bucket flush.
283     // Check that there's a past bucket and the bucket end is not adjusted.
284     switch (GetParam()) {
285         case APP_UPGRADE:
286             countProducer.notifyAppUpgrade(eventTimeNs);
287             break;
288         case BOOT_COMPLETE:
289             countProducer.onStatsdInitCompleted(eventTimeNs);
290             break;
291     }
292     ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
293     EXPECT_EQ(bucketStartTimeNs,
294               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
295     EXPECT_EQ(eventTimeNs,
296               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
297     EXPECT_EQ(0, countProducer.getCurrentBucketNum());
298     EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
299     // Anomaly tracker only contains full buckets.
300     EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
301 
302     int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
303     // Next event occurs in same bucket as partial bucket created.
304     LogEvent event2(/*uid=*/0, /*pid=*/0);
305     makeLogEvent(&event2, bucketStartTimeNs + 59 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
306     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
307     ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
308     EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
309     EXPECT_EQ(0, countProducer.getCurrentBucketNum());
310     EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
311 
312     // Third event in following bucket.
313     LogEvent event3(/*uid=*/0, /*pid=*/0);
314     makeLogEvent(&event3, bucketStartTimeNs + 62 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
315     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
316     ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
317     EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
318     EXPECT_EQ(1, countProducer.getCurrentBucketNum());
319     EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
320 }
321 
TEST_P(CountMetricProducerTest_PartialBucket,TestSplitInNextBucket)322 TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInNextBucket) {
323     int64_t bucketStartTimeNs = 10000000000;
324     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
325     int64_t eventTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
326 
327     int tagId = 1;
328     int conditionTagId = 2;
329 
330     CountMetric metric;
331     metric.set_id(1);
332     metric.set_bucket(ONE_MINUTE);
333 
334     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
335 
336     CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
337                                       protoHash, bucketStartTimeNs, bucketStartTimeNs);
338 
339     // Bucket is flushed yet.
340     LogEvent event1(/*uid=*/0, /*pid=*/0);
341     makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
342     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
343     ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
344 
345     // App upgrade or boot complete forces bucket flush.
346     // Check that there's a past bucket and the bucket end is not adjusted since the upgrade
347     // occurred after the bucket end time.
348     switch (GetParam()) {
349         case APP_UPGRADE:
350             countProducer.notifyAppUpgrade(eventTimeNs);
351             break;
352         case BOOT_COMPLETE:
353             countProducer.onStatsdInitCompleted(eventTimeNs);
354             break;
355     }
356     ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
357     EXPECT_EQ(bucketStartTimeNs,
358               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
359     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
360               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
361     EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
362 
363     // Next event occurs in same bucket as partial bucket created.
364     LogEvent event2(/*uid=*/0, /*pid=*/0);
365     makeLogEvent(&event2, bucketStartTimeNs + 70 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
366     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
367     ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
368 
369     // Third event in following bucket.
370     LogEvent event3(/*uid=*/0, /*pid=*/0);
371     makeLogEvent(&event3, bucketStartTimeNs + 121 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
372     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
373     ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
374     EXPECT_EQ((int64_t)eventTimeNs,
375               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
376     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
377               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
378 }
379 
TEST(CountMetricProducerTest,TestAnomalyDetectionUnSliced)380 TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
381     sp<AlarmMonitor> alarmMonitor;
382     Alert alert;
383     alert.set_id(11);
384     alert.set_metric_id(1);
385     alert.set_trigger_if_sum_gt(2);
386     alert.set_num_buckets(2);
387     const int32_t refPeriodSec = 1;
388     alert.set_refractory_period_secs(refPeriodSec);
389 
390     int64_t bucketStartTimeNs = 10000000000;
391     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
392     int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
393     int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
394 
395     CountMetric metric;
396     metric.set_id(1);
397     metric.set_bucket(ONE_MINUTE);
398 
399     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
400 
401     CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
402                                       wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs);
403 
404     sp<AnomalyTracker> anomalyTracker =
405             countProducer.addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
406 
407     int tagId = 1;
408     LogEvent event1(/*uid=*/0, /*pid=*/0);
409     makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
410     LogEvent event2(/*uid=*/0, /*pid=*/0);
411     makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
412     LogEvent event3(/*uid=*/0, /*pid=*/0);
413     makeLogEvent(&event3, bucketStartTimeNs + 2 * bucketSizeNs + 1, tagId);
414     LogEvent event4(/*uid=*/0, /*pid=*/0);
415     makeLogEvent(&event4, bucketStartTimeNs + 3 * bucketSizeNs + 1, tagId);
416     LogEvent event5(/*uid=*/0, /*pid=*/0);
417     makeLogEvent(&event5, bucketStartTimeNs + 3 * bucketSizeNs + 2, tagId);
418     LogEvent event6(/*uid=*/0, /*pid=*/0);
419     makeLogEvent(&event6, bucketStartTimeNs + 3 * bucketSizeNs + 3, tagId);
420     LogEvent event7(/*uid=*/0, /*pid=*/0);
421     makeLogEvent(&event7, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, tagId);
422 
423     // Two events in bucket #0.
424     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
425     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
426 
427     ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
428     EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
429     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
430 
431     // One event in bucket #2. No alarm as bucket #0 is trashed out.
432     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
433     ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
434     EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
435     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
436 
437     // Two events in bucket #3.
438     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
439     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
440     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
441     ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
442     EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
443     // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
444     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
445               std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
446 
447     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
448     ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
449     EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
450     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
451               std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
452 }
453 
TEST(CountMetricProducerTest,TestOneWeekTimeUnit)454 TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
455     CountMetric metric;
456     metric.set_id(1);
457     metric.set_bucket(ONE_WEEK);
458 
459     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
460 
461     int64_t oneDayNs = 24 * 60 * 60 * 1e9;
462     int64_t fiveWeeksNs = 5 * 7 * oneDayNs;
463 
464     CountMetricProducer countProducer(kConfigKey, metric, -1 /* meaning no condition */, {}, wizard,
465                                       protoHash, oneDayNs, fiveWeeksNs);
466 
467     int64_t fiveWeeksOneDayNs = fiveWeeksNs + oneDayNs;
468 
469     EXPECT_EQ(fiveWeeksNs, countProducer.mCurrentBucketStartTimeNs);
470     EXPECT_EQ(4, countProducer.mCurrentBucketNum);
471     EXPECT_EQ(fiveWeeksOneDayNs, countProducer.getCurrentBucketEndTimeNs());
472 }
473 
474 }  // namespace statsd
475 }  // namespace os
476 }  // namespace android
477 #else
478 GTEST_LOG_(INFO) << "This test does nothing.\n";
479 #endif
480