blob: 6e114a628fef085041183cf71d0e422721e9db74 [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"
Yao Chend5aa01b32017-12-19 16:46:36 -080017#include "metrics_test_helper.h"
Yao Chen93fe3a32017-11-02 13:52:59 -070018
19#include <gmock/gmock.h>
20#include <gtest/gtest.h>
21#include <stdio.h>
22#include <vector>
23
24using namespace testing;
25using android::sp;
26using std::set;
27using std::unordered_map;
28using std::vector;
29
30#ifdef __ANDROID__
31
32namespace android {
33namespace os {
34namespace statsd {
35
Yao Chenb3561512017-11-21 18:07:17 -080036const ConfigKey kConfigKey(0, "test");
37
Yao Chen93fe3a32017-11-02 13:52:59 -070038TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
39 int64_t bucketStartTimeNs = 10000000000;
40 int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
41 int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
42 int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
43 int tagId = 1;
44
45 CountMetric metric;
Yangster-macd1815dc2017-11-13 21:43:15 -080046 metric.set_name("1");
Yao Chen93fe3a32017-11-02 13:52:59 -070047 metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
48
49 LogEvent event1(tagId, bucketStartTimeNs + 1);
50 LogEvent event2(tagId, bucketStartTimeNs + 2);
51
52 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
53
Yao Chenb3561512017-11-21 18:07:17 -080054 CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
Yao Chen93fe3a32017-11-02 13:52:59 -070055 bucketStartTimeNs);
56
57 // 2 events in bucket 1.
Chenjie Yua7259ab2017-12-10 08:31:05 -080058 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
59 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
Yangster-mace2cd6d52017-11-09 20:38:30 -080060
61 // Flushes at event #2.
Yangsterf2bee6f2017-11-29 12:01:05 -080062 countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
Yangster-mace2cd6d52017-11-09 20:38:30 -080063 EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
64
65 // Flushes.
Yangsterf2bee6f2017-11-29 12:01:05 -080066 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -070067 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
68 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
69 countProducer.mPastBuckets.end());
70 const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
71 EXPECT_EQ(1UL, buckets.size());
Yangster-mace2cd6d52017-11-09 20:38:30 -080072 EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
73 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
74 EXPECT_EQ(2LL, buckets[0].mCount);
Yao Chen93fe3a32017-11-02 13:52:59 -070075
76 // 1 matched event happens in bucket 2.
77 LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
Chenjie Yua7259ab2017-12-10 08:31:05 -080078 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
Yangsterf2bee6f2017-11-29 12:01:05 -080079 countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -070080 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
81 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
82 countProducer.mPastBuckets.end());
83 EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY].size());
84 const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY][1];
85 EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
86 EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
87 EXPECT_EQ(1LL, bucketInfo2.mCount);
88
89 // nothing happens in bucket 3. we should not record anything for bucket 3.
Yangsterf2bee6f2017-11-29 12:01:05 -080090 countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -070091 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
92 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
93 countProducer.mPastBuckets.end());
94 const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
95 EXPECT_EQ(2UL, buckets3.size());
96}
97
98TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
99 int64_t bucketStartTimeNs = 10000000000;
100 int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
101
102 CountMetric metric;
Yangster-macd1815dc2017-11-13 21:43:15 -0800103 metric.set_name("1");
Yao Chen93fe3a32017-11-02 13:52:59 -0700104 metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
105 metric.set_condition("SCREEN_ON");
106
107 LogEvent event1(1, bucketStartTimeNs + 1);
108 LogEvent event2(1, bucketStartTimeNs + 10);
109
110 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
111
Yao Chenb3561512017-11-21 18:07:17 -0800112 CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
Yao Chen93fe3a32017-11-02 13:52:59 -0700113
114 countProducer.onConditionChanged(true, bucketStartTimeNs);
Chenjie Yua7259ab2017-12-10 08:31:05 -0800115 countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
Yao Chen93fe3a32017-11-02 13:52:59 -0700116 EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
117
118 countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800119 // Upon this match event, the matched event1 is flushed.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800120 countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
Yao Chen93fe3a32017-11-02 13:52:59 -0700121 EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
122
Yangsterf2bee6f2017-11-29 12:01:05 -0800123 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -0700124 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
125 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
126 countProducer.mPastBuckets.end());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800127 {
128 const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
129 EXPECT_EQ(1UL, buckets.size());
130 const auto& bucketInfo = buckets[0];
131 EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
132 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
133 EXPECT_EQ(1LL, bucketInfo.mCount);
134 }
Yao Chen93fe3a32017-11-02 13:52:59 -0700135}
136
137TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
138 int64_t bucketStartTimeNs = 10000000000;
139 int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
140
Yangster-mac20877162017-12-22 17:19:39 -0800141 int tagId = 1;
142 int conditionTagId = 2;
143
Yao Chen93fe3a32017-11-02 13:52:59 -0700144 CountMetric metric;
Yangster-macd1815dc2017-11-13 21:43:15 -0800145 metric.set_name("1");
Yao Chen93fe3a32017-11-02 13:52:59 -0700146 metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
147 metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
Stefan Lafona5b51912017-12-05 21:43:52 -0800148 MetricConditionLink* link = metric.add_links();
Yao Chen93fe3a32017-11-02 13:52:59 -0700149 link->set_condition("APP_IN_BACKGROUND_PER_UID");
Yangster-mac20877162017-12-22 17:19:39 -0800150 *link->mutable_dimensions_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
151 *link->mutable_dimensions_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
Yao Chen93fe3a32017-11-02 13:52:59 -0700152
Yangster-mac20877162017-12-22 17:19:39 -0800153 LogEvent event1(tagId, bucketStartTimeNs + 1);
Yao Chen80235402017-11-13 20:42:25 -0800154 event1.write("111"); // uid
Yao Chen93fe3a32017-11-02 13:52:59 -0700155 event1.init();
156 ConditionKey key1;
Yangster-mac20877162017-12-22 17:19:39 -0800157 key1["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "111")};
Yao Chen93fe3a32017-11-02 13:52:59 -0700158
Yangster-mac20877162017-12-22 17:19:39 -0800159 LogEvent event2(tagId, bucketStartTimeNs + 10);
Yao Chen80235402017-11-13 20:42:25 -0800160 event2.write("222"); // uid
Yao Chen93fe3a32017-11-02 13:52:59 -0700161 event2.init();
162 ConditionKey key2;
Yangster-mac20877162017-12-22 17:19:39 -0800163 key2["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "222")};
Yao Chen93fe3a32017-11-02 13:52:59 -0700164
165 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
166 EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
167
168 EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue));
169
Yao Chenb3561512017-11-21 18:07:17 -0800170 CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
Yao Chen93fe3a32017-11-02 13:52:59 -0700171 bucketStartTimeNs);
172
Chenjie Yua7259ab2017-12-10 08:31:05 -0800173 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
Yangsterf2bee6f2017-11-29 12:01:05 -0800174 countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800175 EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
176
Chenjie Yua7259ab2017-12-10 08:31:05 -0800177 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
Yangsterf2bee6f2017-11-29 12:01:05 -0800178 countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
Yao Chen93fe3a32017-11-02 13:52:59 -0700179 EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
180 EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
181 countProducer.mPastBuckets.end());
182 const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
183 EXPECT_EQ(1UL, buckets.size());
184 const auto& bucketInfo = buckets[0];
185 EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
186 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
187 EXPECT_EQ(1LL, bucketInfo.mCount);
188}
189
Yangster-mace2cd6d52017-11-09 20:38:30 -0800190TEST(CountMetricProducerTest, TestAnomalyDetection) {
191 Alert alert;
192 alert.set_name("alert");
193 alert.set_metric_name("1");
194 alert.set_trigger_if_sum_gt(2);
195 alert.set_number_of_buckets(2);
196 alert.set_refractory_period_secs(1);
197
198 int64_t bucketStartTimeNs = 10000000000;
199 int64_t bucketSizeNs = 30 * NS_PER_SEC;
200 int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
201 int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
202
Yangster-mace2cd6d52017-11-09 20:38:30 -0800203 CountMetric metric;
204 metric.set_name("1");
205 metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
206
207 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
Yao Chenb3561512017-11-21 18:07:17 -0800208 CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
Yangster-mace2cd6d52017-11-09 20:38:30 -0800209 bucketStartTimeNs);
Bookatz857aaa52017-12-19 15:29:06 -0800210 sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800211
212 int tagId = 1;
213 LogEvent event1(tagId, bucketStartTimeNs + 1);
214 LogEvent event2(tagId, bucketStartTimeNs + 2);
215 LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1);
216 LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
217 LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
218 LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
219 LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3 + NS_PER_SEC);
220
221 // Two events in bucket #0.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800222 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
223 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800224
225 EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
226 EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
Bookatz857aaa52017-12-19 15:29:06 -0800227 EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800228
229 // One event in bucket #2. No alarm as bucket #0 is trashed out.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800230 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800231 EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
232 EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
Bookatz857aaa52017-12-19 15:29:06 -0800233 EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800234
235 // Two events in bucket #3.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800236 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
237 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
238 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800239 EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
240 EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
241 // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
Bookatz857aaa52017-12-19 15:29:06 -0800242 EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event5.GetTimestampNs());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800243
Chenjie Yua7259ab2017-12-10 08:31:05 -0800244 countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800245 EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
246 EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
Bookatz857aaa52017-12-19 15:29:06 -0800247 EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event7.GetTimestampNs());
Yangster-mace2cd6d52017-11-09 20:38:30 -0800248}
249
Yao Chen93fe3a32017-11-02 13:52:59 -0700250} // namespace statsd
251} // namespace os
252} // namespace android
253#else
254GTEST_LOG_(INFO) << "This test does nothing.\n";
255#endif