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