• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ValueMetricProducer.h"
16 #include "src/stats_log_util.h"
17 #include "metrics_test_helper.h"
18 #include "tests/statsd_test_util.h"
19 
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include <math.h>
23 #include <stdio.h>
24 #include <vector>
25 
26 using namespace testing;
27 using android::sp;
28 using std::make_shared;
29 using std::set;
30 using std::shared_ptr;
31 using std::unordered_map;
32 using std::vector;
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 = 10000000000;
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 bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs;
49 const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
50 const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
51 
52 /*
53  * Tests pulled atoms with no conditions
54  */
TEST(ValueMetricProducerTest,TestNonDimensionalEvents)55 TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
56     ValueMetric metric;
57     metric.set_id(metricId);
58     metric.set_bucket(ONE_MINUTE);
59     metric.mutable_value_field()->set_field(tagId);
60     metric.mutable_value_field()->add_child()->set_field(2);
61 
62     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
63     // TODO: pending refactor of StatsPullerManager
64     // For now we still need this so that it doesn't do real pulling.
65     shared_ptr<MockStatsPullerManager> pullerManager =
66             make_shared<StrictMock<MockStatsPullerManager>>();
67     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
68     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
69 
70     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
71                                       tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
72     valueProducer.setBucketSize(60 * NS_PER_SEC);
73 
74     vector<shared_ptr<LogEvent>> allData;
75     allData.clear();
76     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
77     event->write(tagId);
78     event->write(11);
79     event->init();
80     allData.push_back(event);
81 
82     valueProducer.onDataPulled(allData);
83     // has one slice
84     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
85     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
86     valueProducer.setBucketSize(60 * NS_PER_SEC);
87 
88     // startUpdated:true tainted:0 sum:0 start:11
89     EXPECT_EQ(true, curInterval.startUpdated);
90     EXPECT_EQ(0, curInterval.tainted);
91     EXPECT_EQ(0, curInterval.sum);
92     EXPECT_EQ(11, curInterval.start);
93     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
94 
95     allData.clear();
96     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
97     event->write(tagId);
98     event->write(23);
99     event->init();
100     allData.push_back(event);
101     valueProducer.onDataPulled(allData);
102     // has one slice
103     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
104     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
105     // tartUpdated:false tainted:0 sum:12
106     EXPECT_EQ(true, curInterval.startUpdated);
107     EXPECT_EQ(0, curInterval.tainted);
108     EXPECT_EQ(0, curInterval.sum);
109     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
110     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
111     EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValue);
112 
113     allData.clear();
114     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
115     event->write(tagId);
116     event->write(36);
117     event->init();
118     allData.push_back(event);
119     valueProducer.onDataPulled(allData);
120     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
121     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
122     // startUpdated:false tainted:0 sum:12
123     EXPECT_EQ(true, curInterval.startUpdated);
124     EXPECT_EQ(0, curInterval.tainted);
125     EXPECT_EQ(0, curInterval.sum);
126     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
127     EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
128     EXPECT_EQ(13, valueProducer.mPastBuckets.begin()->second.back().mValue);
129 }
130 
131 /*
132  * Tests pulled atoms with no conditions and take absolute value after reset
133  */
TEST(ValueMetricProducerTest,TestPulledEventsTakeAbsoluteValueOnReset)134 TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
135     ValueMetric metric;
136     metric.set_id(metricId);
137     metric.set_bucket(ONE_MINUTE);
138     metric.mutable_value_field()->set_field(tagId);
139     metric.mutable_value_field()->add_child()->set_field(2);
140     metric.set_use_absolute_value_on_reset(true);
141 
142     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
143     shared_ptr<MockStatsPullerManager> pullerManager =
144             make_shared<StrictMock<MockStatsPullerManager>>();
145     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
146     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
147 
148     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
149                                       tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
150     valueProducer.setBucketSize(60 * NS_PER_SEC);
151 
152     vector<shared_ptr<LogEvent>> allData;
153     allData.clear();
154     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
155     event->write(tagId);
156     event->write(11);
157     event->init();
158     allData.push_back(event);
159 
160     valueProducer.onDataPulled(allData);
161     // has one slice
162     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
163     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
164     valueProducer.setBucketSize(60 * NS_PER_SEC);
165 
166     EXPECT_EQ(true, curInterval.startUpdated);
167     EXPECT_EQ(0, curInterval.tainted);
168     EXPECT_EQ(0, curInterval.sum);
169     EXPECT_EQ(11, curInterval.start);
170     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
171 
172     allData.clear();
173     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
174     event->write(tagId);
175     event->write(10);
176     event->init();
177     allData.push_back(event);
178     valueProducer.onDataPulled(allData);
179     // has one slice
180     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
181     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
182     EXPECT_EQ(true, curInterval.startUpdated);
183     EXPECT_EQ(0, curInterval.tainted);
184     EXPECT_EQ(0, curInterval.sum);
185     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
186     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
187     EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValue);
188 
189     allData.clear();
190     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
191     event->write(tagId);
192     event->write(36);
193     event->init();
194     allData.push_back(event);
195     valueProducer.onDataPulled(allData);
196     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
197     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
198     EXPECT_EQ(true, curInterval.startUpdated);
199     EXPECT_EQ(0, curInterval.tainted);
200     EXPECT_EQ(0, curInterval.sum);
201     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
202     EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
203     EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValue);
204 }
205 
206 /*
207  * Tests pulled atoms with no conditions and take zero value after reset
208  */
TEST(ValueMetricProducerTest,TestPulledEventsTakeZeroOnReset)209 TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
210     ValueMetric metric;
211     metric.set_id(metricId);
212     metric.set_bucket(ONE_MINUTE);
213     metric.mutable_value_field()->set_field(tagId);
214     metric.mutable_value_field()->add_child()->set_field(2);
215 
216     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
217     shared_ptr<MockStatsPullerManager> pullerManager =
218             make_shared<StrictMock<MockStatsPullerManager>>();
219     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
220     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
221 
222     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
223                                       tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
224     valueProducer.setBucketSize(60 * NS_PER_SEC);
225 
226     vector<shared_ptr<LogEvent>> allData;
227     allData.clear();
228     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
229     event->write(tagId);
230     event->write(11);
231     event->init();
232     allData.push_back(event);
233 
234     valueProducer.onDataPulled(allData);
235     // has one slice
236     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
237     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
238     valueProducer.setBucketSize(60 * NS_PER_SEC);
239 
240     EXPECT_EQ(true, curInterval.startUpdated);
241     EXPECT_EQ(0, curInterval.tainted);
242     EXPECT_EQ(0, curInterval.sum);
243     EXPECT_EQ(11, curInterval.start);
244     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
245 
246     allData.clear();
247     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
248     event->write(tagId);
249     event->write(10);
250     event->init();
251     allData.push_back(event);
252     valueProducer.onDataPulled(allData);
253     // has one slice
254     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
255     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
256     EXPECT_EQ(true, curInterval.startUpdated);
257     EXPECT_EQ(0, curInterval.tainted);
258     EXPECT_EQ(0, curInterval.sum);
259     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
260 
261     allData.clear();
262     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
263     event->write(tagId);
264     event->write(36);
265     event->init();
266     allData.push_back(event);
267     valueProducer.onDataPulled(allData);
268     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
269     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
270     EXPECT_EQ(true, curInterval.startUpdated);
271     EXPECT_EQ(0, curInterval.tainted);
272     EXPECT_EQ(0, curInterval.sum);
273     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
274     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
275     EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValue);
276 }
277 
278 /*
279  * Test pulled event with non sliced condition.
280  */
TEST(ValueMetricProducerTest,TestEventsWithNonSlicedCondition)281 TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
282     ValueMetric metric;
283     metric.set_id(metricId);
284     metric.set_bucket(ONE_MINUTE);
285     metric.mutable_value_field()->set_field(tagId);
286     metric.mutable_value_field()->add_child()->set_field(2);
287     metric.set_condition(StringToId("SCREEN_ON"));
288 
289     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
290     shared_ptr<MockStatsPullerManager> pullerManager =
291             make_shared<StrictMock<MockStatsPullerManager>>();
292     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
293     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
294 
295     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
296             .WillOnce(Invoke([](int tagId, int64_t timeNs,
297                                 vector<std::shared_ptr<LogEvent>>* data) {
298                 data->clear();
299                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
300                 event->write(tagId);
301                 event->write(100);
302                 event->init();
303                 data->push_back(event);
304                 return true;
305             }))
306             .WillOnce(Invoke([](int tagId, int64_t timeNs,
307                                 vector<std::shared_ptr<LogEvent>>* data) {
308                 data->clear();
309                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
310                 event->write(tagId);
311                 event->write(120);
312                 event->init();
313                 data->push_back(event);
314                 return true;
315             }));
316 
317     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
318                                       bucketStartTimeNs, pullerManager);
319     valueProducer.setBucketSize(60 * NS_PER_SEC);
320     valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
321 
322     // has one slice
323     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
324     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
325     // startUpdated:false tainted:0 sum:0 start:100
326     EXPECT_EQ(100, curInterval.start);
327     EXPECT_EQ(true, curInterval.startUpdated);
328     EXPECT_EQ(0, curInterval.tainted);
329     EXPECT_EQ(0, curInterval.sum);
330     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
331 
332     vector<shared_ptr<LogEvent>> allData;
333     allData.clear();
334     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
335     event->write(1);
336     event->write(110);
337     event->init();
338     allData.push_back(event);
339     valueProducer.onDataPulled(allData);
340 
341     // has one slice
342     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
343     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
344     // startUpdated:false tainted:0 sum:0 start:110
345     EXPECT_EQ(110, curInterval.start);
346     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
347     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
348     EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValue);
349 
350     valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
351 
352     // has one slice
353     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
354     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
355     // startUpdated:false tainted:0 sum:0 start:110
356     EXPECT_EQ(10, curInterval.sum);
357     EXPECT_EQ(false, curInterval.startUpdated);
358 }
359 
TEST(ValueMetricProducerTest,TestPushedEventsWithUpgrade)360 TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
361     ValueMetric metric;
362     metric.set_id(metricId);
363     metric.set_bucket(ONE_MINUTE);
364     metric.mutable_value_field()->set_field(tagId);
365     metric.mutable_value_field()->add_child()->set_field(2);
366 
367     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
368     shared_ptr<MockStatsPullerManager> pullerManager =
369             make_shared<StrictMock<MockStatsPullerManager>>();
370     ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
371                                       bucketStartTimeNs, pullerManager);
372     valueProducer.setBucketSize(60 * NS_PER_SEC);
373 
374     shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
375     event1->write(1);
376     event1->write(10);
377     event1->init();
378     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
379     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
380 
381     valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
382     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
383     EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
384 
385     shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
386     event2->write(1);
387     event2->write(10);
388     event2->init();
389     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
390     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
391     EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
392 
393     // Next value should create a new bucket.
394     shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
395     event3->write(1);
396     event3->write(10);
397     event3->init();
398     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
399     EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
400     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, valueProducer.mCurrentBucketStartTimeNs);
401 }
402 
TEST(ValueMetricProducerTest,TestPulledValueWithUpgrade)403 TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
404     ValueMetric metric;
405     metric.set_id(metricId);
406     metric.set_bucket(ONE_MINUTE);
407     metric.mutable_value_field()->set_field(tagId);
408     metric.mutable_value_field()->add_child()->set_field(2);
409 
410     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
411     shared_ptr<MockStatsPullerManager> pullerManager =
412             make_shared<StrictMock<MockStatsPullerManager>>();
413     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
414     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
415     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
416             .WillOnce(Invoke([](int tagId, int64_t timeNs,
417                                 vector<std::shared_ptr<LogEvent>>* data) {
418                 data->clear();
419                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
420                 event->write(tagId);
421                 event->write(120);
422                 event->init();
423                 data->push_back(event);
424                 return true;
425             }));
426     ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, tagId, bucketStartTimeNs,
427                                       bucketStartTimeNs, pullerManager);
428     valueProducer.setBucketSize(60 * NS_PER_SEC);
429 
430     vector<shared_ptr<LogEvent>> allData;
431     allData.clear();
432     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
433     event->write(tagId);
434     event->write(100);
435     event->init();
436     allData.push_back(event);
437 
438     valueProducer.onDataPulled(allData);
439     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
440 
441     valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
442     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
443     EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
444     EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValue);
445 
446     allData.clear();
447     event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
448     event->write(tagId);
449     event->write(150);
450     event->init();
451     allData.push_back(event);
452     valueProducer.onDataPulled(allData);
453     EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
454     EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
455     EXPECT_EQ(30L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mValue);
456 }
457 
TEST(ValueMetricProducerTest,TestPulledValueWithUpgradeWhileConditionFalse)458 TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
459     ValueMetric metric;
460     metric.set_id(metricId);
461     metric.set_bucket(ONE_MINUTE);
462     metric.mutable_value_field()->set_field(tagId);
463     metric.mutable_value_field()->add_child()->set_field(2);
464     metric.set_condition(StringToId("SCREEN_ON"));
465 
466     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
467     shared_ptr<MockStatsPullerManager> pullerManager =
468             make_shared<StrictMock<MockStatsPullerManager>>();
469     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
470     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
471     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
472             .WillOnce(Invoke([](int tagId, int64_t timeNs,
473                                 vector<std::shared_ptr<LogEvent>>* data) {
474                 data->clear();
475                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
476                 event->write(tagId);
477                 event->write(100);
478                 event->init();
479                 data->push_back(event);
480                 return true;
481             }))
482             .WillOnce(Invoke([](int tagId, int64_t timeNs,
483                                 vector<std::shared_ptr<LogEvent>>* data) {
484                 data->clear();
485                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
486                 event->write(tagId);
487                 event->write(120);
488                 event->init();
489                 data->push_back(event);
490                 return true;
491             }));
492     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
493                                       bucketStartTimeNs, pullerManager);
494     valueProducer.setBucketSize(60 * NS_PER_SEC);
495     valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
496 
497     valueProducer.onConditionChanged(false, bucket2StartTimeNs-100);
498     EXPECT_FALSE(valueProducer.mCondition);
499 
500     valueProducer.notifyAppUpgrade(bucket2StartTimeNs-50, "ANY.APP", 1, 1);
501     // Expect one full buckets already done and starting a partial bucket.
502     EXPECT_EQ(bucket2StartTimeNs-50, valueProducer.mCurrentBucketStartTimeNs);
503     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
504     EXPECT_EQ(bucketStartTimeNs, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
505     EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValue);
506     EXPECT_FALSE(valueProducer.mCondition);
507 }
508 
TEST(ValueMetricProducerTest,TestPushedEventsWithoutCondition)509 TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
510     ValueMetric metric;
511     metric.set_id(metricId);
512     metric.set_bucket(ONE_MINUTE);
513     metric.mutable_value_field()->set_field(tagId);
514     metric.mutable_value_field()->add_child()->set_field(2);
515 
516     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
517     shared_ptr<MockStatsPullerManager> pullerManager =
518             make_shared<StrictMock<MockStatsPullerManager>>();
519 
520     ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
521                                       bucketStartTimeNs, pullerManager);
522     valueProducer.setBucketSize(60 * NS_PER_SEC);
523 
524     shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
525     event1->write(1);
526     event1->write(10);
527     event1->init();
528     shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
529     event2->write(1);
530     event2->write(20);
531     event2->init();
532     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
533     // has one slice
534     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
535     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
536     EXPECT_EQ(10, curInterval.sum);
537 
538     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
539 
540     // has one slice
541     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
542     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
543     EXPECT_EQ(30, curInterval.sum);
544 
545     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
546     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
547     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
548     EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().mValue);
549 }
550 
TEST(ValueMetricProducerTest,TestPushedEventsWithCondition)551 TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
552     ValueMetric metric;
553     metric.set_id(metricId);
554     metric.set_bucket(ONE_MINUTE);
555     metric.mutable_value_field()->set_field(tagId);
556     metric.mutable_value_field()->add_child()->set_field(2);
557 
558     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
559     shared_ptr<MockStatsPullerManager> pullerManager =
560             make_shared<StrictMock<MockStatsPullerManager>>();
561 
562     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, -1, bucketStartTimeNs,
563                                       bucketStartTimeNs, pullerManager);
564     valueProducer.setBucketSize(60 * NS_PER_SEC);
565 
566     shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
567     event1->write(1);
568     event1->write(10);
569     event1->init();
570     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
571     // has 1 slice
572     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
573     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
574     EXPECT_EQ(false, curInterval.hasValue);
575 
576     valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
577     shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
578     event2->write(1);
579     event2->write(20);
580     event2->init();
581     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
582 
583     // has one slice
584     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
585     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
586     EXPECT_EQ(20, curInterval.sum);
587 
588     shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 30);
589     event3->write(1);
590     event3->write(30);
591     event3->init();
592     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
593 
594     // has one slice
595     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
596     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
597     EXPECT_EQ(50, curInterval.sum);
598 
599     valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
600     shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 40);
601     event4->write(1);
602     event4->write(40);
603     event4->init();
604     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
605 
606     // has one slice
607     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
608     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
609     EXPECT_EQ(50, curInterval.sum);
610 
611     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
612     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
613     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
614     EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().mValue);
615 }
616 
TEST(ValueMetricProducerTest,TestAnomalyDetection)617 TEST(ValueMetricProducerTest, TestAnomalyDetection) {
618     sp<AlarmMonitor> alarmMonitor;
619     Alert alert;
620     alert.set_id(101);
621     alert.set_metric_id(metricId);
622     alert.set_trigger_if_sum_gt(130);
623     alert.set_num_buckets(2);
624     const int32_t refPeriodSec = 3;
625     alert.set_refractory_period_secs(refPeriodSec);
626 
627     ValueMetric metric;
628     metric.set_id(metricId);
629     metric.set_bucket(ONE_MINUTE);
630     metric.mutable_value_field()->set_field(tagId);
631     metric.mutable_value_field()->add_child()->set_field(2);
632 
633     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
634     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
635                                       -1 /*not pulled*/, bucketStartTimeNs, bucketStartTimeNs);
636     valueProducer.setBucketSize(60 * NS_PER_SEC);
637 
638     sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
639 
640 
641     shared_ptr<LogEvent> event1
642             = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1 * NS_PER_SEC);
643     event1->write(161);
644     event1->write(10); // value of interest
645     event1->init();
646     shared_ptr<LogEvent> event2
647             = make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 + NS_PER_SEC);
648     event2->write(162);
649     event2->write(20); // value of interest
650     event2->init();
651     shared_ptr<LogEvent> event3
652             = make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC);
653     event3->write(163);
654     event3->write(130); // value of interest
655     event3->init();
656     shared_ptr<LogEvent> event4
657             = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1 * NS_PER_SEC);
658     event4->write(35);
659     event4->write(1); // value of interest
660     event4->init();
661     shared_ptr<LogEvent> event5
662             = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
663     event5->write(45);
664     event5->write(150); // value of interest
665     event5->init();
666     shared_ptr<LogEvent> event6
667             = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10 * NS_PER_SEC);
668     event6->write(25);
669     event6->write(160); // value of interest
670     event6->init();
671 
672     // Two events in bucket #0.
673     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
674     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
675     // Value sum == 30 <= 130.
676     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
677 
678     // One event in bucket #2. No alarm as bucket #0 is trashed out.
679     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
680     // Value sum == 130 <= 130.
681     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
682 
683     // Three events in bucket #3.
684     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
685     // Anomaly at event 4 since Value sum == 131 > 130!
686     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
687             std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
688     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
689     // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
690     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
691             std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
692 
693     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
694     // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
695     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
696             std::ceil(1.0 * event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
697 }
698 
699 // Test value metric no condition, the pull on bucket boundary come in time and too late
TEST(ValueMetricProducerTest,TestBucketBoundaryNoCondition)700 TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
701     ValueMetric metric;
702     metric.set_id(metricId);
703     metric.set_bucket(ONE_MINUTE);
704     metric.mutable_value_field()->set_field(tagId);
705     metric.mutable_value_field()->add_child()->set_field(2);
706 
707     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
708     shared_ptr<MockStatsPullerManager> pullerManager =
709             make_shared<StrictMock<MockStatsPullerManager>>();
710     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
711     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
712 
713     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
714                                       tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
715     valueProducer.setBucketSize(60 * NS_PER_SEC);
716 
717     vector<shared_ptr<LogEvent>> allData;
718     // pull 1
719     allData.clear();
720     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
721     event->write(tagId);
722     event->write(11);
723     event->init();
724     allData.push_back(event);
725 
726     valueProducer.onDataPulled(allData);
727     // has one slice
728     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
729     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
730 
731     // startUpdated:true tainted:0 sum:0 start:11
732     EXPECT_EQ(true, curInterval.startUpdated);
733     EXPECT_EQ(0, curInterval.tainted);
734     EXPECT_EQ(0, curInterval.sum);
735     EXPECT_EQ(11, curInterval.start);
736     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
737 
738     // pull 2 at correct time
739     allData.clear();
740     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
741     event->write(tagId);
742     event->write(23);
743     event->init();
744     allData.push_back(event);
745     valueProducer.onDataPulled(allData);
746     // has one slice
747     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
748     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
749     // tartUpdated:false tainted:0 sum:12
750     EXPECT_EQ(true, curInterval.startUpdated);
751     EXPECT_EQ(0, curInterval.tainted);
752     EXPECT_EQ(0, curInterval.sum);
753     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
754     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
755     EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValue);
756 
757     // pull 3 come late.
758     // The previous bucket gets closed with error. (Has start value 23, no ending)
759     // Another bucket gets closed with error. (No start, but ending with 36)
760     // The new bucket is back to normal.
761     allData.clear();
762     event = make_shared<LogEvent>(tagId, bucket6StartTimeNs + 1);
763     event->write(tagId);
764     event->write(36);
765     event->init();
766     allData.push_back(event);
767     valueProducer.onDataPulled(allData);
768     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
769     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
770     // startUpdated:false tainted:0 sum:12
771     EXPECT_EQ(true, curInterval.startUpdated);
772     EXPECT_EQ(0, curInterval.tainted);
773     EXPECT_EQ(36, curInterval.start);
774     EXPECT_EQ(0, curInterval.sum);
775     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
776     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
777     EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValue);
778 }
779 
780 /*
781  * Test pulled event with non sliced condition. The pull on boundary come late because the alarm
782  * was delivered late.
783  */
TEST(ValueMetricProducerTest,TestBucketBoundaryWithCondition)784 TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
785     ValueMetric metric;
786     metric.set_id(metricId);
787     metric.set_bucket(ONE_MINUTE);
788     metric.mutable_value_field()->set_field(tagId);
789     metric.mutable_value_field()->add_child()->set_field(2);
790     metric.set_condition(StringToId("SCREEN_ON"));
791 
792     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
793     shared_ptr<MockStatsPullerManager> pullerManager =
794             make_shared<StrictMock<MockStatsPullerManager>>();
795     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
796     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
797 
798     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
799             // condition becomes true
800             .WillOnce(Invoke([](int tagId, int64_t timeNs,
801                                 vector<std::shared_ptr<LogEvent>>* data) {
802                 data->clear();
803                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
804                 event->write(tagId);
805                 event->write(100);
806                 event->init();
807                 data->push_back(event);
808                 return true;
809             }))
810             // condition becomes false
811             .WillOnce(Invoke([](int tagId, int64_t timeNs,
812                                 vector<std::shared_ptr<LogEvent>>* data) {
813                 data->clear();
814                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
815                 event->write(tagId);
816                 event->write(120);
817                 event->init();
818                 data->push_back(event);
819                 return true;
820             }));
821 
822     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
823                                       bucketStartTimeNs, pullerManager);
824     valueProducer.setBucketSize(60 * NS_PER_SEC);
825     valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
826 
827     // has one slice
828     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
829     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
830     // startUpdated:false tainted:0 sum:0 start:100
831     EXPECT_EQ(100, curInterval.start);
832     EXPECT_EQ(true, curInterval.startUpdated);
833     EXPECT_EQ(0, curInterval.tainted);
834     EXPECT_EQ(0, curInterval.sum);
835     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
836 
837     // pull on bucket boundary come late, condition change happens before it
838     valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
839     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
840     EXPECT_EQ(false, curInterval.startUpdated);
841     EXPECT_EQ(1, curInterval.tainted);
842     EXPECT_EQ(0, curInterval.sum);
843     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
844 
845     // Now the alarm is delivered.
846     // since the condition turned to off before this pull finish, it has no effect
847     vector<shared_ptr<LogEvent>> allData;
848     allData.clear();
849     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30);
850     event->write(1);
851     event->write(110);
852     event->init();
853     allData.push_back(event);
854     valueProducer.onDataPulled(allData);
855 
856     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
857     EXPECT_EQ(false, curInterval.startUpdated);
858     EXPECT_EQ(1, curInterval.tainted);
859     EXPECT_EQ(0, curInterval.sum);
860     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
861 }
862 
863 /*
864  * Test pulled event with non sliced condition. The pull on boundary come late, after the condition
865  * change to false, and then true again. This is due to alarm delivered late.
866  */
TEST(ValueMetricProducerTest,TestBucketBoundaryWithCondition2)867 TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
868     ValueMetric metric;
869     metric.set_id(metricId);
870     metric.set_bucket(ONE_MINUTE);
871     metric.mutable_value_field()->set_field(tagId);
872     metric.mutable_value_field()->add_child()->set_field(2);
873     metric.set_condition(StringToId("SCREEN_ON"));
874 
875     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
876     shared_ptr<MockStatsPullerManager> pullerManager =
877             make_shared<StrictMock<MockStatsPullerManager>>();
878     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillRepeatedly(Return());
879     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
880 
881     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
882             // condition becomes true
883             .WillOnce(Invoke([](int tagId, int64_t timeNs,
884                                 vector<std::shared_ptr<LogEvent>>* data) {
885                 data->clear();
886                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
887                 event->write(tagId);
888                 event->write(100);
889                 event->init();
890                 data->push_back(event);
891                 return true;
892             }))
893             // condition becomes false
894             .WillOnce(Invoke([](int tagId, int64_t timeNs,
895                                 vector<std::shared_ptr<LogEvent>>* data) {
896                 data->clear();
897                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
898                 event->write(tagId);
899                 event->write(120);
900                 event->init();
901                 data->push_back(event);
902                 return true;
903             }))
904             // condition becomes true again
905             .WillOnce(Invoke([](int tagId, int64_t timeNs,
906                                 vector<std::shared_ptr<LogEvent>>* data) {
907                 data->clear();
908                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30);
909                 event->write(tagId);
910                 event->write(130);
911                 event->init();
912                 data->push_back(event);
913                 return true;
914             }));
915 
916     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
917                                       bucketStartTimeNs, pullerManager);
918     valueProducer.setBucketSize(60 * NS_PER_SEC);
919     valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
920 
921     // has one slice
922     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
923     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
924     // startUpdated:false tainted:0 sum:0 start:100
925     EXPECT_EQ(100, curInterval.start);
926     EXPECT_EQ(true, curInterval.startUpdated);
927     EXPECT_EQ(0, curInterval.tainted);
928     EXPECT_EQ(0, curInterval.sum);
929     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
930 
931     // pull on bucket boundary come late, condition change happens before it
932     valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
933     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
934     EXPECT_EQ(false, curInterval.startUpdated);
935     EXPECT_EQ(1, curInterval.tainted);
936     EXPECT_EQ(0, curInterval.sum);
937     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
938 
939     // condition changed to true again, before the pull alarm is delivered
940     valueProducer.onConditionChanged(true, bucket2StartTimeNs + 25);
941     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
942     EXPECT_EQ(true, curInterval.startUpdated);
943     EXPECT_EQ(130, curInterval.start);
944     EXPECT_EQ(1, curInterval.tainted);
945     EXPECT_EQ(0, curInterval.sum);
946     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
947 
948     // Now the alarm is delivered, but it is considered late, it has no effect
949     vector<shared_ptr<LogEvent>> allData;
950     allData.clear();
951     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 50);
952     event->write(1);
953     event->write(110);
954     event->init();
955     allData.push_back(event);
956     valueProducer.onDataPulled(allData);
957 
958     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
959     EXPECT_EQ(true, curInterval.startUpdated);
960     EXPECT_EQ(130, curInterval.start);
961     EXPECT_EQ(1, curInterval.tainted);
962     EXPECT_EQ(0, curInterval.sum);
963     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
964 }
965 
966 /*
967  * Test pulled event with non sliced condition. The pull on boundary come late because the puller is
968  * very slow.
969  */
TEST(ValueMetricProducerTest,TestBucketBoundaryWithCondition3)970 TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3) {
971     ValueMetric metric;
972     metric.set_id(metricId);
973     metric.set_bucket(ONE_MINUTE);
974     metric.mutable_value_field()->set_field(tagId);
975     metric.mutable_value_field()->add_child()->set_field(2);
976     metric.set_condition(StringToId("SCREEN_ON"));
977 
978     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
979     shared_ptr<MockStatsPullerManager> pullerManager =
980             make_shared<StrictMock<MockStatsPullerManager>>();
981     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
982     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
983 
984     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
985             // condition becomes true
986             .WillOnce(Invoke([](int tagId, int64_t timeNs,
987                                 vector<std::shared_ptr<LogEvent>>* data) {
988                 data->clear();
989                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
990                 event->write(tagId);
991                 event->write(100);
992                 event->init();
993                 data->push_back(event);
994                 return true;
995             }))
996             // condition becomes false
997             .WillOnce(Invoke([](int tagId, int64_t timeNs,
998                                 vector<std::shared_ptr<LogEvent>>* data) {
999                 data->clear();
1000                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 20);
1001                 event->write(tagId);
1002                 event->write(120);
1003                 event->init();
1004                 data->push_back(event);
1005                 return true;
1006             }));
1007 
1008     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
1009                                       bucketStartTimeNs, pullerManager);
1010     valueProducer.setBucketSize(60 * NS_PER_SEC);
1011     valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
1012 
1013     // has one slice
1014     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
1015     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
1016     // startUpdated:false tainted:0 sum:0 start:100
1017     EXPECT_EQ(100, curInterval.start);
1018     EXPECT_EQ(true, curInterval.startUpdated);
1019     EXPECT_EQ(0, curInterval.tainted);
1020     EXPECT_EQ(0, curInterval.sum);
1021     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
1022 
1023     // pull on bucket boundary come late, condition change happens before it.
1024     // But puller is very slow in this one, so the data come after bucket finish
1025     valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
1026     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
1027     EXPECT_EQ(false, curInterval.startUpdated);
1028     EXPECT_EQ(1, curInterval.tainted);
1029     EXPECT_EQ(0, curInterval.sum);
1030     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
1031 
1032     // Alarm is delivered in time, but the pull is very slow, and pullers are called in order,
1033     // so this one comes even later
1034     vector<shared_ptr<LogEvent>> allData;
1035     allData.clear();
1036     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 30);
1037     event->write(1);
1038     event->write(110);
1039     event->init();
1040     allData.push_back(event);
1041     valueProducer.onDataPulled(allData);
1042 
1043     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
1044     EXPECT_EQ(false, curInterval.startUpdated);
1045     EXPECT_EQ(1, curInterval.tainted);
1046     EXPECT_EQ(0, curInterval.sum);
1047     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
1048 }
1049 
1050 }  // namespace statsd
1051 }  // namespace os
1052 }  // namespace android
1053 #else
1054 GTEST_LOG_(INFO) << "This test does nothing.\n";
1055 #endif
1056