blob: c39151313c55616471f4a891cf7a234eafeaa01b [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"
Yangster-mac20877162017-12-22 17:19:39 -080016#include "src/dimension.h"
Yangster-macb8144812018-01-04 10:56:23 -080017#include "src/stats_log_util.h"
Yao Chend5aa01b32017-12-19 16:46:36 -080018#include "metrics_test_helper.h"
Yangster-mac94e197c2018-01-02 16:03:03 -080019#include "tests/statsd_test_util.h"
Yao Chen93fe3a32017-11-02 13:52:59 -070020
21#include <gmock/gmock.h>
22#include <gtest/gtest.h>
23#include <stdio.h>
24#include <vector>
25
26using namespace testing;
27using android::sp;
28using std::set;
29using std::unordered_map;
30using std::vector;
31
32#ifdef __ANDROID__
33
34namespace android {
35namespace os {
36namespace statsd {
37
Yangster-mac94e197c2018-01-02 16:03:03 -080038const ConfigKey kConfigKey(0, 12345);
Yao Chenb3561512017-11-21 18:07:17 -080039
Yao Chen93fe3a32017-11-02 13:52:59 -070040TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
41 int64_t bucketStartTimeNs = 10000000000;
Yangster-macb8144812018-01-04 10:56:23 -080042 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
Yao Chen93fe3a32017-11-02 13:52:59 -070043 int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
44 int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
45 int tagId = 1;
46
47 CountMetric metric;
Yangster-mac94e197c2018-01-02 16:03:03 -080048 metric.set_id(1);
Yangster-macb8144812018-01-04 10:56:23 -080049 metric.set_bucket(ONE_MINUTE);
Yao Chen93fe3a32017-11-02 13:52:59 -070050
51 LogEvent event1(tagId, bucketStartTimeNs + 1);
52 LogEvent event2(tagId, bucketStartTimeNs + 2);
53
54 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
55
Yao Chenb3561512017-11-21 18:07:17 -080056 CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
Yao Chen93fe3a32017-11-02 13:52:59 -070057 bucketStartTimeNs);
58
59 // 2 events in bucket 1.
Chenjie Yua7259ab2017-12-10 08:31:05 -080060 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
61 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
Yangster-mace2cd6d52017-11-09 20:38:30 -080062
63 // Flushes at event #2.
Yangsterf2bee6f2017-11-29 12:01:05 -080064 countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
Yangster-mace2cd6d52017-11-09 20:38:30 -080065 EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
66
67 // Flushes.
Yangsterf2bee6f2017-11-29 12:01:05 -080068 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -070069 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
70 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
71 countProducer.mPastBuckets.end());
72 const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
73 EXPECT_EQ(1UL, buckets.size());
Yangster-mace2cd6d52017-11-09 20:38:30 -080074 EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
75 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
76 EXPECT_EQ(2LL, buckets[0].mCount);
Yao Chen93fe3a32017-11-02 13:52:59 -070077
78 // 1 matched event happens in bucket 2.
79 LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
Chenjie Yua7259ab2017-12-10 08:31:05 -080080 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
Yangsterf2bee6f2017-11-29 12:01:05 -080081 countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -070082 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
83 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
84 countProducer.mPastBuckets.end());
85 EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY].size());
86 const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY][1];
87 EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
88 EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
89 EXPECT_EQ(1LL, bucketInfo2.mCount);
90
91 // nothing happens in bucket 3. we should not record anything for bucket 3.
Yangsterf2bee6f2017-11-29 12:01:05 -080092 countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -070093 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
94 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
95 countProducer.mPastBuckets.end());
96 const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
97 EXPECT_EQ(2UL, buckets3.size());
98}
99
100TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
101 int64_t bucketStartTimeNs = 10000000000;
Yangster-macb8144812018-01-04 10:56:23 -0800102 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
Yao Chen93fe3a32017-11-02 13:52:59 -0700103
104 CountMetric metric;
Yangster-mac94e197c2018-01-02 16:03:03 -0800105 metric.set_id(1);
Yangster-macb8144812018-01-04 10:56:23 -0800106 metric.set_bucket(ONE_MINUTE);
Yangster-mac94e197c2018-01-02 16:03:03 -0800107 metric.set_condition(StringToId("SCREEN_ON"));
Yao Chen93fe3a32017-11-02 13:52:59 -0700108
109 LogEvent event1(1, bucketStartTimeNs + 1);
110 LogEvent event2(1, bucketStartTimeNs + 10);
111
112 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
113
Yao Chenb3561512017-11-21 18:07:17 -0800114 CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
Yao Chen93fe3a32017-11-02 13:52:59 -0700115
116 countProducer.onConditionChanged(true, bucketStartTimeNs);
Chenjie Yua7259ab2017-12-10 08:31:05 -0800117 countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
Yao Chen93fe3a32017-11-02 13:52:59 -0700118 EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
119
120 countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800121 // Upon this match event, the matched event1 is flushed.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800122 countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
Yao Chen93fe3a32017-11-02 13:52:59 -0700123 EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
124
Yangsterf2bee6f2017-11-29 12:01:05 -0800125 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -0700126 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
127 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
128 countProducer.mPastBuckets.end());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800129 {
130 const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
131 EXPECT_EQ(1UL, buckets.size());
132 const auto& bucketInfo = buckets[0];
133 EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
134 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
135 EXPECT_EQ(1LL, bucketInfo.mCount);
136 }
Yao Chen93fe3a32017-11-02 13:52:59 -0700137}
138
139TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
140 int64_t bucketStartTimeNs = 10000000000;
Yangster-macb8144812018-01-04 10:56:23 -0800141 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
Yao Chen93fe3a32017-11-02 13:52:59 -0700142
Yangster-mac20877162017-12-22 17:19:39 -0800143 int tagId = 1;
144 int conditionTagId = 2;
145
Yao Chen93fe3a32017-11-02 13:52:59 -0700146 CountMetric metric;
Yangster-mac94e197c2018-01-02 16:03:03 -0800147 metric.set_id(1);
Yangster-macb8144812018-01-04 10:56:23 -0800148 metric.set_bucket(ONE_MINUTE);
Yangster-mac94e197c2018-01-02 16:03:03 -0800149 metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
Stefan Lafona5b51912017-12-05 21:43:52 -0800150 MetricConditionLink* link = metric.add_links();
Yangster-mac94e197c2018-01-02 16:03:03 -0800151 link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
Yangster-mac20877162017-12-22 17:19:39 -0800152 *link->mutable_dimensions_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
153 *link->mutable_dimensions_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
Yao Chen93fe3a32017-11-02 13:52:59 -0700154
Yangster-mac20877162017-12-22 17:19:39 -0800155 LogEvent event1(tagId, bucketStartTimeNs + 1);
Yao Chen80235402017-11-13 20:42:25 -0800156 event1.write("111"); // uid
Yao Chen93fe3a32017-11-02 13:52:59 -0700157 event1.init();
158 ConditionKey key1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800159 key1[StringToId("APP_IN_BACKGROUND_PER_UID")] =
160 {getMockedDimensionKey(conditionTagId, 2, "111")};
Yao Chen93fe3a32017-11-02 13:52:59 -0700161
Yangster-mac20877162017-12-22 17:19:39 -0800162 LogEvent event2(tagId, bucketStartTimeNs + 10);
Yao Chen80235402017-11-13 20:42:25 -0800163 event2.write("222"); // uid
Yao Chen93fe3a32017-11-02 13:52:59 -0700164 event2.init();
165 ConditionKey key2;
Yangster-mac94e197c2018-01-02 16:03:03 -0800166 key2[StringToId("APP_IN_BACKGROUND_PER_UID")] =
167 {getMockedDimensionKey(conditionTagId, 2, "222")};
Yao Chen93fe3a32017-11-02 13:52:59 -0700168
169 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
170 EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
171
172 EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue));
173
Yao Chenb3561512017-11-21 18:07:17 -0800174 CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
Yao Chen93fe3a32017-11-02 13:52:59 -0700175 bucketStartTimeNs);
176
Chenjie Yua7259ab2017-12-10 08:31:05 -0800177 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
Yangsterf2bee6f2017-11-29 12:01:05 -0800178 countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800179 EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
180
Chenjie Yua7259ab2017-12-10 08:31:05 -0800181 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
Yangsterf2bee6f2017-11-29 12:01:05 -0800182 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -0700183 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
184 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
185 countProducer.mPastBuckets.end());
186 const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
187 EXPECT_EQ(1UL, buckets.size());
188 const auto& bucketInfo = buckets[0];
189 EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
190 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
191 EXPECT_EQ(1LL, bucketInfo.mCount);
192}
193
Bookatz1bf94382018-01-04 11:43:20 -0800194TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800195 Alert alert;
Yangster-mac94e197c2018-01-02 16:03:03 -0800196 alert.set_id(11);
197 alert.set_metric_id(1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800198 alert.set_trigger_if_sum_gt(2);
Yangster-maca7fb12d2018-01-03 17:17:20 -0800199 alert.set_num_buckets(2);
Bookatz1bf94382018-01-04 11:43:20 -0800200 const int32_t refPeriodSec = 1;
201 alert.set_refractory_period_secs(refPeriodSec);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800202
203 int64_t bucketStartTimeNs = 10000000000;
Yangster-macb8144812018-01-04 10:56:23 -0800204 int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800205 int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
206 int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
207
Yangster-mace2cd6d52017-11-09 20:38:30 -0800208 CountMetric metric;
Yangster-mac94e197c2018-01-02 16:03:03 -0800209 metric.set_id(1);
Yangster-macb8144812018-01-04 10:56:23 -0800210 metric.set_bucket(ONE_MINUTE);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800211
212 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
Yao Chenb3561512017-11-21 18:07:17 -0800213 CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
Yangster-mace2cd6d52017-11-09 20:38:30 -0800214 bucketStartTimeNs);
Bookatz857aaa52017-12-19 15:29:06 -0800215 sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800216
217 int tagId = 1;
218 LogEvent event1(tagId, bucketStartTimeNs + 1);
219 LogEvent event2(tagId, bucketStartTimeNs + 2);
220 LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1);
221 LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
222 LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
223 LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
Bookatz1bf94382018-01-04 11:43:20 -0800224 LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800225
226 // Two events in bucket #0.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800227 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
228 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800229
230 EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
231 EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
Bookatz1bf94382018-01-04 11:43:20 -0800232 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY), 0U);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800233
234 // One event in bucket #2. No alarm as bucket #0 is trashed out.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800235 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800236 EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
237 EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
Bookatz1bf94382018-01-04 11:43:20 -0800238 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY), 0U);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800239
240 // Two events in bucket #3.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800241 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
242 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
243 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800244 EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
245 EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
246 // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
Bookatz1bf94382018-01-04 11:43:20 -0800247 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
248 event5.GetTimestampNs() / NS_PER_SEC + refPeriodSec);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800249
Chenjie Yua7259ab2017-12-10 08:31:05 -0800250 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800251 EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
252 EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
Bookatz1bf94382018-01-04 11:43:20 -0800253 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_DIMENSION_KEY),
254 event7.GetTimestampNs() / NS_PER_SEC + refPeriodSec);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800255}
256
Yao Chen93fe3a32017-11-02 13:52:59 -0700257} // namespace statsd
258} // namespace os
259} // namespace android
260#else
261GTEST_LOG_(INFO) << "This test does nothing.\n";
262#endif