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
26using namespace testing;
27using android::sp;
28using std::make_shared;
29using std::set;
30using std::shared_ptr;
31using std::unordered_map;
32using std::vector;
33
34#ifdef __ANDROID__
35
36namespace android {
37namespace os {
38namespace statsd {
39
40const ConfigKey kConfigKey(0, 12345);
41const int tagId = 1;
42const int64_t metricId = 123;
43const int64_t bucketStartTimeNs = 10000000000;
44const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
45const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
46const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
47const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
48const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs;
49const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
50const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
51
52/*
53 * Tests pulled atoms with no conditions
54 */
55TEST(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 */
134TEST(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 */
209TEST(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 */
281TEST(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
360TEST(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
403TEST(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
458TEST(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
509TEST(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
551TEST(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
617TEST(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
700TEST(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 */
784TEST(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 */
867TEST(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 */
970TEST(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
1054GTEST_LOG_(INFO) << "This test does nothing.\n";
1055#endif
1056