blob: 12839e6d1fbe1bb99954cf168a04f19106305e8c [file] [log] [blame]
Yangster-mace2cd6d52017-11-09 20:38:30 -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
Yao Chend5aa01b32017-12-19 16:46:36 -080015#include "src/metrics/GaugeMetricProducer.h"
Yangster-mace2cd6d52017-11-09 20:38:30 -080016
17#include <gmock/gmock.h>
18#include <gtest/gtest.h>
Bookatz6bf98252018-03-14 10:44:24 -070019#include <math.h>
Yangster-mace2cd6d52017-11-09 20:38:30 -080020#include <stdio.h>
tsaichristineb87ca152019-12-09 15:19:41 -080021
Yangster-mace2cd6d52017-11-09 20:38:30 -080022#include <vector>
23
tsaichristineb87ca152019-12-09 15:19:41 -080024#include "logd/LogEvent.h"
25#include "metrics_test_helper.h"
26#include "src/matchers/SimpleLogMatchingTracker.h"
27#include "src/metrics/MetricProducer.h"
28#include "src/stats_log_util.h"
tsaichristined5800b22020-03-25 10:31:50 -070029#include "stats_event.h"
tsaichristineb87ca152019-12-09 15:19:41 -080030#include "tests/statsd_test_util.h"
31
Yangster-mace2cd6d52017-11-09 20:38:30 -080032using namespace testing;
33using android::sp;
34using std::set;
35using std::unordered_map;
36using std::vector;
Chenjie Yud9dfda72017-12-11 17:41:20 -080037using std::make_shared;
Yangster-mace2cd6d52017-11-09 20:38:30 -080038
39#ifdef __ANDROID__
40
41namespace android {
42namespace os {
43namespace statsd {
44
Tej Singhe678cb72020-04-14 16:23:30 -070045namespace {
46
Yangster-mac94e197c2018-01-02 16:03:03 -080047const ConfigKey kConfigKey(0, 12345);
Chenjie Yud9dfda72017-12-11 17:41:20 -080048const int tagId = 1;
Yangster-mac94e197c2018-01-02 16:03:03 -080049const int64_t metricId = 123;
Yangster-mac32f07af2018-10-13 17:08:11 -070050const int64_t atomMatcherId = 678;
51const int logEventMatcherIndex = 0;
Yangster-macbe10ddf2018-03-13 15:39:51 -070052const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
Yangster-macb8144812018-01-04 10:56:23 -080053const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
Chenjie Yud9dfda72017-12-11 17:41:20 -080054const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
55const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
56const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
Tej Singhe678cb72020-04-14 16:23:30 -070057const int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
Bookatz8f2f3d82017-12-07 13:53:21 -080058
tsaichristined5800b22020-03-25 10:31:50 -070059shared_ptr<LogEvent> makeLogEvent(int32_t atomId, int64_t timestampNs, int32_t value1, string str1,
60 int32_t value2) {
61 AStatsEvent* statsEvent = AStatsEvent_obtain();
62 AStatsEvent_setAtomId(statsEvent, atomId);
63 AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
64
65 AStatsEvent_writeInt32(statsEvent, value1);
66 AStatsEvent_writeString(statsEvent, str1.c_str());
67 AStatsEvent_writeInt32(statsEvent, value2);
tsaichristined5800b22020-03-25 10:31:50 -070068
tsaichristined5800b22020-03-25 10:31:50 -070069 shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
tsaichristine8dca82e2020-04-07 09:40:03 -070070 parseStatsEventToLogEvent(statsEvent, logEvent.get());
tsaichristined5800b22020-03-25 10:31:50 -070071 return logEvent;
72}
73} // anonymous namespace
74
Tej Singhe678cb72020-04-14 16:23:30 -070075// Setup for parameterized tests.
76class GaugeMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
77
78INSTANTIATE_TEST_SUITE_P(GaugeMetricProducerTest_PartialBucket,
79 GaugeMetricProducerTest_PartialBucket,
80 testing::Values(APP_UPGRADE, BOOT_COMPLETE));
81
Chenjie Yue1361ed2018-07-23 17:33:09 -070082/*
83 * Tests that the first bucket works correctly
84 */
85TEST(GaugeMetricProducerTest, TestFirstBucket) {
86 GaugeMetric metric;
87 metric.set_id(metricId);
88 metric.set_bucket(ONE_MINUTE);
89 metric.mutable_gauge_fields_filter()->set_include_all(false);
90 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
91 gaugeFieldMatcher->set_field(tagId);
92 gaugeFieldMatcher->add_child()->set_field(1);
93 gaugeFieldMatcher->add_child()->set_field(3);
94
95 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
Yangster-mac32f07af2018-10-13 17:08:11 -070096
97 UidMap uidMap;
98 SimpleAtomMatcher atomMatcher;
99 atomMatcher.set_atom_id(tagId);
100 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
101 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
102
Chenjie Yue1361ed2018-07-23 17:33:09 -0700103 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
104
105 // statsd started long ago.
106 // The metric starts in the middle of the bucket
107 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
Yangster-mac32f07af2018-10-13 17:08:11 -0700108 logEventMatcherIndex, eventMatcherWizard,
Chenjie Yu88588972018-08-03 09:49:22 -0700109 -1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
110 pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800111 gaugeProducer.prepareFirstBucket();
Chenjie Yue1361ed2018-07-23 17:33:09 -0700112
113 EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
114 EXPECT_EQ(10, gaugeProducer.mCurrentBucketNum);
115 EXPECT_EQ(660000000005, gaugeProducer.getCurrentBucketEndTimeNs());
116}
117
tsaichristined5800b22020-03-25 10:31:50 -0700118TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
119 GaugeMetric metric;
120 metric.set_id(metricId);
121 metric.set_bucket(ONE_MINUTE);
122 metric.mutable_gauge_fields_filter()->set_include_all(false);
123 metric.set_max_pull_delay_sec(INT_MAX);
124 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
125 gaugeFieldMatcher->set_field(tagId);
126 gaugeFieldMatcher->add_child()->set_field(1);
127 gaugeFieldMatcher->add_child()->set_field(3);
128
129 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
130
131 UidMap uidMap;
132 SimpleAtomMatcher atomMatcher;
133 atomMatcher.set_atom_id(tagId);
134 sp<EventMatcherWizard> eventMatcherWizard =
135 new EventMatcherWizard({new SimpleLogMatchingTracker(
136 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
137
138 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800139 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
140 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
141 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
142 .WillOnce(Invoke([](int tagId, const ConfigKey&,
143 vector<std::shared_ptr<LogEvent>>* data, bool) {
tsaichristined5800b22020-03-25 10:31:50 -0700144 data->clear();
145 data->push_back(makeLogEvent(tagId, bucketStartTimeNs + 10, 3, "some value", 11));
146 return true;
147 }));
148
149 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
150 logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
151 bucketStartTimeNs, bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800152 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700153
154 vector<shared_ptr<LogEvent>> allData;
155 allData.clear();
156 allData.push_back(makeLogEvent(tagId, bucket2StartTimeNs + 1, 10, "some value", 11));
157
158 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700159 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700160 auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
161 EXPECT_EQ(INT, it->mValue.getType());
162 EXPECT_EQ(10, it->mValue.int_value);
163 it++;
164 EXPECT_EQ(11, it->mValue.int_value);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700165 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
tsaichristined5800b22020-03-25 10:31:50 -0700166 EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()
167 ->second.back()
168 .mGaugeAtoms.front()
169 .mFields->begin()
170 ->mValue.int_value);
171
172 allData.clear();
173 allData.push_back(makeLogEvent(tagId, bucket3StartTimeNs + 10, 24, "some value", 25));
174 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700175 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700176 it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
177 EXPECT_EQ(INT, it->mValue.getType());
178 EXPECT_EQ(24, it->mValue.int_value);
179 it++;
180 EXPECT_EQ(INT, it->mValue.getType());
181 EXPECT_EQ(25, it->mValue.int_value);
182 // One dimension.
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700183 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
184 ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
tsaichristined5800b22020-03-25 10:31:50 -0700185 it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
186 EXPECT_EQ(INT, it->mValue.getType());
187 EXPECT_EQ(10L, it->mValue.int_value);
188 it++;
189 EXPECT_EQ(INT, it->mValue.getType());
190 EXPECT_EQ(11L, it->mValue.int_value);
191
192 gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700193 ASSERT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700194 // One dimension.
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700195 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
196 ASSERT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
tsaichristined5800b22020-03-25 10:31:50 -0700197 it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
198 EXPECT_EQ(INT, it->mValue.getType());
199 EXPECT_EQ(24L, it->mValue.int_value);
200 it++;
201 EXPECT_EQ(INT, it->mValue.getType());
202 EXPECT_EQ(25L, it->mValue.int_value);
203}
204
Tej Singhe678cb72020-04-14 16:23:30 -0700205TEST_P(GaugeMetricProducerTest_PartialBucket, TestPushedEvents) {
tsaichristined5800b22020-03-25 10:31:50 -0700206 sp<AlarmMonitor> alarmMonitor;
207 GaugeMetric metric;
208 metric.set_id(metricId);
209 metric.set_bucket(ONE_MINUTE);
210 metric.mutable_gauge_fields_filter()->set_include_all(true);
211
212 Alert alert;
213 alert.set_id(101);
214 alert.set_metric_id(metricId);
215 alert.set_trigger_if_sum_gt(25);
216 alert.set_num_buckets(100);
217 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
218 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
219
220 UidMap uidMap;
221 SimpleAtomMatcher atomMatcher;
222 atomMatcher.set_atom_id(tagId);
223 sp<EventMatcherWizard> eventMatcherWizard =
224 new EventMatcherWizard({new SimpleLogMatchingTracker(
225 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
226
227 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
228 logEventMatcherIndex, eventMatcherWizard,
229 -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
230 bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800231 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700232
233 sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
234 EXPECT_TRUE(anomalyTracker != nullptr);
235
236 LogEvent event1(/*uid=*/0, /*pid=*/0);
237 CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
238 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
239 EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
240
Tej Singhe678cb72020-04-14 16:23:30 -0700241 switch (GetParam()) {
242 case APP_UPGRADE:
243 gaugeProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
244 break;
245 case BOOT_COMPLETE:
246 gaugeProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
247 break;
248 }
tsaichristined5800b22020-03-25 10:31:50 -0700249 EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700250 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700251 EXPECT_EQ(bucketStartTimeNs,
252 gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
253 EXPECT_EQ(partialBucketSplitTimeNs,
254 gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
tsaichristined5800b22020-03-25 10:31:50 -0700255 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
Tej Singhe678cb72020-04-14 16:23:30 -0700256 EXPECT_EQ(partialBucketSplitTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
tsaichristined5800b22020-03-25 10:31:50 -0700257 // Partial buckets are not sent to anomaly tracker.
258 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
259
260 // Create an event in the same partial bucket.
261 LogEvent event2(/*uid=*/0, /*pid=*/0);
262 CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10);
263 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
264 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700265 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700266 EXPECT_EQ(bucketStartTimeNs,
267 gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
268 EXPECT_EQ(partialBucketSplitTimeNs,
269 gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
270 EXPECT_EQ((int64_t)partialBucketSplitTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
tsaichristined5800b22020-03-25 10:31:50 -0700271 // Partial buckets are not sent to anomaly tracker.
272 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
273
274 // Next event should trigger creation of new bucket and send previous full bucket to anomaly
275 // tracker.
276 LogEvent event3(/*uid=*/0, /*pid=*/0);
277 CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10);
278 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
279 EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700280 ASSERT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
tsaichristined5800b22020-03-25 10:31:50 -0700281 EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
282 EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
283
284 // Next event should trigger creation of new bucket.
285 LogEvent event4(/*uid=*/0, /*pid=*/0);
286 CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 125 * NS_PER_SEC, 1, 10);
287 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
288 EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700289 ASSERT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
tsaichristined5800b22020-03-25 10:31:50 -0700290 EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
291}
292
Tej Singhe678cb72020-04-14 16:23:30 -0700293TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) {
tsaichristined5800b22020-03-25 10:31:50 -0700294 GaugeMetric metric;
295 metric.set_id(metricId);
296 metric.set_bucket(ONE_MINUTE);
297 metric.set_max_pull_delay_sec(INT_MAX);
298 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
299 gaugeFieldMatcher->set_field(tagId);
300 gaugeFieldMatcher->add_child()->set_field(2);
301
302 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
303
304 UidMap uidMap;
305 SimpleAtomMatcher atomMatcher;
306 atomMatcher.set_atom_id(tagId);
307 sp<EventMatcherWizard> eventMatcherWizard =
308 new EventMatcherWizard({new SimpleLogMatchingTracker(
309 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
310
311 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800312 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
313 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
314 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
tsaichristined5800b22020-03-25 10:31:50 -0700315 .WillOnce(Return(false))
Tej Singh3be093b2020-03-04 20:08:38 -0800316 .WillOnce(Invoke(
317 [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
318 data->clear();
Tej Singhe678cb72020-04-14 16:23:30 -0700319 data->push_back(
320 CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 2));
Tej Singh3be093b2020-03-04 20:08:38 -0800321 return true;
322 }));
tsaichristined5800b22020-03-25 10:31:50 -0700323
324 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
325 logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
326 bucketStartTimeNs, bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800327 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700328
329 vector<shared_ptr<LogEvent>> allData;
330 allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
331 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700332 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700333 EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
334 ->second.front()
335 .mFields->begin()
336 ->mValue.int_value);
337
Tej Singhe678cb72020-04-14 16:23:30 -0700338 switch (GetParam()) {
339 case APP_UPGRADE:
340 gaugeProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
341 break;
342 case BOOT_COMPLETE:
343 gaugeProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
344 break;
345 }
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700346 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
Tej Singhe678cb72020-04-14 16:23:30 -0700347 EXPECT_EQ(bucketStartTimeNs,
348 gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
349 EXPECT_EQ(partialBucketSplitTimeNs,
350 gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
tsaichristined5800b22020-03-25 10:31:50 -0700351 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
Tej Singhe678cb72020-04-14 16:23:30 -0700352 EXPECT_EQ(partialBucketSplitTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700353 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700354 EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
355 ->second.front()
356 .mFields->begin()
357 ->mValue.int_value);
358
359 allData.clear();
360 allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 1, 3));
361 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700362 ASSERT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
363 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700364 EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
365 ->second.front()
366 .mFields->begin()
367 ->mValue.int_value);
368}
369
370TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
371 GaugeMetric metric;
372 metric.set_id(metricId);
373 metric.set_bucket(ONE_MINUTE);
374 metric.set_max_pull_delay_sec(INT_MAX);
375 metric.set_split_bucket_for_app_upgrade(false);
376 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
377 gaugeFieldMatcher->set_field(tagId);
378 gaugeFieldMatcher->add_child()->set_field(2);
379
380 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
381
382 UidMap uidMap;
383 SimpleAtomMatcher atomMatcher;
384 atomMatcher.set_atom_id(tagId);
385 sp<EventMatcherWizard> eventMatcherWizard =
386 new EventMatcherWizard({new SimpleLogMatchingTracker(
387 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
388
389 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800390 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
391 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
392 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)).WillOnce(Return(false));
tsaichristined5800b22020-03-25 10:31:50 -0700393
394 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
395 logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
396 bucketStartTimeNs, bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800397 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700398
399 vector<shared_ptr<LogEvent>> allData;
400 allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
401 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700402 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700403 EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
404 ->second.front()
405 .mFields->begin()
406 ->mValue.int_value);
407
Tej Singhe678cb72020-04-14 16:23:30 -0700408 gaugeProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700409 ASSERT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
tsaichristined5800b22020-03-25 10:31:50 -0700410 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
411 EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700412 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700413 EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
414 ->second.front()
415 .mFields->begin()
416 ->mValue.int_value);
417}
418
419TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
420 GaugeMetric metric;
421 metric.set_id(metricId);
422 metric.set_bucket(ONE_MINUTE);
423 metric.set_max_pull_delay_sec(INT_MAX);
424 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
425 gaugeFieldMatcher->set_field(tagId);
426 gaugeFieldMatcher->add_child()->set_field(2);
427 metric.set_condition(StringToId("SCREEN_ON"));
428
429 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
430
431 UidMap uidMap;
432 SimpleAtomMatcher atomMatcher;
433 atomMatcher.set_atom_id(tagId);
434 sp<EventMatcherWizard> eventMatcherWizard =
435 new EventMatcherWizard({new SimpleLogMatchingTracker(
436 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
437
438 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800439 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
440 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
441 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
442 .WillOnce(Invoke([](int tagId, const ConfigKey&,
443 vector<std::shared_ptr<LogEvent>>* data, bool) {
tsaichristined5800b22020-03-25 10:31:50 -0700444 data->clear();
445 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 100));
446 return true;
447 }));
448
449 GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
450 eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
451 bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800452 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700453
454 gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700455 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700456 EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
457 ->second.front()
458 .mFields->begin()
459 ->mValue.int_value);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700460 ASSERT_EQ(0UL, gaugeProducer.mPastBuckets.size());
tsaichristined5800b22020-03-25 10:31:50 -0700461
462 vector<shared_ptr<LogEvent>> allData;
463 allData.clear();
464 allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
465 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
466
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700467 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700468 EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
469 ->second.front()
470 .mFields->begin()
471 ->mValue.int_value);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700472 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
tsaichristined5800b22020-03-25 10:31:50 -0700473 EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
474 ->second.back()
475 .mGaugeAtoms.front()
476 .mFields->begin()
477 ->mValue.int_value);
478
479 gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
480 gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700481 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
482 ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
tsaichristined5800b22020-03-25 10:31:50 -0700483 EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
484 ->second.back()
485 .mGaugeAtoms.front()
486 .mFields->begin()
487 ->mValue.int_value);
488}
489
490TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
491 const int conditionTag = 65;
492 GaugeMetric metric;
493 metric.set_id(1111111);
494 metric.set_bucket(ONE_MINUTE);
495 metric.mutable_gauge_fields_filter()->set_include_all(true);
496 metric.set_condition(StringToId("APP_DIED"));
497 metric.set_max_pull_delay_sec(INT_MAX);
498 auto dim = metric.mutable_dimensions_in_what();
499 dim->set_field(tagId);
500 dim->add_child()->set_field(1);
501
502 UidMap uidMap;
503 SimpleAtomMatcher atomMatcher;
504 atomMatcher.set_atom_id(tagId);
505 sp<EventMatcherWizard> eventMatcherWizard =
506 new EventMatcherWizard({new SimpleLogMatchingTracker(
507 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
508
509 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
510 EXPECT_CALL(*wizard, query(_, _, _))
511 .WillRepeatedly(
512 Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
513 const bool isPartialLink) {
514 int pos[] = {1, 0, 0};
515 Field f(conditionTag, pos, 0);
516 HashableDimensionKey key;
517 key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
518
519 return ConditionState::kTrue;
520 }));
521
522 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800523 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
524 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
525 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
526 .WillOnce(Invoke([](int tagId, const ConfigKey&,
527 vector<std::shared_ptr<LogEvent>>* data, bool) {
tsaichristined5800b22020-03-25 10:31:50 -0700528 data->clear();
529 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 1000, 100));
530 return true;
531 }));
532
533 GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
534 eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
535 bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800536 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700537
538 gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
539
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700540 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700541 const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700542 ASSERT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
tsaichristined5800b22020-03-25 10:31:50 -0700543 EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
544
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700545 ASSERT_EQ(0UL, gaugeProducer.mPastBuckets.size());
tsaichristined5800b22020-03-25 10:31:50 -0700546
547 vector<shared_ptr<LogEvent>> allData;
548 allData.clear();
549 allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1000, 110));
550 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
551
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700552 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
553 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
tsaichristined5800b22020-03-25 10:31:50 -0700554}
555
556TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
557 sp<AlarmMonitor> alarmMonitor;
558 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
559
560 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800561 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
562 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
563 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)).WillOnce(Return(false));
tsaichristined5800b22020-03-25 10:31:50 -0700564
565 GaugeMetric metric;
566 metric.set_id(metricId);
567 metric.set_bucket(ONE_MINUTE);
568 metric.set_max_pull_delay_sec(INT_MAX);
569 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
570 gaugeFieldMatcher->set_field(tagId);
571 gaugeFieldMatcher->add_child()->set_field(2);
572
573 UidMap uidMap;
574 SimpleAtomMatcher atomMatcher;
575 atomMatcher.set_atom_id(tagId);
576 sp<EventMatcherWizard> eventMatcherWizard =
577 new EventMatcherWizard({new SimpleLogMatchingTracker(
578 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
579
580 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
581 logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
582 bucketStartTimeNs, bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800583 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700584
585 Alert alert;
586 alert.set_id(101);
587 alert.set_metric_id(metricId);
588 alert.set_trigger_if_sum_gt(25);
589 alert.set_num_buckets(2);
590 const int32_t refPeriodSec = 60;
591 alert.set_refractory_period_secs(refPeriodSec);
592 sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
593
594 int tagId = 1;
595 vector<shared_ptr<LogEvent>> allData;
596 allData.clear();
597 allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 13));
598 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700599 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700600 EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
601 ->second.front()
602 .mFields->begin()
603 ->mValue.int_value);
604 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
605
606 std::shared_ptr<LogEvent> event2 =
607 CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 20, 15);
608
609 allData.clear();
610 allData.push_back(event2);
611 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700612 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700613 EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
614 ->second.front()
615 .mFields->begin()
616 ->mValue.int_value);
617 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
618 std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
619
620 allData.clear();
621 allData.push_back(
622 CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10, 26));
623 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700624 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700625 EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
626 ->second.front()
627 .mFields->begin()
628 ->mValue.int_value);
629 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
630 std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
631
632 // This event does not have the gauge field. Thus the current bucket value is 0.
633 allData.clear();
634 allData.push_back(CreateNoValuesLogEvent(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10));
635 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700636 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700637 EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
638}
639
640TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
641 GaugeMetric metric;
642 metric.set_id(metricId);
643 metric.set_bucket(ONE_MINUTE);
644 metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
645 metric.mutable_gauge_fields_filter()->set_include_all(false);
646 metric.set_max_pull_delay_sec(INT_MAX);
647 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
648 gaugeFieldMatcher->set_field(tagId);
649 gaugeFieldMatcher->add_child()->set_field(1);
650
651 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
652
653 UidMap uidMap;
654 SimpleAtomMatcher atomMatcher;
655 atomMatcher.set_atom_id(tagId);
656 sp<EventMatcherWizard> eventMatcherWizard =
657 new EventMatcherWizard({new SimpleLogMatchingTracker(
658 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
659
660 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800661 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
662 .WillOnce(Invoke([](int tagId, const ConfigKey&,
663 vector<std::shared_ptr<LogEvent>>* data, bool) {
tsaichristined5800b22020-03-25 10:31:50 -0700664 data->clear();
665 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 4));
666 return true;
667 }))
Tej Singh3be093b2020-03-04 20:08:38 -0800668 .WillOnce(Invoke([](int tagId, const ConfigKey&,
669 vector<std::shared_ptr<LogEvent>>* data, bool) {
tsaichristined5800b22020-03-25 10:31:50 -0700670 data->clear();
671 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 5));
672 return true;
673 }))
674 .WillOnce(Return(true));
675
676 int triggerId = 5;
677 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
678 logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
679 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800680 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700681
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700682 ASSERT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700683
684 LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
685 CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 10);
686 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700687 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
tsaichristined5800b22020-03-25 10:31:50 -0700688 triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
689 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700690 ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
tsaichristined5800b22020-03-25 10:31:50 -0700691 triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
692 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
693
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700694 ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
695 ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
tsaichristined5800b22020-03-25 10:31:50 -0700696 EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
697 ->second.back()
698 .mGaugeAtoms[0]
699 .mFields->begin()
700 ->mValue.int_value);
701 EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
702 ->second.back()
703 .mGaugeAtoms[1]
704 .mFields->begin()
705 ->mValue.int_value);
706}
707
708TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
709 GaugeMetric metric;
710 metric.set_id(metricId);
711 metric.set_bucket(ONE_MINUTE);
712 metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
713 metric.mutable_gauge_fields_filter()->set_include_all(true);
714 metric.set_max_pull_delay_sec(INT_MAX);
715 auto dimensionMatcher = metric.mutable_dimensions_in_what();
716 // use field 1 as dimension.
717 dimensionMatcher->set_field(tagId);
718 dimensionMatcher->add_child()->set_field(1);
719
720 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
721
722 UidMap uidMap;
723 SimpleAtomMatcher atomMatcher;
724 atomMatcher.set_atom_id(tagId);
725 sp<EventMatcherWizard> eventMatcherWizard =
726 new EventMatcherWizard({new SimpleLogMatchingTracker(
727 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
728
729 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800730 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
731 .WillOnce(Invoke(
732 [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
733 data->clear();
734 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 3, 3, 4));
735 return true;
736 }))
737 .WillOnce(Invoke([](int tagId, const ConfigKey&,
738 vector<std::shared_ptr<LogEvent>>* data, bool) {
tsaichristined5800b22020-03-25 10:31:50 -0700739 data->clear();
740 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 4, 5));
741 return true;
742 }))
Tej Singh3be093b2020-03-04 20:08:38 -0800743 .WillOnce(Invoke([](int tagId, const ConfigKey&,
744 vector<std::shared_ptr<LogEvent>>* data, bool) {
tsaichristined5800b22020-03-25 10:31:50 -0700745 data->clear();
746 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 4, 6));
747 return true;
748 }))
749 .WillOnce(Return(true));
750
751 int triggerId = 5;
752 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
753 logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
754 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800755 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700756
757 LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
758 CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
759 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700760 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
tsaichristined5800b22020-03-25 10:31:50 -0700761 triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 10);
762 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700763 ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
764 ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
tsaichristined5800b22020-03-25 10:31:50 -0700765 triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
766 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700767 ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
tsaichristined5800b22020-03-25 10:31:50 -0700768 triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
769 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
770
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700771 ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.size());
tsaichristined5800b22020-03-25 10:31:50 -0700772 auto bucketIt = gaugeProducer.mPastBuckets.begin();
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700773 ASSERT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
tsaichristined5800b22020-03-25 10:31:50 -0700774 EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
775 EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
776 bucketIt++;
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700777 ASSERT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
tsaichristined5800b22020-03-25 10:31:50 -0700778 EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
779 EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
780 EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
781}
782
783/*
784 * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
785 * is smaller than the "min_bucket_size_nanos" specified in the metric config.
786 */
787TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
788 GaugeMetric metric;
789 metric.set_id(metricId);
790 metric.set_bucket(FIVE_MINUTES);
791 metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
792 metric.set_min_bucket_size_nanos(10000000000); // 10 seconds
793
794 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
795
796 UidMap uidMap;
797 SimpleAtomMatcher atomMatcher;
798 atomMatcher.set_atom_id(tagId);
799 sp<EventMatcherWizard> eventMatcherWizard =
800 new EventMatcherWizard({new SimpleLogMatchingTracker(
801 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
802
803 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
Tej Singh3be093b2020-03-04 20:08:38 -0800804 EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
tsaichristined5800b22020-03-25 10:31:50 -0700805 // Bucket start.
Tej Singh3be093b2020-03-04 20:08:38 -0800806 .WillOnce(Invoke(
807 [](int tagId, const ConfigKey&, vector<std::shared_ptr<LogEvent>>* data, bool) {
808 data->clear();
809 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 10));
810 return true;
811 }));
tsaichristined5800b22020-03-25 10:31:50 -0700812
813 int triggerId = 5;
814 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
815 logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
816 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
Tej Singh3be093b2020-03-04 20:08:38 -0800817 gaugeProducer.prepareFirstBucket();
tsaichristined5800b22020-03-25 10:31:50 -0700818
819 LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
820 CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
821 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
822
823 // Check dump report.
824 ProtoOutputStream output;
825 std::set<string> strSet;
826 gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */, true,
827 FAST /* dump_latency */, &strSet, &output);
828
829 StatsLogReport report = outputStreamToProto(&output);
830 EXPECT_TRUE(report.has_gauge_metrics());
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700831 ASSERT_EQ(0, report.gauge_metrics().data_size());
832 ASSERT_EQ(1, report.gauge_metrics().skipped_size());
tsaichristined5800b22020-03-25 10:31:50 -0700833
834 EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
835 report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
836 EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
837 report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
Muhammad Qureshidff78d62020-05-11 13:37:43 -0700838 ASSERT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
tsaichristined5800b22020-03-25 10:31:50 -0700839
840 auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
841 EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
842 EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
843}
tsaichristineb87ca152019-12-09 15:19:41 -0800844
Yangster-mace2cd6d52017-11-09 20:38:30 -0800845} // namespace statsd
846} // namespace os
847} // namespace android
848#else
849GTEST_LOG_(INFO) << "This test does nothing.\n";
850#endif