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/matchers/SimpleLogMatchingTracker.h"
16 #include "src/metrics/GaugeMetricProducer.h"
17 #include "src/stats_log_util.h"
18 #include "logd/LogEvent.h"
19 #include "metrics_test_helper.h"
20 #include "tests/statsd_test_util.h"
21
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24 #include <math.h>
25 #include <stdio.h>
26 #include <vector>
27
28 using namespace testing;
29 using android::sp;
30 using std::set;
31 using std::unordered_map;
32 using std::vector;
33 using std::make_shared;
34
35 #ifdef __ANDROID__
36
37 namespace android {
38 namespace os {
39 namespace statsd {
40
41 const ConfigKey kConfigKey(0, 12345);
42 const int tagId = 1;
43 const int64_t metricId = 123;
44 const int64_t atomMatcherId = 678;
45 const int logEventMatcherIndex = 0;
46 const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
47 const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
48 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
49 const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
50 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
51 const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
52
53 /*
54 * Tests that the first bucket works correctly
55 */
TEST(GaugeMetricProducerTest,TestFirstBucket)56 TEST(GaugeMetricProducerTest, TestFirstBucket) {
57 GaugeMetric metric;
58 metric.set_id(metricId);
59 metric.set_bucket(ONE_MINUTE);
60 metric.mutable_gauge_fields_filter()->set_include_all(false);
61 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
62 gaugeFieldMatcher->set_field(tagId);
63 gaugeFieldMatcher->add_child()->set_field(1);
64 gaugeFieldMatcher->add_child()->set_field(3);
65
66 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
67
68 UidMap uidMap;
69 SimpleAtomMatcher atomMatcher;
70 atomMatcher.set_atom_id(tagId);
71 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
72 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
73
74 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
75
76 // statsd started long ago.
77 // The metric starts in the middle of the bucket
78 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
79 logEventMatcherIndex, eventMatcherWizard,
80 -1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
81 pullerManager);
82 gaugeProducer.prepareFirstBucket();
83
84
85 EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
86 EXPECT_EQ(10, gaugeProducer.mCurrentBucketNum);
87 EXPECT_EQ(660000000005, gaugeProducer.getCurrentBucketEndTimeNs());
88 }
89
TEST(GaugeMetricProducerTest,TestPulledEventsNoCondition)90 TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
91 GaugeMetric metric;
92 metric.set_id(metricId);
93 metric.set_bucket(ONE_MINUTE);
94 metric.mutable_gauge_fields_filter()->set_include_all(false);
95 metric.set_max_pull_delay_sec(INT_MAX);
96 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
97 gaugeFieldMatcher->set_field(tagId);
98 gaugeFieldMatcher->add_child()->set_field(1);
99 gaugeFieldMatcher->add_child()->set_field(3);
100
101 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
102
103 UidMap uidMap;
104 SimpleAtomMatcher atomMatcher;
105 atomMatcher.set_atom_id(tagId);
106 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
107 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
108
109 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
110 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
111 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
112 EXPECT_CALL(*pullerManager, Pull(tagId, _))
113 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
114 data->clear();
115 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
116 event->write(3);
117 event->write("some value");
118 event->write(11);
119 event->init();
120 data->push_back(event);
121 return true;
122 }));
123
124 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
125 logEventMatcherIndex, eventMatcherWizard,
126 tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
127 pullerManager);
128
129 gaugeProducer.prepareFirstBucket();
130
131 vector<shared_ptr<LogEvent>> allData;
132 allData.clear();
133 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
134 event->write(10);
135 event->write("some value");
136 event->write(11);
137 event->init();
138 allData.push_back(event);
139
140 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
141 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
142 auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
143 EXPECT_EQ(INT, it->mValue.getType());
144 EXPECT_EQ(10, it->mValue.int_value);
145 it++;
146 EXPECT_EQ(11, it->mValue.int_value);
147 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
148 EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms
149 .front().mFields->begin()->mValue.int_value);
150
151 allData.clear();
152 std::shared_ptr<LogEvent> event2 = std::make_shared<LogEvent>(tagId, bucket3StartTimeNs + 10);
153 event2->write(24);
154 event2->write("some value");
155 event2->write(25);
156 event2->init();
157 allData.push_back(event2);
158 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
159 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
160 it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
161 EXPECT_EQ(INT, it->mValue.getType());
162 EXPECT_EQ(24, it->mValue.int_value);
163 it++;
164 EXPECT_EQ(INT, it->mValue.getType());
165 EXPECT_EQ(25, it->mValue.int_value);
166 // One dimension.
167 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
168 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
169 it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
170 EXPECT_EQ(INT, it->mValue.getType());
171 EXPECT_EQ(10L, it->mValue.int_value);
172 it++;
173 EXPECT_EQ(INT, it->mValue.getType());
174 EXPECT_EQ(11L, it->mValue.int_value);
175
176 gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
177 EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
178 // One dimension.
179 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
180 EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
181 it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
182 EXPECT_EQ(INT, it->mValue.getType());
183 EXPECT_EQ(24L, it->mValue.int_value);
184 it++;
185 EXPECT_EQ(INT, it->mValue.getType());
186 EXPECT_EQ(25L, it->mValue.int_value);
187 }
188
TEST(GaugeMetricProducerTest,TestPushedEventsWithUpgrade)189 TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
190 sp<AlarmMonitor> alarmMonitor;
191 GaugeMetric metric;
192 metric.set_id(metricId);
193 metric.set_bucket(ONE_MINUTE);
194 metric.mutable_gauge_fields_filter()->set_include_all(true);
195
196 Alert alert;
197 alert.set_id(101);
198 alert.set_metric_id(metricId);
199 alert.set_trigger_if_sum_gt(25);
200 alert.set_num_buckets(100);
201 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
202 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
203
204 UidMap uidMap;
205 SimpleAtomMatcher atomMatcher;
206 atomMatcher.set_atom_id(tagId);
207 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
208 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
209
210 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
211 logEventMatcherIndex, eventMatcherWizard,
212 -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
213 bucketStartTimeNs, pullerManager);
214 gaugeProducer.prepareFirstBucket();
215
216 sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
217 EXPECT_TRUE(anomalyTracker != nullptr);
218
219 shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
220 event1->write(1);
221 event1->write(10);
222 event1->init();
223 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
224 EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
225
226 gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
227 EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
228 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
229 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
230 EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
231 // Partial buckets are not sent to anomaly tracker.
232 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
233
234 // Create an event in the same partial bucket.
235 shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
236 event2->write(1);
237 event2->write(10);
238 event2->init();
239 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
240 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
241 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
242 EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
243 // Partial buckets are not sent to anomaly tracker.
244 EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
245
246 // Next event should trigger creation of new bucket and send previous full bucket to anomaly
247 // tracker.
248 shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
249 event3->write(1);
250 event3->write(10);
251 event3->init();
252 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
253 EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
254 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
255 EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
256 EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
257
258 // Next event should trigger creation of new bucket.
259 shared_ptr<LogEvent> event4 =
260 make_shared<LogEvent>(tagId, bucketStartTimeNs + 125 * NS_PER_SEC);
261 event4->write(1);
262 event4->write(10);
263 event4->init();
264 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
265 EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
266 EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
267 EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
268 }
269
TEST(GaugeMetricProducerTest,TestPulledWithUpgrade)270 TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
271 GaugeMetric metric;
272 metric.set_id(metricId);
273 metric.set_bucket(ONE_MINUTE);
274 metric.set_max_pull_delay_sec(INT_MAX);
275 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
276 gaugeFieldMatcher->set_field(tagId);
277 gaugeFieldMatcher->add_child()->set_field(2);
278
279 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
280
281 UidMap uidMap;
282 SimpleAtomMatcher atomMatcher;
283 atomMatcher.set_atom_id(tagId);
284 sp<EventMatcherWizard> eventMatcherWizard =
285 new EventMatcherWizard({new SimpleLogMatchingTracker(
286 atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
287
288 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
289 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
290 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
291 EXPECT_CALL(*pullerManager, Pull(tagId, _))
292 .WillOnce(Return(false))
293 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
294 data->clear();
295 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs);
296 event->write("some value");
297 event->write(2);
298 event->init();
299 data->push_back(event);
300 return true;
301 }));
302
303 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
304 logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
305 bucketStartTimeNs, bucketStartTimeNs, pullerManager);
306 gaugeProducer.prepareFirstBucket();
307
308 vector<shared_ptr<LogEvent>> allData;
309 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
310 event->write("some value");
311 event->write(1);
312 event->init();
313 allData.push_back(event);
314 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
315 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
316 EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
317 ->second.front()
318 .mFields->begin()
319 ->mValue.int_value);
320
321 gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
322 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
323 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
324 EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
325 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
326 EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
327 ->second.front()
328 .mFields->begin()
329 ->mValue.int_value);
330
331 allData.clear();
332 event = make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 1);
333 event->write("some value");
334 event->write(3);
335 event->init();
336 allData.push_back(event);
337 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
338 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
339 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
340 EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
341 ->second.front()
342 .mFields->begin()
343 ->mValue.int_value);
344 }
345
TEST(GaugeMetricProducerTest,TestPulledWithAppUpgradeDisabled)346 TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
347 GaugeMetric metric;
348 metric.set_id(metricId);
349 metric.set_bucket(ONE_MINUTE);
350 metric.set_max_pull_delay_sec(INT_MAX);
351 metric.set_split_bucket_for_app_upgrade(false);
352 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
353 gaugeFieldMatcher->set_field(tagId);
354 gaugeFieldMatcher->add_child()->set_field(2);
355
356 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
357
358 UidMap uidMap;
359 SimpleAtomMatcher atomMatcher;
360 atomMatcher.set_atom_id(tagId);
361 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
362 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
363
364 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
365 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
366 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
367 EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
368
369 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
370 logEventMatcherIndex, eventMatcherWizard,
371 tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
372 pullerManager);
373 gaugeProducer.prepareFirstBucket();
374
375 vector<shared_ptr<LogEvent>> allData;
376 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
377 event->write("some value");
378 event->write(1);
379 event->init();
380 allData.push_back(event);
381 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
382 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
383 EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
384 ->second.front()
385 .mFields->begin()
386 ->mValue.int_value);
387
388 gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
389 EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
390 EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
391 EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
392 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
393 EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
394 ->second.front()
395 .mFields->begin()
396 ->mValue.int_value);
397 }
398
TEST(GaugeMetricProducerTest,TestPulledEventsWithCondition)399 TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
400 GaugeMetric metric;
401 metric.set_id(metricId);
402 metric.set_bucket(ONE_MINUTE);
403 metric.set_max_pull_delay_sec(INT_MAX);
404 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
405 gaugeFieldMatcher->set_field(tagId);
406 gaugeFieldMatcher->add_child()->set_field(2);
407 metric.set_condition(StringToId("SCREEN_ON"));
408
409 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
410
411 UidMap uidMap;
412 SimpleAtomMatcher atomMatcher;
413 atomMatcher.set_atom_id(tagId);
414 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
415 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
416
417 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
418 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
419 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
420 EXPECT_CALL(*pullerManager, Pull(tagId, _))
421 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
422 data->clear();
423 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
424 event->write("some value");
425 event->write(100);
426 event->init();
427 data->push_back(event);
428 return true;
429 }));
430
431 GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
432 logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
433 bucketStartTimeNs, bucketStartTimeNs, pullerManager);
434 gaugeProducer.prepareFirstBucket();
435
436 gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
437 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
438 EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
439 ->second.front()
440 .mFields->begin()
441 ->mValue.int_value);
442 EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
443
444 vector<shared_ptr<LogEvent>> allData;
445 allData.clear();
446 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
447 event->write("some value");
448 event->write(110);
449 event->init();
450 allData.push_back(event);
451 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
452
453 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
454 EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
455 ->second.front()
456 .mFields->begin()
457 ->mValue.int_value);
458 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
459 EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
460 ->second.back()
461 .mGaugeAtoms.front()
462 .mFields->begin()
463 ->mValue.int_value);
464
465 gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
466 gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
467 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
468 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
469 EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
470 ->second.back()
471 .mGaugeAtoms.front()
472 .mFields->begin()
473 ->mValue.int_value);
474 }
475
TEST(GaugeMetricProducerTest,TestPulledEventsWithSlicedCondition)476 TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
477 const int conditionTag = 65;
478 GaugeMetric metric;
479 metric.set_id(1111111);
480 metric.set_bucket(ONE_MINUTE);
481 metric.mutable_gauge_fields_filter()->set_include_all(true);
482 metric.set_condition(StringToId("APP_DIED"));
483 metric.set_max_pull_delay_sec(INT_MAX);
484 auto dim = metric.mutable_dimensions_in_what();
485 dim->set_field(tagId);
486 dim->add_child()->set_field(1);
487
488 dim = metric.mutable_dimensions_in_condition();
489 dim->set_field(conditionTag);
490 dim->add_child()->set_field(1);
491
492 UidMap uidMap;
493 SimpleAtomMatcher atomMatcher;
494 atomMatcher.set_atom_id(tagId);
495 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
496 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
497
498 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
499 EXPECT_CALL(*wizard, query(_, _, _, _, _, _))
500 .WillRepeatedly(
501 Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
502 const vector<Matcher>& dimensionFields, const bool isSubsetDim,
503 const bool isPartialLink,
504 std::unordered_set<HashableDimensionKey>* dimensionKeySet) {
505 dimensionKeySet->clear();
506 int pos[] = {1, 0, 0};
507 Field f(conditionTag, pos, 0);
508 HashableDimensionKey key;
509 key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
510 dimensionKeySet->insert(key);
511
512 return ConditionState::kTrue;
513 }));
514
515 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
516 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
517 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
518 EXPECT_CALL(*pullerManager, Pull(tagId, _))
519 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
520 data->clear();
521 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
522 event->write(1000);
523 event->write(100);
524 event->init();
525 data->push_back(event);
526 return true;
527 }));
528
529 GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
530 logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
531 bucketStartTimeNs, bucketStartTimeNs, pullerManager);
532 gaugeProducer.prepareFirstBucket();
533
534 gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
535
536 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
537 const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
538 EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
539 EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
540
541 EXPECT_EQ(1UL, key.getDimensionKeyInCondition().getValues().size());
542 EXPECT_EQ(1000000, key.getDimensionKeyInCondition().getValues()[0].mValue.int_value);
543
544 EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
545
546 vector<shared_ptr<LogEvent>> allData;
547 allData.clear();
548 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
549 event->write(1000);
550 event->write(110);
551 event->init();
552 allData.push_back(event);
553 gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
554
555 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
556 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
557 }
558
TEST(GaugeMetricProducerTest,TestPulledEventsAnomalyDetection)559 TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
560 sp<AlarmMonitor> alarmMonitor;
561 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
562
563 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
564 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
565 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
566 EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
567
568 GaugeMetric metric;
569 metric.set_id(metricId);
570 metric.set_bucket(ONE_MINUTE);
571 metric.set_max_pull_delay_sec(INT_MAX);
572 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
573 gaugeFieldMatcher->set_field(tagId);
574 gaugeFieldMatcher->add_child()->set_field(2);
575
576 UidMap uidMap;
577 SimpleAtomMatcher atomMatcher;
578 atomMatcher.set_atom_id(tagId);
579 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
580 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
581
582 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
583 logEventMatcherIndex, eventMatcherWizard,
584 tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
585 pullerManager);
586 gaugeProducer.prepareFirstBucket();
587
588 Alert alert;
589 alert.set_id(101);
590 alert.set_metric_id(metricId);
591 alert.set_trigger_if_sum_gt(25);
592 alert.set_num_buckets(2);
593 const int32_t refPeriodSec = 60;
594 alert.set_refractory_period_secs(refPeriodSec);
595 sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
596
597 int tagId = 1;
598 std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
599 event1->write("some value");
600 event1->write(13);
601 event1->init();
602
603 gaugeProducer.onDataPulled({event1}, /** succeed */ true, bucketStartTimeNs);
604 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
605 EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
606 ->second.front()
607 .mFields->begin()
608 ->mValue.int_value);
609 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
610
611 std::shared_ptr<LogEvent> event2 =
612 std::make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 20);
613 event2->write("some value");
614 event2->write(15);
615 event2->init();
616
617 gaugeProducer.onDataPulled({event2}, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
618 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
619 EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
620 ->second.front()
621 .mFields->begin()
622 ->mValue.int_value);
623 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
624 std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
625
626 std::shared_ptr<LogEvent> event3 =
627 std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
628 event3->write("some value");
629 event3->write(26);
630 event3->init();
631
632 gaugeProducer.onDataPulled({event3}, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
633 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
634 EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
635 ->second.front()
636 .mFields->begin()
637 ->mValue.int_value);
638 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
639 std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
640
641 // The event4 does not have the gauge field. Thus the current bucket value is 0.
642 std::shared_ptr<LogEvent> event4 =
643 std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10);
644 event4->write("some value");
645 event4->init();
646 gaugeProducer.onDataPulled({event4}, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
647 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
648 EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
649 }
650
TEST(GaugeMetricProducerTest,TestPullOnTrigger)651 TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
652 GaugeMetric metric;
653 metric.set_id(metricId);
654 metric.set_bucket(ONE_MINUTE);
655 metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
656 metric.mutable_gauge_fields_filter()->set_include_all(false);
657 metric.set_max_pull_delay_sec(INT_MAX);
658 auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
659 gaugeFieldMatcher->set_field(tagId);
660 gaugeFieldMatcher->add_child()->set_field(1);
661
662 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
663
664 UidMap uidMap;
665 SimpleAtomMatcher atomMatcher;
666 atomMatcher.set_atom_id(tagId);
667 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
668 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
669
670 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
671 EXPECT_CALL(*pullerManager, Pull(tagId, _))
672 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
673 data->clear();
674 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
675 event->write(4);
676 event->init();
677 data->push_back(event);
678 return true;
679 }))
680 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
681 data->clear();
682 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
683 event->write(5);
684 event->init();
685 data->push_back(event);
686 return true;
687 }))
688 .WillOnce(Return(true));
689
690 int triggerId = 5;
691 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
692 logEventMatcherIndex, eventMatcherWizard,
693 tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
694 pullerManager);
695 gaugeProducer.prepareFirstBucket();
696
697 vector<shared_ptr<LogEvent>> allData;
698
699 EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
700 LogEvent trigger(triggerId, bucketStartTimeNs + 10);
701 trigger.init();
702 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
703 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
704 trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
705 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
706 EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
707 trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1);
708 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
709
710 EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
711 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
712 EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
713 ->second.back()
714 .mGaugeAtoms[0]
715 .mFields->begin()
716 ->mValue.int_value);
717 EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
718 ->second.back()
719 .mGaugeAtoms[1]
720 .mFields->begin()
721 ->mValue.int_value);
722 }
723
TEST(GaugeMetricProducerTest,TestRemoveDimensionInOutput)724 TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
725 GaugeMetric metric;
726 metric.set_id(metricId);
727 metric.set_bucket(ONE_MINUTE);
728 metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
729 metric.mutable_gauge_fields_filter()->set_include_all(true);
730 metric.set_max_pull_delay_sec(INT_MAX);
731 auto dimensionMatcher = metric.mutable_dimensions_in_what();
732 // use field 1 as dimension.
733 dimensionMatcher->set_field(tagId);
734 dimensionMatcher->add_child()->set_field(1);
735
736 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
737
738 UidMap uidMap;
739 SimpleAtomMatcher atomMatcher;
740 atomMatcher.set_atom_id(tagId);
741 sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
742 new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
743
744 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
745 EXPECT_CALL(*pullerManager, Pull(tagId, _))
746 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
747 data->clear();
748 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3);
749 event->write(3);
750 event->write(4);
751 event->init();
752 data->push_back(event);
753 return true;
754 }))
755 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
756 data->clear();
757 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
758 event->write(4);
759 event->write(5);
760 event->init();
761 data->push_back(event);
762 return true;
763 }))
764 .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
765 data->clear();
766 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
767 event->write(4);
768 event->write(6);
769 event->init();
770 data->push_back(event);
771 return true;
772 }))
773 .WillOnce(Return(true));
774
775 int triggerId = 5;
776 GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
777 logEventMatcherIndex, eventMatcherWizard,
778 tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
779 pullerManager);
780 gaugeProducer.prepareFirstBucket();
781
782 vector<shared_ptr<LogEvent>> allData;
783
784 LogEvent trigger(triggerId, bucketStartTimeNs + 3);
785 trigger.init();
786 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
787 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
788 trigger.setElapsedTimestampNs(bucketStartTimeNs + 10);
789 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
790 EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
791 EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
792 trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
793 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
794 EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
795 trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1);
796 gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
797
798 EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
799 auto bucketIt = gaugeProducer.mPastBuckets.begin();
800 EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
801 EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
802 EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
803 bucketIt++;
804 EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
805 EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
806 EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
807 EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
808 }
809
810 } // namespace statsd
811 } // namespace os
812 } // namespace android
813 #else
814 GTEST_LOG_(INFO) << "This test does nothing.\n";
815 #endif
816