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/GaugeMetricProducer.h"
16 #include "src/stats_log_util.h"
17 #include "logd/LogEvent.h"
18 #include "metrics_test_helper.h"
19 #include "tests/statsd_test_util.h"
20
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 #include <math.h>
24 #include <stdio.h>
25 #include <vector>
26
27 using namespace testing;
28 using android::sp;
29 using std::set;
30 using std::unordered_map;
31 using std::vector;
32 using std::make_shared;
33
34 #ifdef __ANDROID__
35
36 namespace android {
37 namespace os {
38 namespace statsd {
39
40 const ConfigKey kConfigKey(0, 12345);
41 const int tagId = 1;
42 const int64_t metricId = 123;
43 const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
44 const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
45 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
46 const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
47 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
48 const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
49
TEST(GaugeMetricProducerTest,TestNoCondition)50 TEST(GaugeMetricProducerTest, TestNoCondition) {
51 GaugeMetric metric;
52 metric.set_id(metricId);
53 metric.set_bucket(ONE_MINUTE);
54 metric.mutable_gauge_fields_filter()->set_include_all(false);
55 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
56 gaugeFieldMatcher->set_field(tagId);
57 gaugeFieldMatcher->add_child()->set_field(1);
58 gaugeFieldMatcher->add_child()->set_field(3);
59
60 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
61
62 // TODO: pending refactor of StatsPullerManager
63 // For now we still need this so that it doesn't do real pulling.
64 shared_ptr<MockStatsPullerManager> pullerManager =
65 make_shared<StrictMock<MockStatsPullerManager>>();
66 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
67 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
68
69 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
70 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
71 gaugeProducer.setBucketSize(60 * NS_PER_SEC);
72
73 vector<shared_ptr<LogEvent>> allData;
74 allData.clear();
75 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
76 event->write(10);
77 event->write("some value");
78 event->write(11);
79 event->init();
80 allData.push_back(event);
81
82 gaugeProducer.onDataPulled(allData);
83 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
84 auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
85 EXPECT_EQ(INT, it->mValue.getType());
86 EXPECT_EQ(10, it->mValue.int_value);
87 it++;
88 EXPECT_EQ(11, it->mValue.int_value);
89 EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
90
91 allData.clear();
92 std::shared_ptr<LogEvent> event2 =
93 std::make_shared<LogEvent>(tagId, bucket3StartTimeNs + 10);
94 event2->write(24);
95 event2->write("some value");
96 event2->write(25);
97 event2->init();
98 allData.push_back(event2);
99 gaugeProducer.onDataPulled(allData);
100 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
101 it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
102 EXPECT_EQ(INT, it->mValue.getType());
103 EXPECT_EQ(24, it->mValue.int_value);
104 it++;
105 EXPECT_EQ(INT, it->mValue.getType());
106 EXPECT_EQ(25, it->mValue.int_value);
107 // One dimension.
108 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
109 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.size());
110 it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
111 EXPECT_EQ(INT, it->mValue.getType());
112 EXPECT_EQ(10L, it->mValue.int_value);
113 it++;
114 EXPECT_EQ(INT, it->mValue.getType());
115 EXPECT_EQ(11L, it->mValue.int_value);
116
117 gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
118 EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
119 // One dimension.
120 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
121 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
122 it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
123 EXPECT_EQ(INT, it->mValue.getType());
124 EXPECT_EQ(24L, it->mValue.int_value);
125 it++;
126 EXPECT_EQ(INT, it->mValue.getType());
127 EXPECT_EQ(25L, it->mValue.int_value);
128 }
129
TEST(GaugeMetricProducerTest,TestPushedEventsWithUpgrade)130 TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
131 sp<AlarmMonitor> alarmMonitor;
132 GaugeMetric metric;
133 metric.set_id(metricId);
134 metric.set_bucket(ONE_MINUTE);
135 metric.mutable_gauge_fields_filter()->set_include_all(true);
136
137 Alert alert;
138 alert.set_id(101);
139 alert.set_metric_id(metricId);
140 alert.set_trigger_if_sum_gt(25);
141 alert.set_num_buckets(100);
142 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
143 shared_ptr<MockStatsPullerManager> pullerManager =
144 make_shared<StrictMock<MockStatsPullerManager>>();
145 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
146 -1 /* -1 means no pulling */, bucketStartTimeNs,
147 bucketStartTimeNs, pullerManager);
148
149 gaugeProducer.setBucketSize(60 * NS_PER_SEC);
150 sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
151 EXPECT_TRUE(anomalyTracker != nullptr);
152
153 shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
154 event1->write(1);
155 event1->write(10);
156 event1->init();
157 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
158 EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
159
160 gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
161 EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
162 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
163 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
164 EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
165 // Partial buckets are not sent to anomaly tracker.
166 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
167
168 // Create an event in the same partial bucket.
169 shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
170 event2->write(1);
171 event2->write(10);
172 event2->init();
173 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
174 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
175 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
176 EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
177 // Partial buckets are not sent to anomaly tracker.
178 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
179
180 // Next event should trigger creation of new bucket and send previous full bucket to anomaly
181 // tracker.
182 shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
183 event3->write(1);
184 event3->write(10);
185 event3->init();
186 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
187 EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
188 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
189 EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
190 EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
191
192 // Next event should trigger creation of new bucket.
193 shared_ptr<LogEvent> event4 =
194 make_shared<LogEvent>(tagId, bucketStartTimeNs + 125 * NS_PER_SEC);
195 event4->write(1);
196 event4->write(10);
197 event4->init();
198 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
199 EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
200 EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
201 EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
202 }
203
TEST(GaugeMetricProducerTest,TestPulledWithUpgrade)204 TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
205 GaugeMetric metric;
206 metric.set_id(metricId);
207 metric.set_bucket(ONE_MINUTE);
208 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
209 gaugeFieldMatcher->set_field(tagId);
210 gaugeFieldMatcher->add_child()->set_field(2);
211
212 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
213
214 shared_ptr<MockStatsPullerManager> pullerManager =
215 make_shared<StrictMock<MockStatsPullerManager>>();
216 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
217 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
218 EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
219 .WillOnce(Invoke([](int tagId, int64_t timeNs,
220 vector<std::shared_ptr<LogEvent>>* data) {
221 data->clear();
222 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs);
223 event->write("some value");
224 event->write(2);
225 event->init();
226 data->push_back(event);
227 return true;
228 }));
229
230 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
231 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
232 gaugeProducer.setBucketSize(60 * NS_PER_SEC);
233
234 vector<shared_ptr<LogEvent>> allData;
235 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
236 event->write("some value");
237 event->write(1);
238 event->init();
239 allData.push_back(event);
240 gaugeProducer.onDataPulled(allData);
241 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
242 EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
243 ->second.front()
244 .mFields->begin()
245 ->mValue.int_value);
246
247 gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
248 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
249 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
250 EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
251 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
252 EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
253 ->second.front()
254 .mFields->begin()
255 ->mValue.int_value);
256
257 allData.clear();
258 event = make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 1);
259 event->write("some value");
260 event->write(3);
261 event->init();
262 allData.push_back(event);
263 gaugeProducer.onDataPulled(allData);
264 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
265 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
266 EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
267 ->second.front()
268 .mFields->begin()
269 ->mValue.int_value);
270 }
271
TEST(GaugeMetricProducerTest,TestWithCondition)272 TEST(GaugeMetricProducerTest, TestWithCondition) {
273 GaugeMetric metric;
274 metric.set_id(metricId);
275 metric.set_bucket(ONE_MINUTE);
276 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
277 gaugeFieldMatcher->set_field(tagId);
278 gaugeFieldMatcher->add_child()->set_field(2);
279 metric.set_condition(StringToId("SCREEN_ON"));
280
281 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
282
283 shared_ptr<MockStatsPullerManager> pullerManager =
284 make_shared<StrictMock<MockStatsPullerManager>>();
285 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
286 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
287 EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
288 .WillOnce(Invoke([](int tagId, int64_t timeNs,
289 vector<std::shared_ptr<LogEvent>>* data) {
290 data->clear();
291 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
292 event->write("some value");
293 event->write(100);
294 event->init();
295 data->push_back(event);
296 return true;
297 }));
298
299 GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId,
300 bucketStartTimeNs, bucketStartTimeNs, pullerManager);
301 gaugeProducer.setBucketSize(60 * NS_PER_SEC);
302
303 gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
304 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
305 EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
306 ->second.front()
307 .mFields->begin()
308 ->mValue.int_value);
309 EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
310
311 vector<shared_ptr<LogEvent>> allData;
312 allData.clear();
313 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
314 event->write("some value");
315 event->write(110);
316 event->init();
317 allData.push_back(event);
318 gaugeProducer.onDataPulled(allData);
319
320 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
321 EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
322 ->second.front()
323 .mFields->begin()
324 ->mValue.int_value);
325 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
326 EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
327 ->second.back()
328 .mGaugeAtoms.front()
329 .mFields->begin()
330 ->mValue.int_value);
331
332 gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
333 gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
334 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
335 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
336 EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
337 ->second.back()
338 .mGaugeAtoms.front()
339 .mFields->begin()
340 ->mValue.int_value);
341 }
342
TEST(GaugeMetricProducerTest,TestWithSlicedCondition)343 TEST(GaugeMetricProducerTest, TestWithSlicedCondition) {
344 const int conditionTag = 65;
345 GaugeMetric metric;
346 metric.set_id(1111111);
347 metric.set_bucket(ONE_MINUTE);
348 metric.mutable_gauge_fields_filter()->set_include_all(true);
349 metric.set_condition(StringToId("APP_DIED"));
350 auto dim = metric.mutable_dimensions_in_what();
351 dim->set_field(tagId);
352 dim->add_child()->set_field(1);
353
354 dim = metric.mutable_dimensions_in_condition();
355 dim->set_field(conditionTag);
356 dim->add_child()->set_field(1);
357
358 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
359 EXPECT_CALL(*wizard, query(_, _, _, _, _, _))
360 .WillRepeatedly(
361 Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
362 const vector<Matcher>& dimensionFields, const bool isSubsetDim,
363 const bool isPartialLink,
364 std::unordered_set<HashableDimensionKey>* dimensionKeySet) {
365 dimensionKeySet->clear();
366 int pos[] = {1, 0, 0};
367 Field f(conditionTag, pos, 0);
368 HashableDimensionKey key;
369 key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
370 dimensionKeySet->insert(key);
371
372 return ConditionState::kTrue;
373 }));
374
375 shared_ptr<MockStatsPullerManager> pullerManager =
376 make_shared<StrictMock<MockStatsPullerManager>>();
377 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
378 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
379 EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
380 .WillOnce(Invoke([](int tagId, int64_t timeNs,
381 vector<std::shared_ptr<LogEvent>>* data) {
382 data->clear();
383 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
384 event->write(1000);
385 event->write(100);
386 event->init();
387 data->push_back(event);
388 return true;
389 }));
390
391 GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
392 bucketStartTimeNs, pullerManager);
393 gaugeProducer.setBucketSize(60 * NS_PER_SEC);
394
395 gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
396
397 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
398 const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
399 EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
400 EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
401
402 EXPECT_EQ(1UL, key.getDimensionKeyInCondition().getValues().size());
403 EXPECT_EQ(1000000, key.getDimensionKeyInCondition().getValues()[0].mValue.int_value);
404
405 EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
406
407 vector<shared_ptr<LogEvent>> allData;
408 allData.clear();
409 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
410 event->write(1000);
411 event->write(110);
412 event->init();
413 allData.push_back(event);
414 gaugeProducer.onDataPulled(allData);
415
416 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
417 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
418 }
419
TEST(GaugeMetricProducerTest,TestAnomalyDetection)420 TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
421 sp<AlarmMonitor> alarmMonitor;
422 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
423
424 shared_ptr<MockStatsPullerManager> pullerManager =
425 make_shared<StrictMock<MockStatsPullerManager>>();
426 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
427 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
428
429 GaugeMetric metric;
430 metric.set_id(metricId);
431 metric.set_bucket(ONE_MINUTE);
432 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
433 gaugeFieldMatcher->set_field(tagId);
434 gaugeFieldMatcher->add_child()->set_field(2);
435 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
436 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
437 gaugeProducer.setBucketSize(60 * NS_PER_SEC);
438
439 Alert alert;
440 alert.set_id(101);
441 alert.set_metric_id(metricId);
442 alert.set_trigger_if_sum_gt(25);
443 alert.set_num_buckets(2);
444 const int32_t refPeriodSec = 60;
445 alert.set_refractory_period_secs(refPeriodSec);
446 sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
447
448 int tagId = 1;
449 std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
450 event1->write("some value");
451 event1->write(13);
452 event1->init();
453
454 gaugeProducer.onDataPulled({event1});
455 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
456 EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
457 ->second.front()
458 .mFields->begin()
459 ->mValue.int_value);
460 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
461
462 std::shared_ptr<LogEvent> event2 =
463 std::make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 20);
464 event2->write("some value");
465 event2->write(15);
466 event2->init();
467
468 gaugeProducer.onDataPulled({event2});
469 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
470 EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
471 ->second.front()
472 .mFields->begin()
473 ->mValue.int_value);
474 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
475 std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
476
477 std::shared_ptr<LogEvent> event3 =
478 std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
479 event3->write("some value");
480 event3->write(26);
481 event3->init();
482
483 gaugeProducer.onDataPulled({event3});
484 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
485 EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
486 ->second.front()
487 .mFields->begin()
488 ->mValue.int_value);
489 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
490 std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
491
492 // The event4 does not have the gauge field. Thus the current bucket value is 0.
493 std::shared_ptr<LogEvent> event4 =
494 std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10);
495 event4->write("some value");
496 event4->init();
497 gaugeProducer.onDataPulled({event4});
498 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
499 EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
500 }
501
502 } // namespace statsd
503 } // namespace os
504 } // namespace android
505 #else
506 GTEST_LOG_(INFO) << "This test does nothing.\n";
507 #endif
508