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/NumericValueMetricProducer.h"
16 
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 #include <math.h>
20 #include <stdio.h>
21 
22 #include <vector>
23 
24 #include "metrics_test_helper.h"
25 #include "src/FieldValue.h"
26 #include "src/matchers/SimpleAtomMatchingTracker.h"
27 #include "src/metrics/MetricProducer.h"
28 #include "src/stats_log_util.h"
29 #include "tests/statsd_test_util.h"
30 
31 using namespace testing;
32 using android::sp;
33 using std::make_shared;
34 using std::nullopt;
35 using std::optional;
36 using std::set;
37 using std::shared_ptr;
38 using std::unordered_map;
39 using std::vector;
40 
41 #ifdef __ANDROID__
42 
43 namespace android {
44 namespace os {
45 namespace statsd {
46 
47 namespace {
48 
49 const ConfigKey kConfigKey(0, 12345);
50 const int tagId = 1;
51 const int64_t metricId = 123;
52 const uint64_t protoHash = 0x1234567890;
53 const int logEventMatcherIndex = 0;
54 const int64_t bucketStartTimeNs = 10000000000;
55 const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
56 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
57 const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
58 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
59 const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs;
60 const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
61 double epsilon = 0.001;
62 
assertPastBucketValuesSingleKey(const std::unordered_map<MetricDimensionKey,std::vector<PastBucket<Value>>> & mPastBuckets,const std::initializer_list<int> & expectedValuesList,const std::initializer_list<int64_t> & expectedDurationNsList,const std::initializer_list<int64_t> & expectedCorrectionNsList,const std::initializer_list<int64_t> & expectedStartTimeNsList,const std::initializer_list<int64_t> & expectedEndTimeNsList)63 static void assertPastBucketValuesSingleKey(
64         const std::unordered_map<MetricDimensionKey, std::vector<PastBucket<Value>>>& mPastBuckets,
65         const std::initializer_list<int>& expectedValuesList,
66         const std::initializer_list<int64_t>& expectedDurationNsList,
67         const std::initializer_list<int64_t>& expectedCorrectionNsList,
68         const std::initializer_list<int64_t>& expectedStartTimeNsList,
69         const std::initializer_list<int64_t>& expectedEndTimeNsList) {
70     vector<int> expectedValues(expectedValuesList);
71     vector<int64_t> expectedDurationNs(expectedDurationNsList);
72     vector<int64_t> expectedCorrectionNs(expectedCorrectionNsList);
73     vector<int64_t> expectedStartTimeNs(expectedStartTimeNsList);
74     vector<int64_t> expectedEndTimeNs(expectedEndTimeNsList);
75 
76     ASSERT_EQ(expectedValues.size(), expectedDurationNs.size());
77     ASSERT_EQ(expectedValues.size(), expectedStartTimeNs.size());
78     ASSERT_EQ(expectedValues.size(), expectedEndTimeNs.size());
79     ASSERT_EQ(expectedValues.size(), expectedCorrectionNs.size());
80 
81     if (expectedValues.size() == 0) {
82         ASSERT_EQ(0, mPastBuckets.size());
83         return;
84     }
85 
86     ASSERT_EQ(1, mPastBuckets.size());
87     ASSERT_EQ(expectedValues.size(), mPastBuckets.begin()->second.size());
88 
89     const vector<PastBucket<Value>>& buckets = mPastBuckets.begin()->second;
90     for (int i = 0; i < expectedValues.size(); i++) {
91         EXPECT_EQ(expectedValues[i], buckets[i].aggregates[0].long_value)
92                 << "Values differ at index " << i;
93         EXPECT_EQ(expectedDurationNs[i], buckets[i].mConditionTrueNs)
94                 << "Condition duration value differ at index " << i;
95         EXPECT_EQ(expectedStartTimeNs[i], buckets[i].mBucketStartNs)
96                 << "Start time differs at index " << i;
97         EXPECT_EQ(expectedEndTimeNs[i], buckets[i].mBucketEndNs)
98                 << "End time differs at index " << i;
99         EXPECT_EQ(expectedCorrectionNs[i], buckets[i].mConditionCorrectionNs)
100                 << "Condition correction differs at index " << i;
101     }
102 }
103 
104 }  // anonymous namespace
105 
106 class NumericValueMetricProducerTestHelper {
107 public:
createValueProducerNoConditions(sp<MockStatsPullerManager> & pullerManager,ValueMetric & metric,const int pullAtomId=tagId)108     static sp<NumericValueMetricProducer> createValueProducerNoConditions(
109             sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
110             const int pullAtomId = tagId) {
111         return createValueProducer(pullerManager, metric, pullAtomId);
112     }
113 
createValueProducerWithCondition(sp<MockStatsPullerManager> & pullerManager,ValueMetric & metric,ConditionState conditionAfterFirstBucketPrepared,const int pullAtomId=tagId)114     static sp<NumericValueMetricProducer> createValueProducerWithCondition(
115             sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
116             ConditionState conditionAfterFirstBucketPrepared, const int pullAtomId = tagId) {
117         return createValueProducer(pullerManager, metric, pullAtomId,
118                                    conditionAfterFirstBucketPrepared);
119     }
120 
createValueProducerWithState(sp<MockStatsPullerManager> & pullerManager,ValueMetric & metric,vector<int32_t> slicedStateAtoms,unordered_map<int,unordered_map<int,int64_t>> stateGroupMap,const int pullAtomId=tagId)121     static sp<NumericValueMetricProducer> createValueProducerWithState(
122             sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
123             vector<int32_t> slicedStateAtoms,
124             unordered_map<int, unordered_map<int, int64_t>> stateGroupMap,
125             const int pullAtomId = tagId) {
126         return createValueProducer(pullerManager, metric, pullAtomId,
127                                    /*conditionAfterFirstBucketPrepared=*/nullopt, slicedStateAtoms,
128                                    stateGroupMap);
129     }
130 
createValueProducerWithConditionAndState(sp<MockStatsPullerManager> & pullerManager,ValueMetric & metric,vector<int32_t> slicedStateAtoms,unordered_map<int,unordered_map<int,int64_t>> stateGroupMap,ConditionState conditionAfterFirstBucketPrepared,const int pullAtomId=tagId)131     static sp<NumericValueMetricProducer> createValueProducerWithConditionAndState(
132             sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
133             vector<int32_t> slicedStateAtoms,
134             unordered_map<int, unordered_map<int, int64_t>> stateGroupMap,
135             ConditionState conditionAfterFirstBucketPrepared, const int pullAtomId = tagId) {
136         return createValueProducer(pullerManager, metric, pullAtomId,
137                                    conditionAfterFirstBucketPrepared, slicedStateAtoms,
138                                    stateGroupMap);
139     }
140 
createValueProducerWithSampling(sp<MockStatsPullerManager> & pullerManager,ValueMetric & metric,const int pullAtomId=tagId)141     static sp<NumericValueMetricProducer> createValueProducerWithSampling(
142             sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
143             const int pullAtomId = tagId) {
144         sp<NumericValueMetricProducer> valueProducer = createValueProducer(
145                 pullerManager, metric, pullAtomId, /*conditionAfterFirstBucketPrepared=*/nullopt,
146                 /*slicedStateAtoms=*/{}, /*stateGroupMap=*/{}, bucketStartTimeNs, bucketStartTimeNs,
147                 /*eventMatcherWizard=*/nullptr);
148 
149         SamplingInfo samplingInfo;
150         samplingInfo.shardCount = metric.dimensional_sampling_info().shard_count();
151         translateFieldMatcher(metric.dimensional_sampling_info().sampled_what_field(),
152                               &samplingInfo.sampledWhatFields);
153         valueProducer->setSamplingInfo(samplingInfo);
154         return valueProducer;
155     }
156 
createValueProducerWithBucketParams(sp<MockStatsPullerManager> & pullerManager,ValueMetric & metric,const int64_t timeBaseNs,const int64_t startTimeNs,const int pullAtomId=tagId)157     static sp<NumericValueMetricProducer> createValueProducerWithBucketParams(
158             sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
159             const int64_t timeBaseNs, const int64_t startTimeNs, const int pullAtomId = tagId) {
160         return createValueProducer(
161                 pullerManager, metric, pullAtomId, /*conditionAfterFirstBucketPrepared=*/nullopt,
162                 /*slicedStateAtoms=*/{}, /*stateGroupMap=*/{}, timeBaseNs, startTimeNs);
163     }
164 
createValueProducerWithEventMatcherWizard(sp<MockStatsPullerManager> & pullerManager,ValueMetric & metric,const sp<EventMatcherWizard> & eventMatcherWizard,const int pullAtomId=tagId)165     static sp<NumericValueMetricProducer> createValueProducerWithEventMatcherWizard(
166             sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
167             const sp<EventMatcherWizard>& eventMatcherWizard, const int pullAtomId = tagId) {
168         return createValueProducer(pullerManager, metric, pullAtomId,
169                                    /*conditionAfterFirstBucketPrepared=*/nullopt,
170                                    /*slicedStateAtoms=*/{}, /*stateGroupMap=*/{}, bucketStartTimeNs,
171                                    bucketStartTimeNs, eventMatcherWizard);
172     }
173 
createValueProducer(sp<MockStatsPullerManager> & pullerManager,ValueMetric & metric,const int pullAtomId,optional<ConditionState> conditionAfterFirstBucketPrepared=nullopt,vector<int32_t> slicedStateAtoms={},unordered_map<int,unordered_map<int,int64_t>> stateGroupMap={},const int64_t timeBaseNs=bucketStartTimeNs,const int64_t startTimeNs=bucketStartTimeNs,sp<EventMatcherWizard> eventMatcherWizard=nullptr)174     static sp<NumericValueMetricProducer> createValueProducer(
175             sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric, const int pullAtomId,
176             optional<ConditionState> conditionAfterFirstBucketPrepared = nullopt,
177             vector<int32_t> slicedStateAtoms = {},
178             unordered_map<int, unordered_map<int, int64_t>> stateGroupMap = {},
179             const int64_t timeBaseNs = bucketStartTimeNs,
180             const int64_t startTimeNs = bucketStartTimeNs,
181             sp<EventMatcherWizard> eventMatcherWizard = nullptr) {
182         sp<NumericValueMetricProducer> valueProducer = createNumericValueMetricProducer(
183                 pullerManager, metric, tagId, pullAtomId != -1, kConfigKey, protoHash, timeBaseNs,
184                 startTimeNs, logEventMatcherIndex, conditionAfterFirstBucketPrepared,
185                 slicedStateAtoms, stateGroupMap, eventMatcherWizard);
186 
187         valueProducer->prepareFirstBucket();
188         if (conditionAfterFirstBucketPrepared) {
189             valueProducer->mCondition = conditionAfterFirstBucketPrepared.value();
190         }
191         return valueProducer;
192     }
193 
createMetric()194     static ValueMetric createMetric() {
195         ValueMetric metric;
196         metric.set_id(metricId);
197         metric.set_bucket(ONE_MINUTE);
198         metric.mutable_value_field()->set_field(tagId);
199         metric.mutable_value_field()->add_child()->set_field(2);
200         metric.set_max_pull_delay_sec(INT_MAX);
201         metric.set_split_bucket_for_app_upgrade(true);
202         return metric;
203     }
204 
createMetricWithCondition()205     static ValueMetric createMetricWithCondition() {
206         ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
207         metric.set_condition(StringToId("SCREEN_ON"));
208         return metric;
209     }
210 
createMetricWithState(string state)211     static ValueMetric createMetricWithState(string state) {
212         ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
213         metric.add_slice_by_state(StringToId(state));
214         return metric;
215     }
216 
createMetricWithConditionAndState(string state)217     static ValueMetric createMetricWithConditionAndState(string state) {
218         ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
219         metric.set_condition(StringToId("SCREEN_ON"));
220         metric.add_slice_by_state(StringToId(state));
221         return metric;
222     }
223 
createMetricWithRepeatedValueField()224     static ValueMetric createMetricWithRepeatedValueField() {
225         ValueMetric metric;
226         metric.set_id(metricId);
227         metric.set_bucket(ONE_MINUTE);
228         metric.mutable_value_field()->set_field(tagId);
229         FieldMatcher* valueChild = metric.mutable_value_field()->add_child();
230         valueChild->set_field(3);
231         valueChild->set_position(Position::FIRST);
232         metric.set_max_pull_delay_sec(INT_MAX);
233         metric.set_split_bucket_for_app_upgrade(true);
234         metric.set_aggregation_type(ValueMetric_AggregationType_SUM);
235         return metric;
236     }
237 };
238 
239 // Setup for parameterized tests.
240 class NumericValueMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
241 
242 INSTANTIATE_TEST_SUITE_P(NumericValueMetricProducerTest_PartialBucket,
243                          NumericValueMetricProducerTest_PartialBucket,
244                          testing::Values(APP_UPGRADE, BOOT_COMPLETE));
245 
246 /*
247  * Tests that the first bucket works correctly
248  */
TEST(NumericValueMetricProducerTest,TestCalcPreviousBucketEndTime)249 TEST(NumericValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
250     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
251 
252     int64_t startTimeBase = 11;
253     sp<EventMatcherWizard> eventMatcherWizard =
254             createEventMatcherWizard(tagId, logEventMatcherIndex);
255     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
256     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
257 
258     // statsd started long ago.
259     // The metric starts in the middle of the bucket
260     sp<NumericValueMetricProducer> valueProducer =
261             NumericValueMetricProducerTestHelper::createValueProducerWithBucketParams(
262                     pullerManager, metric, startTimeBase, /*startTimeNs=*/22, /*pullAtomId=*/-1);
263 
264     EXPECT_EQ(startTimeBase, valueProducer->calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
265     EXPECT_EQ(startTimeBase, valueProducer->calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
266     EXPECT_EQ(60 * NS_PER_SEC + startTimeBase,
267               valueProducer->calcPreviousBucketEndTime(2 * 60 * NS_PER_SEC));
268     EXPECT_EQ(2 * 60 * NS_PER_SEC + startTimeBase,
269               valueProducer->calcPreviousBucketEndTime(3 * 60 * NS_PER_SEC));
270 }
271 
272 /*
273  * Tests that the first bucket works correctly
274  */
TEST(NumericValueMetricProducerTest,TestFirstBucket)275 TEST(NumericValueMetricProducerTest, TestFirstBucket) {
276     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
277 
278     sp<EventMatcherWizard> eventMatcherWizard =
279             createEventMatcherWizard(tagId, logEventMatcherIndex);
280     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
281     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
282 
283     // statsd started long ago.
284     // The metric starts in the middle of the bucket
285     sp<NumericValueMetricProducer> valueProducer =
286             NumericValueMetricProducerTestHelper::createValueProducerWithBucketParams(
287                     pullerManager, metric, /*timeBaseNs=*/5,
288                     /*startTimeNs=*/600 * NS_PER_SEC + NS_PER_SEC / 2, /*pullAtomId=*/-1);
289 
290     EXPECT_EQ(600500000000, valueProducer->mCurrentBucketStartTimeNs);
291     EXPECT_EQ(10, valueProducer->mCurrentBucketNum);
292     EXPECT_EQ(660000000005, valueProducer->getCurrentBucketEndTimeNs());
293 }
294 
295 /*
296  * Tests pulled atoms with no conditions
297  */
TEST(NumericValueMetricProducerTest,TestPulledEventsNoCondition)298 TEST(NumericValueMetricProducerTest, TestPulledEventsNoCondition) {
299     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
300     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
301     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
302             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
303                                 vector<std::shared_ptr<LogEvent>>* data) {
304                 data->clear();
305                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
306                 return true;
307             }));
308 
309     sp<NumericValueMetricProducer> valueProducer =
310             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
311                                                                                   metric);
312 
313     vector<shared_ptr<LogEvent>> allData;
314     allData.clear();
315     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 11));
316 
317     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
318     // empty since bucket is flushed
319     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
320     // dimInfos holds the base
321     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
322     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
323 
324     EXPECT_EQ(true, curBase.has_value());
325     EXPECT_EQ(11, curBase.value().long_value);
326     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs}, {0},
327                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
328 
329     allData.clear();
330     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 23));
331     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
332     // empty since bucket is cleared
333     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
334     // dimInfos holds the base
335     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
336     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
337 
338     EXPECT_EQ(true, curBase.has_value());
339     EXPECT_EQ(23, curBase.value().long_value);
340     assertPastBucketValuesSingleKey(
341             valueProducer->mPastBuckets, {8, 12}, {bucketSizeNs, bucketSizeNs}, {0, 0},
342             {bucketStartTimeNs, bucket2StartTimeNs}, {bucket2StartTimeNs, bucket3StartTimeNs});
343 
344     allData.clear();
345     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
346     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
347     // empty since bucket is cleared
348     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
349     // dimInfos holds the base
350     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
351     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
352 
353     EXPECT_EQ(true, curBase.has_value());
354     EXPECT_EQ(36, curBase.value().long_value);
355     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8, 12, 13},
356                                     {bucketSizeNs, bucketSizeNs, bucketSizeNs}, {0, 0, 0},
357                                     {bucketStartTimeNs, bucket2StartTimeNs, bucket3StartTimeNs},
358                                     {bucket2StartTimeNs, bucket3StartTimeNs, bucket4StartTimeNs});
359 }
360 
TEST_P(NumericValueMetricProducerTest_PartialBucket,TestPartialBucketCreated)361 TEST_P(NumericValueMetricProducerTest_PartialBucket, TestPartialBucketCreated) {
362     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
363     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
364     int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 2;
365     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
366             // Initialize bucket.
367             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
368                                 vector<std::shared_ptr<LogEvent>>* data) {
369                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
370                 data->clear();
371                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
372                 return true;
373             }))
374             // Partial bucket.
375             .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
376                                                         const int64_t eventTimeNs,
377                                                         vector<std::shared_ptr<LogEvent>>* data) {
378                 EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
379                 data->clear();
380                 data->push_back(
381                         CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs + 8, 5));
382                 return true;
383             }));
384 
385     sp<NumericValueMetricProducer> valueProducer =
386             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
387                                                                                   metric);
388 
389     // First bucket ends.
390     vector<shared_ptr<LogEvent>> allData;
391     allData.clear();
392     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 10, 2));
393     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
394 
395     // Partial buckets created in 2nd bucket.
396     switch (GetParam()) {
397         case APP_UPGRADE:
398             valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
399             break;
400         case BOOT_COMPLETE:
401             valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
402             break;
403     }
404     EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
405     EXPECT_EQ(1, valueProducer->getCurrentBucketNum());
406 
407     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {1, 3},
408                                     {bucketSizeNs, partialBucketSplitTimeNs - bucket2StartTimeNs},
409                                     {0, 0}, {bucketStartTimeNs, bucket2StartTimeNs},
410                                     {bucket2StartTimeNs, partialBucketSplitTimeNs});
411 }
412 
413 /*
414  * Tests pulled atoms with filtering
415  */
TEST(NumericValueMetricProducerTest,TestPulledEventsWithFiltering)416 TEST(NumericValueMetricProducerTest, TestPulledEventsWithFiltering) {
417     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
418 
419     FieldValueMatcher fvm;
420     fvm.set_field(1);
421     fvm.set_eq_int(3);
422     sp<EventMatcherWizard> eventMatcherWizard =
423             createEventMatcherWizard(tagId, logEventMatcherIndex, {fvm});
424     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
425     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
426     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
427             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
428                                 vector<std::shared_ptr<LogEvent>>* data) {
429                 data->clear();
430                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 3, 3));
431                 return true;
432             }));
433 
434     sp<NumericValueMetricProducer> valueProducer =
435             NumericValueMetricProducerTestHelper::createValueProducerWithEventMatcherWizard(
436                     pullerManager, metric, eventMatcherWizard);
437 
438     vector<shared_ptr<LogEvent>> allData;
439     allData.clear();
440     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 3, 11));
441 
442     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
443     // empty since bucket is cleared
444     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
445     // dimInfos holds the base
446     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
447     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
448 
449     EXPECT_EQ(true, curBase.has_value());
450     EXPECT_EQ(11, curBase.value().long_value);
451     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs}, {0},
452                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
453 
454     allData.clear();
455     allData.push_back(CreateTwoValueLogEvent(tagId, bucket3StartTimeNs + 1, 4, 23));
456     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
457     // No new data seen, so data has been cleared.
458     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
459     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
460 
461     allData.clear();
462     allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 3, 36));
463     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
464     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
465     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
466     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
467 
468     // the base was reset
469     EXPECT_EQ(true, curBase.has_value());
470     EXPECT_EQ(36, curBase.value().long_value);
471     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs}, {0},
472                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
473 }
474 
475 /*
476  * Tests pulled atoms with no conditions and take absolute value after reset
477  */
TEST(NumericValueMetricProducerTest,TestPulledEventsTakeAbsoluteValueOnReset)478 TEST(NumericValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
479     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
480     metric.set_use_absolute_value_on_reset(true);
481 
482     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
483     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
484             .WillOnce(Return(true));
485     sp<NumericValueMetricProducer> valueProducer =
486             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
487                                                                                   metric);
488 
489     vector<shared_ptr<LogEvent>> allData;
490     allData.clear();
491     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 11));
492 
493     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
494     // empty since bucket is cleared
495     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
496     // dimInfos holds the base
497     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
498     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
499 
500     EXPECT_EQ(true, curBase.has_value());
501     EXPECT_EQ(11, curBase.value().long_value);
502     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
503 
504     allData.clear();
505     // 10 is less than 11, so we reset and keep 10 as the value.
506     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 10));
507     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
508     // empty since the bucket is flushed.
509     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
510     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
511     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
512     EXPECT_EQ(true, curBase.has_value());
513     EXPECT_EQ(10, curBase.value().long_value);
514     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs}, {0},
515                                     {bucket2StartTimeNs}, {bucket3StartTimeNs});
516 
517     allData.clear();
518     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
519     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
520     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
521     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
522     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
523     EXPECT_EQ(true, curBase.has_value());
524     EXPECT_EQ(36, curBase.value().long_value);
525     assertPastBucketValuesSingleKey(
526             valueProducer->mPastBuckets, {10, 26}, {bucketSizeNs, bucketSizeNs}, {0, 0},
527             {bucket2StartTimeNs, bucket3StartTimeNs}, {bucket3StartTimeNs, bucket4StartTimeNs});
528 }
529 
530 /*
531  * Tests pulled atoms with no conditions and take zero value after reset
532  */
TEST(NumericValueMetricProducerTest,TestPulledEventsTakeZeroOnReset)533 TEST(NumericValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
534     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
535     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
536     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
537             .WillOnce(Return(false));
538     sp<NumericValueMetricProducer> valueProducer =
539             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
540                                                                                   metric);
541 
542     vector<shared_ptr<LogEvent>> allData;
543     allData.clear();
544     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 11));
545 
546     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
547     // empty since bucket is cleared
548     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
549     // mDimInfos holds the base
550     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
551     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
552 
553     EXPECT_EQ(true, curBase.has_value());
554     EXPECT_EQ(11, curBase.value().long_value);
555     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
556 
557     allData.clear();
558     // 10 is less than 11, so we reset. 10 only updates the base.
559     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 10));
560     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
561     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
562     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
563     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
564     EXPECT_EQ(true, curBase.has_value());
565     EXPECT_EQ(10, curBase.value().long_value);
566     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
567 
568     allData.clear();
569     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
570     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
571     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
572     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
573     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
574     EXPECT_EQ(true, curBase.has_value());
575     EXPECT_EQ(36, curBase.value().long_value);
576     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {26}, {bucketSizeNs}, {0},
577                                     {bucket3StartTimeNs}, {bucket4StartTimeNs});
578 }
579 
580 /*
581  * Test pulled event with non sliced condition.
582  */
TEST(NumericValueMetricProducerTest,TestEventsWithNonSlicedCondition)583 TEST(NumericValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
584     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
585 
586     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
587 
588     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
589             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
590                                 vector<std::shared_ptr<LogEvent>>* data) {
591                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);  // First condition change.
592                 data->clear();
593                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
594                 return true;
595             }))
596             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
597                                 vector<std::shared_ptr<LogEvent>>* data) {
598                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1);  // Second condition change.
599                 data->clear();
600                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 130));
601                 return true;
602             }))
603             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
604                                 vector<std::shared_ptr<LogEvent>>* data) {
605                 EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 1);  // Third condition change.
606                 data->clear();
607                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 180));
608                 return true;
609             }));
610 
611     sp<NumericValueMetricProducer> valueProducer =
612             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
613                     pullerManager, metric, ConditionState::kFalse);
614 
615     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
616 
617     // has one slice
618     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
619     NumericValueMetricProducer::Interval curInterval =
620             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
621     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
622     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
623     // startUpdated:false sum:0 start:100
624     EXPECT_EQ(true, curBase.has_value());
625     EXPECT_EQ(100, curBase.value().long_value);
626     EXPECT_EQ(0, curInterval.sampleSize);
627     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
628 
629     vector<shared_ptr<LogEvent>> allData;
630     allData.clear();
631     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
632     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
633     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8}, {0},
634                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
635 
636     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
637     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
638     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
639     EXPECT_EQ(true, curBase.has_value());
640     EXPECT_EQ(110, curBase.value().long_value);
641 
642     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
643     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8}, {0},
644                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
645 
646     // has one slice
647     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
648     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
649     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
650     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
651     EXPECT_TRUE(curInterval.hasValue());
652     EXPECT_EQ(20, curInterval.aggregate.long_value);
653     EXPECT_EQ(false, curBase.has_value());
654 
655     valueProducer->onConditionChanged(true, bucket3StartTimeNs + 1);
656     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10, 20}, {bucketSizeNs - 8, 1},
657                                     {0, 0}, {bucketStartTimeNs, bucket2StartTimeNs},
658                                     {bucket2StartTimeNs, bucket3StartTimeNs});
659 }
660 
TEST_P(NumericValueMetricProducerTest_PartialBucket,TestPushedEvents)661 TEST_P(NumericValueMetricProducerTest_PartialBucket, TestPushedEvents) {
662     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
663 
664     sp<EventMatcherWizard> eventMatcherWizard =
665             createEventMatcherWizard(tagId, logEventMatcherIndex);
666     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
667     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
668 
669     sp<NumericValueMetricProducer> valueProducer =
670             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
671                     pullerManager, metric, /*pullAtomId=*/-1);
672 
673     LogEvent event1(/*uid=*/0, /*pid=*/0);
674     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
675     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
676     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
677 
678     int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 150;
679     switch (GetParam()) {
680         case APP_UPGRADE:
681             valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
682             break;
683         case BOOT_COMPLETE:
684             valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
685             break;
686     }
687     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10},
688                                     {partialBucketSplitTimeNs - bucketStartTimeNs}, {0},
689                                     {bucketStartTimeNs}, {partialBucketSplitTimeNs});
690     EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
691     EXPECT_EQ(0, valueProducer->getCurrentBucketNum());
692 
693     // Event arrives after the bucket split.
694     LogEvent event2(/*uid=*/0, /*pid=*/0);
695     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 20);
696     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
697 
698     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10},
699                                     {partialBucketSplitTimeNs - bucketStartTimeNs}, {0},
700                                     {bucketStartTimeNs}, {partialBucketSplitTimeNs});
701     EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
702     EXPECT_EQ(0, valueProducer->getCurrentBucketNum());
703 
704     // Next value should create a new bucket.
705     LogEvent event3(/*uid=*/0, /*pid=*/0);
706     CreateRepeatedValueLogEvent(&event3, tagId, bucket2StartTimeNs + 5 * NS_PER_SEC, 10);
707     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event3);
708     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10, 20},
709                                     {partialBucketSplitTimeNs - bucketStartTimeNs,
710                                      bucket2StartTimeNs - partialBucketSplitTimeNs},
711                                     {0, 5 * NS_PER_SEC},
712                                     {bucketStartTimeNs, partialBucketSplitTimeNs},
713                                     {partialBucketSplitTimeNs, bucket2StartTimeNs});
714     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, valueProducer->mCurrentBucketStartTimeNs);
715     EXPECT_EQ(1, valueProducer->getCurrentBucketNum());
716 }
717 
TEST_P(NumericValueMetricProducerTest_PartialBucket,TestPulledValue)718 TEST_P(NumericValueMetricProducerTest_PartialBucket, TestPulledValue) {
719     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
720 
721     sp<EventMatcherWizard> eventMatcherWizard =
722             createEventMatcherWizard(tagId, logEventMatcherIndex);
723     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
724     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
725     int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 150;
726     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
727             .WillOnce(Return(true))
728             .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
729                                                         const int64_t eventTimeNs,
730                                                         vector<std::shared_ptr<LogEvent>>* data) {
731                 EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
732                 data->clear();
733                 data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 120));
734                 return true;
735             }));
736 
737     sp<NumericValueMetricProducer> valueProducer =
738             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
739                                                                                   metric);
740 
741     vector<shared_ptr<LogEvent>> allData;
742     allData.clear();
743     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 100));
744 
745     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
746     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
747 
748     switch (GetParam()) {
749         case APP_UPGRADE:
750             valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
751             break;
752         case BOOT_COMPLETE:
753             valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
754             break;
755     }
756     EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
757     EXPECT_EQ(1, valueProducer->getCurrentBucketNum());
758     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {150}, {0},
759                                     {bucket2StartTimeNs}, {partialBucketSplitTimeNs});
760 
761     allData.clear();
762     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 150));
763     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
764     EXPECT_EQ(bucket3StartTimeNs, valueProducer->mCurrentBucketStartTimeNs);
765     EXPECT_EQ(2, valueProducer->getCurrentBucketNum());
766     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30},
767                                     {150, bucketSizeNs - 150}, {0, 0},
768                                     {bucket2StartTimeNs, partialBucketSplitTimeNs},
769                                     {partialBucketSplitTimeNs, bucket3StartTimeNs});
770 }
771 
TEST(NumericValueMetricProducerTest,TestPulledWithAppUpgradeDisabled)772 TEST(NumericValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
773     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
774     metric.set_split_bucket_for_app_upgrade(false);
775 
776     sp<EventMatcherWizard> eventMatcherWizard =
777             createEventMatcherWizard(tagId, logEventMatcherIndex);
778     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
779     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
780     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
781             .WillOnce(Return(true));
782 
783     sp<NumericValueMetricProducer> valueProducer =
784             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
785                                                                                   metric);
786 
787     vector<shared_ptr<LogEvent>> allData;
788     allData.clear();
789     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 100));
790 
791     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
792     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
793     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
794 
795     valueProducer->notifyAppUpgrade(bucket2StartTimeNs + 150);
796     ASSERT_EQ(0UL, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
797     EXPECT_EQ(bucket2StartTimeNs, valueProducer->mCurrentBucketStartTimeNs);
798 }
799 
TEST_P(NumericValueMetricProducerTest_PartialBucket,TestPulledValueWhileConditionFalse)800 TEST_P(NumericValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse) {
801     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
802 
803     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
804     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
805             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
806                                 vector<std::shared_ptr<LogEvent>>* data) {
807                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1);  // Condition change to true time.
808                 data->clear();
809                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100));
810                 return true;
811             }))
812             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
813                                 vector<std::shared_ptr<LogEvent>>* data) {
814                 EXPECT_EQ(eventTimeNs,
815                           bucket2StartTimeNs - 100);  // Condition change to false time.
816                 data->clear();
817                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs - 100, 120));
818                 return true;
819             }));
820     sp<NumericValueMetricProducer> valueProducer =
821             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
822                     pullerManager, metric, ConditionState::kFalse);
823 
824     valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
825 
826     valueProducer->onConditionChanged(false, bucket2StartTimeNs - 100);
827     EXPECT_FALSE(valueProducer->mCondition);
828 
829     int64_t partialBucketSplitTimeNs = bucket2StartTimeNs - 50;
830     switch (GetParam()) {
831         case APP_UPGRADE:
832             valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
833             break;
834         case BOOT_COMPLETE:
835             valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
836             break;
837     }
838     // Expect one full buckets already done and starting a partial bucket.
839     EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
840     EXPECT_EQ(0, valueProducer->getCurrentBucketNum());
841     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20},
842                                     {(bucket2StartTimeNs - 100) - (bucketStartTimeNs + 1)}, {0},
843                                     {bucketStartTimeNs}, {partialBucketSplitTimeNs});
844     EXPECT_FALSE(valueProducer->mCondition);
845 }
846 
TEST(NumericValueMetricProducerTest,TestPushedEventsWithoutCondition)847 TEST(NumericValueMetricProducerTest, TestPushedEventsWithoutCondition) {
848     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
849 
850     sp<EventMatcherWizard> eventMatcherWizard =
851             createEventMatcherWizard(tagId, logEventMatcherIndex);
852     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
853     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
854 
855     sp<NumericValueMetricProducer> valueProducer =
856             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
857                     pullerManager, metric, /*pullAtomId=*/-1);
858 
859     LogEvent event1(/*uid=*/0, /*pid=*/0);
860     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
861 
862     LogEvent event2(/*uid=*/0, /*pid=*/0);
863     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20);
864 
865     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
866     // has one slice
867     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
868     NumericValueMetricProducer::Interval curInterval =
869             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
870     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
871     EXPECT_EQ(10, curInterval.aggregate.long_value);
872     EXPECT_TRUE(curInterval.hasValue());
873 
874     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
875 
876     // has one slice
877     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
878     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
879     EXPECT_EQ(30, curInterval.aggregate.long_value);
880 
881     // Check dump report.
882     ProtoOutputStream output;
883     valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
884                                 true, FAST /* dumpLatency */, nullptr, &output);
885 
886     StatsLogReport report = outputStreamToProto(&output);
887     backfillDimensionPath(&report);
888     backfillStartEndTimestamp(&report);
889     EXPECT_TRUE(report.has_value_metrics());
890     ASSERT_EQ(1, report.value_metrics().data_size());
891     ASSERT_EQ(0, report.value_metrics().skipped_size());
892 
893     auto data = report.value_metrics().data(0);
894     ASSERT_EQ(1, data.bucket_info_size());
895     EXPECT_EQ(30, data.bucket_info(0).values(0).value_long());
896     EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
897     EXPECT_EQ(bucket2StartTimeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
898     EXPECT_FALSE(data.has_dimensions_in_what());
899 
900     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
901 }
902 
TEST(NumericValueMetricProducerTest,TestPushedEventsWithCondition)903 TEST(NumericValueMetricProducerTest, TestPushedEventsWithCondition) {
904     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
905 
906     sp<EventMatcherWizard> eventMatcherWizard =
907             createEventMatcherWizard(tagId, logEventMatcherIndex);
908     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
909     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
910 
911     sp<NumericValueMetricProducer> valueProducer =
912             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
913                     pullerManager, metric, ConditionState::kFalse, /*pullAtomId=*/-1);
914 
915     LogEvent event1(/*uid=*/0, /*pid=*/0);
916     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
917     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
918     // has 1 slice
919     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
920 
921     valueProducer->onConditionChangedLocked(true, bucketStartTimeNs + 15);
922 
923     LogEvent event2(/*uid=*/0, /*pid=*/0);
924     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20);
925     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
926 
927     // has one slice
928     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
929     NumericValueMetricProducer::Interval curInterval =
930             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
931     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
932     EXPECT_EQ(20, curInterval.aggregate.long_value);
933 
934     LogEvent event3(/*uid=*/0, /*pid=*/0);
935     CreateRepeatedValueLogEvent(&event3, tagId, bucketStartTimeNs + 30, 30);
936     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event3);
937 
938     // has one slice
939     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
940     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
941     EXPECT_EQ(50, curInterval.aggregate.long_value);
942 
943     valueProducer->onConditionChangedLocked(false, bucketStartTimeNs + 35);
944 
945     LogEvent event4(/*uid=*/0, /*pid=*/0);
946     CreateRepeatedValueLogEvent(&event4, tagId, bucketStartTimeNs + 40, 40);
947     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event4);
948 
949     // has one slice
950     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
951     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
952     EXPECT_EQ(50, curInterval.aggregate.long_value);
953 
954     // Check dump report.
955     ProtoOutputStream output;
956     valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
957                                 true, FAST /* dumpLatency */, nullptr, &output);
958 
959     StatsLogReport report = outputStreamToProto(&output);
960     backfillDimensionPath(&report);
961     backfillStartEndTimestamp(&report);
962     EXPECT_TRUE(report.has_value_metrics());
963     ASSERT_EQ(1, report.value_metrics().data_size());
964     ASSERT_EQ(0, report.value_metrics().skipped_size());
965 
966     auto data = report.value_metrics().data(0);
967     ASSERT_EQ(1, data.bucket_info_size());
968     EXPECT_EQ(50, data.bucket_info(0).values(0).value_long());
969     EXPECT_EQ(20, data.bucket_info(0).condition_true_nanos());
970     EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
971     EXPECT_EQ(bucket2StartTimeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
972     EXPECT_FALSE(data.has_dimensions_in_what());
973 
974     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
975 }
976 
TEST(NumericValueMetricProducerTest,TestAnomalyDetection)977 TEST(NumericValueMetricProducerTest, TestAnomalyDetection) {
978     sp<AlarmMonitor> alarmMonitor;
979     Alert alert;
980     alert.set_id(101);
981     alert.set_metric_id(metricId);
982     alert.set_trigger_if_sum_gt(130);
983     alert.set_num_buckets(2);
984     const int32_t refPeriodSec = 3;
985     alert.set_refractory_period_secs(refPeriodSec);
986 
987     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
988 
989     sp<EventMatcherWizard> eventMatcherWizard =
990             createEventMatcherWizard(tagId, logEventMatcherIndex);
991     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
992     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
993 
994     sp<NumericValueMetricProducer> valueProducer =
995             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
996                     pullerManager, metric, /*pullAtomId=*/-1);
997 
998     sp<AnomalyTracker> anomalyTracker =
999             valueProducer->addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
1000 
1001     LogEvent event1(/*uid=*/0, /*pid=*/0);
1002     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 1 * NS_PER_SEC, 10);
1003 
1004     LogEvent event2(/*uid=*/0, /*pid=*/0);
1005     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 2 + NS_PER_SEC, 20);
1006 
1007     LogEvent event3(/*uid=*/0, /*pid=*/0);
1008     CreateRepeatedValueLogEvent(&event3, tagId,
1009                                 bucketStartTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, 130);
1010 
1011     LogEvent event4(/*uid=*/0, /*pid=*/0);
1012     CreateRepeatedValueLogEvent(&event4, tagId,
1013                                 bucketStartTimeNs + 3 * bucketSizeNs + 1 * NS_PER_SEC, 1);
1014 
1015     LogEvent event5(/*uid=*/0, /*pid=*/0);
1016     CreateRepeatedValueLogEvent(&event5, tagId,
1017                                 bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, 150);
1018 
1019     LogEvent event6(/*uid=*/0, /*pid=*/0);
1020     CreateRepeatedValueLogEvent(&event6, tagId,
1021                                 bucketStartTimeNs + 3 * bucketSizeNs + 10 * NS_PER_SEC, 160);
1022 
1023     // Two events in bucket #0.
1024     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
1025     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
1026     // Value sum == 30 <= 130.
1027     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
1028 
1029     // One event in bucket #2. No alarm as bucket #0 is trashed out.
1030     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event3);
1031     // Value sum == 130 <= 130.
1032     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
1033 
1034     // Three events in bucket #3.
1035     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event4);
1036     // Anomaly at event 4 since Value sum == 131 > 130!
1037     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
1038               std::ceil(1.0 * event4.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
1039     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event5);
1040     // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
1041     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
1042               std::ceil(1.0 * event4.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
1043 
1044     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event6);
1045     // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
1046     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
1047               std::ceil(1.0 * event6.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
1048 }
1049 
TEST(NumericValueMetricProducerTest,TestAnomalyDetectionMultipleBucketsSkipped)1050 TEST(NumericValueMetricProducerTest, TestAnomalyDetectionMultipleBucketsSkipped) {
1051     sp<AlarmMonitor> alarmMonitor;
1052     Alert alert;
1053     alert.set_id(101);
1054     alert.set_metric_id(metricId);
1055     alert.set_trigger_if_sum_gt(100);
1056     alert.set_num_buckets(1);
1057     const int32_t refPeriodSec = 3;
1058     alert.set_refractory_period_secs(refPeriodSec);
1059 
1060     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
1061 
1062     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1063     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
1064             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
1065                                 vector<std::shared_ptr<LogEvent>>* data) {
1066                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1);  // Condition change to true time.
1067                 data->clear();
1068                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 0));
1069                 return true;
1070             }))
1071             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
1072                                 vector<std::shared_ptr<LogEvent>>* data) {
1073                 EXPECT_EQ(eventTimeNs,
1074                           bucket3StartTimeNs + 100);  // Condition changed to false time.
1075                 data->clear();
1076                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 100, 120));
1077                 return true;
1078             }));
1079     sp<NumericValueMetricProducer> valueProducer =
1080             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
1081                     pullerManager, metric, ConditionState::kFalse);
1082     sp<AnomalyTracker> anomalyTracker =
1083             valueProducer->addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
1084 
1085     valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
1086 
1087     // multiple buckets should be skipped here.
1088     valueProducer->onConditionChanged(false, bucket3StartTimeNs + 100);
1089 
1090     // No alert is fired when multiple buckets are skipped.
1091     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
1092 }
1093 
1094 // Test value metric no condition, the pull on bucket boundary come in time and too late
TEST(NumericValueMetricProducerTest,TestBucketBoundaryNoCondition)1095 TEST(NumericValueMetricProducerTest, TestBucketBoundaryNoCondition) {
1096     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1097     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1098     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
1099             .WillOnce(Return(true));
1100     sp<NumericValueMetricProducer> valueProducer =
1101             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
1102                                                                                   metric);
1103 
1104     vector<shared_ptr<LogEvent>> allData;
1105     // pull 1
1106     allData.clear();
1107     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 11));
1108 
1109     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
1110     // empty since bucket is finished
1111     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1112     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1113     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1114 
1115     // startUpdated:true sum:0 start:11
1116     EXPECT_EQ(true, curBase.has_value());
1117     EXPECT_EQ(11, curBase.value().long_value);
1118     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
1119 
1120     // pull 2 at correct time
1121     allData.clear();
1122     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 23));
1123     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
1124     // empty since bucket is finished
1125     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1126     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1127     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1128     // tartUpdated:false sum:12
1129     EXPECT_EQ(true, curBase.has_value());
1130     EXPECT_EQ(23, curBase.value().long_value);
1131     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs}, {0},
1132                                     {bucket2StartTimeNs}, {bucket3StartTimeNs});
1133 
1134     // pull 3 come late.
1135     // The previous bucket gets closed with error. (Has start value 23, no ending)
1136     // Another bucket gets closed with error. (No start, but ending with 36)
1137     // The new bucket is back to normal.
1138     allData.clear();
1139     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket6StartTimeNs + 1, 36));
1140     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket6StartTimeNs);
1141     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1142     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1143     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1144     // startUpdated:false sum:12
1145     EXPECT_EQ(true, curBase.has_value());
1146     EXPECT_EQ(36, curBase.value().long_value);
1147     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs}, {0},
1148                                     {bucket2StartTimeNs}, {bucket3StartTimeNs});
1149     // The 1st bucket is dropped because of no data
1150     // The 3rd bucket is dropped due to multiple buckets being skipped.
1151     ASSERT_EQ(2, valueProducer->mSkippedBuckets.size());
1152 
1153     EXPECT_EQ(bucketStartTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs);
1154     EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs);
1155     ASSERT_EQ(1, valueProducer->mSkippedBuckets[0].dropEvents.size());
1156     EXPECT_EQ(NO_DATA, valueProducer->mSkippedBuckets[0].dropEvents[0].reason);
1157     EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].dropEvents[0].dropTimeNs);
1158 
1159     EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[1].bucketStartTimeNs);
1160     EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[1].bucketEndTimeNs);
1161     ASSERT_EQ(1, valueProducer->mSkippedBuckets[1].dropEvents.size());
1162     EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[1].dropEvents[0].reason);
1163     EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[1].dropEvents[0].dropTimeNs);
1164 }
1165 
1166 /*
1167  * Test pulled event with non sliced condition. The pull on boundary come late because the alarm
1168  * was delivered late.
1169  */
TEST(NumericValueMetricProducerTest,TestBucketBoundaryWithCondition)1170 TEST(NumericValueMetricProducerTest, TestBucketBoundaryWithCondition) {
1171     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
1172 
1173     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1174     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
1175             // condition becomes true
1176             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
1177                                 vector<std::shared_ptr<LogEvent>>* data) {
1178                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);  // First condition change.
1179                 data->clear();
1180                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
1181                 return true;
1182             }))
1183             // condition becomes false
1184             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
1185                                 vector<std::shared_ptr<LogEvent>>* data) {
1186                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1);  // Second condition change.
1187                 data->clear();
1188                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
1189                 return true;
1190             }));
1191     sp<NumericValueMetricProducer> valueProducer =
1192             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
1193                     pullerManager, metric, ConditionState::kFalse);
1194 
1195     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
1196 
1197     // has one slice
1198     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1199     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1200     NumericValueMetricProducer::Interval curInterval =
1201             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1202     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1203     EXPECT_EQ(true, curBase.has_value());
1204     EXPECT_EQ(100, curBase.value().long_value);
1205     EXPECT_EQ(0, curInterval.sampleSize);
1206     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
1207 
1208     // pull on bucket boundary come late, condition change happens before it
1209     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
1210     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1211     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1212     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1213     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {1},
1214                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1215     EXPECT_EQ(false, curBase.has_value());
1216 
1217     // Now the alarm is delivered.
1218     // since the condition turned to off before this pull finish, it has no effect
1219     vector<shared_ptr<LogEvent>> allData;
1220     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 110));
1221     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
1222 
1223     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {1},
1224                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1225     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1226     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1227     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1228     EXPECT_EQ(false, curBase.has_value());
1229 }
1230 
1231 /*
1232  * Test pulled event with non sliced condition. The pull on boundary come late, after the condition
1233  * change to false, and then true again. This is due to alarm delivered late.
1234  */
TEST(NumericValueMetricProducerTest,TestBucketBoundaryWithCondition2)1235 TEST(NumericValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
1236     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
1237 
1238     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1239     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
1240             // condition becomes true
1241             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
1242                                 vector<std::shared_ptr<LogEvent>>* data) {
1243                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
1244                 data->clear();
1245                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
1246                 return true;
1247             }))
1248             // condition becomes false
1249             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
1250                                 vector<std::shared_ptr<LogEvent>>* data) {
1251                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1);
1252                 data->clear();
1253                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
1254                 return true;
1255             }))
1256             // condition becomes true again
1257             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
1258                                 vector<std::shared_ptr<LogEvent>>* data) {
1259                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 25);
1260                 data->clear();
1261                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 25, 130));
1262                 return true;
1263             }));
1264 
1265     sp<NumericValueMetricProducer> valueProducer =
1266             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
1267                     pullerManager, metric, ConditionState::kFalse);
1268 
1269     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
1270 
1271     // has one slice
1272     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1273     NumericValueMetricProducer::Interval curInterval =
1274             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1275     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1276     // startUpdated:false sum:0 start:100
1277     EXPECT_EQ(true, curBase.has_value());
1278     EXPECT_EQ(100, curBase.value().long_value);
1279     EXPECT_EQ(0, curInterval.sampleSize);
1280     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
1281 
1282     // pull on bucket boundary come late, condition change happens before it
1283     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
1284     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {1},
1285                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1286     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1287     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1288     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1289     EXPECT_EQ(false, curBase.has_value());
1290 
1291     // condition changed to true again, before the pull alarm is delivered
1292     valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
1293     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {1},
1294                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1295     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1296     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1297     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1298     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1299     EXPECT_EQ(true, curBase.has_value());
1300     EXPECT_EQ(130, curBase.value().long_value);
1301     EXPECT_EQ(0, curInterval.sampleSize);
1302 
1303     // Now the alarm is delivered, but it is considered late, the data will be used
1304     // for the new bucket since it was just pulled.
1305     vector<shared_ptr<LogEvent>> allData;
1306     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 50, 140));
1307     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 50);
1308 
1309     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1310     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1311     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1312     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1313     EXPECT_EQ(true, curBase.has_value());
1314     EXPECT_EQ(140, curBase.value().long_value);
1315     EXPECT_TRUE(curInterval.hasValue());
1316     EXPECT_EQ(10, curInterval.aggregate.long_value);
1317     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {1},
1318                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1319 
1320     allData.clear();
1321     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 160));
1322     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
1323     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1324     assertPastBucketValuesSingleKey(
1325             valueProducer->mPastBuckets, {20, 30}, {bucketSizeNs - 8, bucketSizeNs - 24}, {1, -1},
1326             {bucketStartTimeNs, bucket2StartTimeNs}, {bucket2StartTimeNs, bucket3StartTimeNs});
1327 }
1328 
TEST(NumericValueMetricProducerTest,TestPushedAggregateMin)1329 TEST(NumericValueMetricProducerTest, TestPushedAggregateMin) {
1330     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1331     metric.set_aggregation_type(ValueMetric::MIN);
1332 
1333     sp<EventMatcherWizard> eventMatcherWizard =
1334             createEventMatcherWizard(tagId, logEventMatcherIndex);
1335     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
1336     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1337 
1338     sp<NumericValueMetricProducer> valueProducer =
1339             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
1340                     pullerManager, metric, /*pullAtomId=*/-1);
1341 
1342     LogEvent event1(/*uid=*/0, /*pid=*/0);
1343     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
1344 
1345     LogEvent event2(/*uid=*/0, /*pid=*/0);
1346     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20);
1347 
1348     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
1349     // has one slice
1350     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1351     NumericValueMetricProducer::Interval curInterval =
1352             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1353     EXPECT_EQ(10, curInterval.aggregate.long_value);
1354     EXPECT_TRUE(curInterval.hasValue());
1355 
1356     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
1357 
1358     // has one slice
1359     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1360     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1361     EXPECT_EQ(10, curInterval.aggregate.long_value);
1362 
1363     valueProducer->flushIfNeededLocked(bucket2StartTimeNs);
1364     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1365     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs}, {0},
1366                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1367 }
1368 
TEST(NumericValueMetricProducerTest,TestPushedAggregateMax)1369 TEST(NumericValueMetricProducerTest, TestPushedAggregateMax) {
1370     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1371     metric.set_aggregation_type(ValueMetric::MAX);
1372 
1373     sp<EventMatcherWizard> eventMatcherWizard =
1374             createEventMatcherWizard(tagId, logEventMatcherIndex);
1375     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
1376     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1377 
1378     sp<NumericValueMetricProducer> valueProducer =
1379             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
1380                     pullerManager, metric, /*pullAtomId=*/-1);
1381 
1382     LogEvent event1(/*uid=*/0, /*pid=*/0);
1383     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
1384     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
1385 
1386     // has one slice
1387     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1388     NumericValueMetricProducer::Interval curInterval =
1389             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1390     EXPECT_EQ(10, curInterval.aggregate.long_value);
1391     EXPECT_TRUE(curInterval.hasValue());
1392 
1393     LogEvent event2(/*uid=*/0, /*pid=*/0);
1394     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20);
1395     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
1396 
1397     // has one slice
1398     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1399     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1400     EXPECT_EQ(20, curInterval.aggregate.long_value);
1401 
1402     valueProducer->flushIfNeededLocked(bucket2StartTimeNs);
1403     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs}, {0},
1404                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1405 }
1406 
TEST(NumericValueMetricProducerTest,TestPushedAggregateAvg)1407 TEST(NumericValueMetricProducerTest, TestPushedAggregateAvg) {
1408     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1409     metric.set_aggregation_type(ValueMetric::AVG);
1410 
1411     sp<EventMatcherWizard> eventMatcherWizard =
1412             createEventMatcherWizard(tagId, logEventMatcherIndex);
1413     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
1414     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1415 
1416     sp<NumericValueMetricProducer> valueProducer =
1417             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
1418                     pullerManager, metric, /*pullAtomId=*/-1);
1419 
1420     EXPECT_TRUE(valueProducer->mIncludeSampleSize);
1421 
1422     LogEvent event1(/*uid=*/0, /*pid=*/0);
1423     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
1424 
1425     LogEvent event2(/*uid=*/0, /*pid=*/0);
1426     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15);
1427     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
1428     // has one slice
1429     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1430     NumericValueMetricProducer::Interval curInterval;
1431     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1432     EXPECT_EQ(1, curInterval.sampleSize);
1433     EXPECT_EQ(10, curInterval.aggregate.long_value);
1434 
1435     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
1436 
1437     // has one slice
1438     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1439     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1440     EXPECT_EQ(25, curInterval.aggregate.long_value);
1441     EXPECT_EQ(2, curInterval.sampleSize);
1442 
1443     valueProducer->flushIfNeededLocked(bucket2StartTimeNs);
1444     ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
1445     ASSERT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
1446 
1447     EXPECT_TRUE(
1448             std::abs(valueProducer->mPastBuckets.begin()->second.back().aggregates[0].double_value -
1449                      12.5) < epsilon);
1450     EXPECT_EQ(2, valueProducer->mPastBuckets.begin()->second.back().sampleSizes[0]);
1451 }
1452 
TEST(NumericValueMetricProducerTest,TestPushedAggregateSum)1453 TEST(NumericValueMetricProducerTest, TestPushedAggregateSum) {
1454     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1455     metric.set_aggregation_type(ValueMetric::SUM);
1456 
1457     sp<EventMatcherWizard> eventMatcherWizard =
1458             createEventMatcherWizard(tagId, logEventMatcherIndex);
1459     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
1460     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1461 
1462     sp<NumericValueMetricProducer> valueProducer =
1463             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
1464                     pullerManager, metric, /*pullAtomId=*/-1);
1465 
1466     LogEvent event1(/*uid=*/0, /*pid=*/0);
1467     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
1468 
1469     LogEvent event2(/*uid=*/0, /*pid=*/0);
1470     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15);
1471     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
1472     // has one slice
1473     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1474     NumericValueMetricProducer::Interval curInterval =
1475             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1476     EXPECT_EQ(10, curInterval.aggregate.long_value);
1477     EXPECT_TRUE(curInterval.hasValue());
1478 
1479     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
1480 
1481     // has one slice
1482     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1483     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1484     EXPECT_EQ(25, curInterval.aggregate.long_value);
1485 
1486     valueProducer->flushIfNeededLocked(bucket2StartTimeNs);
1487     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {25}, {bucketSizeNs}, {0},
1488                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1489 }
1490 
TEST(NumericValueMetricProducerTest,TestSkipZeroDiffOutput)1491 TEST(NumericValueMetricProducerTest, TestSkipZeroDiffOutput) {
1492     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1493     metric.set_aggregation_type(ValueMetric::MIN);
1494     metric.set_use_diff(true);
1495 
1496     sp<EventMatcherWizard> eventMatcherWizard =
1497             createEventMatcherWizard(tagId, logEventMatcherIndex);
1498     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
1499     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1500 
1501     sp<NumericValueMetricProducer> valueProducer =
1502             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
1503                     pullerManager, metric, /*pullAtomId=*/-1);
1504 
1505     LogEvent event1(/*uid=*/0, /*pid=*/0);
1506     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
1507     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
1508 
1509     // has one slice
1510     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1511     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1512     NumericValueMetricProducer::Interval curInterval =
1513             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1514     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1515     EXPECT_EQ(true, curBase.has_value());
1516     EXPECT_EQ(10, curBase.value().long_value);
1517     EXPECT_EQ(0, curInterval.sampleSize);
1518 
1519     LogEvent event2(/*uid=*/0, /*pid=*/0);
1520     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 15);
1521     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
1522 
1523     // has one slice
1524     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1525     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1526     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1527     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1528     EXPECT_EQ(true, curBase.has_value());
1529     EXPECT_EQ(15, curBase.value().long_value);
1530     EXPECT_TRUE(curInterval.hasValue());
1531     EXPECT_EQ(5, curInterval.aggregate.long_value);
1532 
1533     // no change in data.
1534     LogEvent event3(/*uid=*/0, /*pid=*/0);
1535     CreateRepeatedValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 15);
1536     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event3);
1537 
1538     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1539     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1540     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1541     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1542     EXPECT_EQ(true, curBase.has_value());
1543     EXPECT_EQ(15, curBase.value().long_value);
1544     EXPECT_TRUE(curInterval.hasValue());
1545     EXPECT_EQ(0, curInterval.aggregate.long_value);
1546 
1547     LogEvent event4(/*uid=*/0, /*pid=*/0);
1548     CreateRepeatedValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 15);
1549     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event4);
1550     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1551     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1552     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1553     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1554     EXPECT_EQ(true, curBase.has_value());
1555     EXPECT_EQ(15, curBase.value().long_value);
1556     EXPECT_TRUE(curInterval.hasValue());
1557     EXPECT_EQ(0, curInterval.aggregate.long_value);
1558 
1559     valueProducer->flushIfNeededLocked(bucket3StartTimeNs);
1560     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {10},
1561                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1562 }
1563 
TEST(NumericValueMetricProducerTest,TestSkipZeroDiffOutputMultiValue)1564 TEST(NumericValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
1565     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1566     metric.mutable_value_field()->add_child()->set_field(3);
1567     metric.set_aggregation_type(ValueMetric::MIN);
1568     metric.set_use_diff(true);
1569 
1570     sp<EventMatcherWizard> eventMatcherWizard =
1571             createEventMatcherWizard(tagId, logEventMatcherIndex);
1572     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
1573     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1574 
1575     sp<NumericValueMetricProducer> valueProducer =
1576             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
1577                     pullerManager, metric, /*pullAtomId=*/-1);
1578 
1579     LogEvent event1(/*uid=*/0, /*pid=*/0);
1580     CreateThreeValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10, 20);
1581 
1582     LogEvent event2(/*uid=*/0, /*pid=*/0);
1583     CreateThreeValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 1, 15, 22);
1584 
1585     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
1586     // has one slice
1587     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1588     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1589     NumericValueMetricProducer::Interval curInterval =
1590             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1591     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1592     EXPECT_EQ(true, curBase.has_value());
1593     EXPECT_EQ(10, curBase.value().long_value);
1594     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[1];
1595     EXPECT_EQ(true, curBase.has_value());
1596     EXPECT_EQ(20, curBase.value().long_value);
1597     EXPECT_EQ(0, curInterval.sampleSize);
1598 
1599     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
1600 
1601     // has one slice
1602     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1603     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1604     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1605     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1606     EXPECT_EQ(true, curBase.has_value());
1607     EXPECT_EQ(15, curBase.value().long_value);
1608     EXPECT_TRUE(curInterval.hasValue());
1609     EXPECT_EQ(5, curInterval.aggregate.long_value);
1610     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[1];
1611     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[1];
1612     EXPECT_EQ(true, curBase.has_value());
1613     EXPECT_EQ(22, curBase.value().long_value);
1614     EXPECT_TRUE(curInterval.hasValue());
1615     EXPECT_EQ(2, curInterval.aggregate.long_value);
1616 
1617     // no change in first value field
1618     LogEvent event3(/*uid=*/0, /*pid=*/0);
1619     CreateThreeValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 1, 15, 25);
1620 
1621     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event3);
1622     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1623     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1624     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1625     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1626     EXPECT_EQ(true, curBase.has_value());
1627     EXPECT_EQ(15, curBase.value().long_value);
1628     EXPECT_TRUE(curInterval.hasValue());
1629     EXPECT_EQ(0, curInterval.aggregate.long_value);
1630     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[1];
1631     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[1];
1632     EXPECT_EQ(true, curBase.has_value());
1633     EXPECT_EQ(25, curBase.value().long_value);
1634     EXPECT_TRUE(curInterval.hasValue());
1635     EXPECT_EQ(3, curInterval.aggregate.long_value);
1636 
1637     LogEvent event4(/*uid=*/0, /*pid=*/0);
1638     CreateThreeValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 1, 15, 29);
1639 
1640     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event4);
1641     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1642     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1643     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1644     EXPECT_EQ(true, curBase.has_value());
1645     EXPECT_EQ(15, curBase.value().long_value);
1646     EXPECT_TRUE(curInterval.hasValue());
1647     EXPECT_EQ(0, curInterval.aggregate.long_value);
1648     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[1];
1649     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[1];
1650     EXPECT_EQ(true, curBase.has_value());
1651     EXPECT_EQ(29, curBase.value().long_value);
1652     EXPECT_TRUE(curInterval.hasValue());
1653     EXPECT_EQ(3, curInterval.aggregate.long_value);
1654 
1655     valueProducer->flushIfNeededLocked(bucket3StartTimeNs);
1656 
1657     ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
1658     ASSERT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
1659     ASSERT_EQ(2UL, valueProducer->mPastBuckets.begin()->second[0].aggregates.size());
1660     ASSERT_EQ(1UL, valueProducer->mPastBuckets.begin()->second[1].aggregates.size());
1661 
1662     EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
1663     EXPECT_EQ(5, valueProducer->mPastBuckets.begin()->second[0].aggregates[0].long_value);
1664     EXPECT_EQ(0, valueProducer->mPastBuckets.begin()->second[0].aggIndex[0]);
1665     EXPECT_EQ(2, valueProducer->mPastBuckets.begin()->second[0].aggregates[1].long_value);
1666     EXPECT_EQ(1, valueProducer->mPastBuckets.begin()->second[0].aggIndex[1]);
1667 
1668     EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
1669     EXPECT_EQ(3, valueProducer->mPastBuckets.begin()->second[1].aggregates[0].long_value);
1670     EXPECT_EQ(1, valueProducer->mPastBuckets.begin()->second[1].aggIndex[0]);
1671 }
1672 
1673 /*
1674  * Tests zero default base.
1675  */
TEST(NumericValueMetricProducerTest,TestUseZeroDefaultBase)1676 TEST(NumericValueMetricProducerTest, TestUseZeroDefaultBase) {
1677     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1678     metric.mutable_dimensions_in_what()->set_field(tagId);
1679     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
1680     metric.set_use_zero_default_base(true);
1681 
1682     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1683     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
1684             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
1685                                 vector<std::shared_ptr<LogEvent>>* data) {
1686                 data->clear();
1687                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
1688                 return true;
1689             }));
1690 
1691     sp<NumericValueMetricProducer> valueProducer =
1692             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
1693                                                                                   metric);
1694 
1695     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1696     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1697     auto iter = valueProducer->mCurrentSlicedBucket.begin();
1698     auto& interval1 = iter->second.intervals[0];
1699     auto iterBase = valueProducer->mDimInfos.begin();
1700     auto& base1 = iterBase->second.dimExtras[0];
1701     EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
1702     EXPECT_EQ(true, base1.has_value());
1703     EXPECT_EQ(3, base1.value().long_value);
1704     EXPECT_EQ(0, interval1.sampleSize);
1705     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
1706     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
1707     vector<shared_ptr<LogEvent>> allData;
1708 
1709     allData.clear();
1710     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
1711     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
1712 
1713     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
1714     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1715     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
1716     EXPECT_EQ(true, base1.has_value());
1717     EXPECT_EQ(11, base1.value().long_value);
1718 
1719     auto itBase = valueProducer->mDimInfos.begin();
1720     for (; itBase != valueProducer->mDimInfos.end(); itBase++) {
1721         if (itBase != iterBase) {
1722             break;
1723         }
1724     }
1725     EXPECT_TRUE(itBase != iterBase);
1726     auto& base2 = itBase->second.dimExtras[0];
1727     EXPECT_EQ(true, base2.has_value());
1728     EXPECT_EQ(4, base2.value().long_value);
1729 
1730     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
1731     auto iterator = valueProducer->mPastBuckets.begin();
1732     EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
1733     EXPECT_EQ(8, iterator->second[0].aggregates[0].long_value);
1734     iterator++;
1735     EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
1736     EXPECT_EQ(4, iterator->second[0].aggregates[0].long_value);
1737 }
1738 
1739 /*
1740  * Tests using zero default base with failed pull.
1741  */
TEST(NumericValueMetricProducerTest,TestUseZeroDefaultBaseWithPullFailures)1742 TEST(NumericValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
1743     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1744     metric.mutable_dimensions_in_what()->set_field(tagId);
1745     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
1746     metric.set_use_zero_default_base(true);
1747 
1748     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1749     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
1750             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
1751                                 vector<std::shared_ptr<LogEvent>>* data) {
1752                 data->clear();
1753                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
1754                 return true;
1755             }));
1756 
1757     sp<NumericValueMetricProducer> valueProducer =
1758             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
1759                                                                                   metric);
1760 
1761     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1762     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1763     const auto& it = valueProducer->mCurrentSlicedBucket.begin();
1764     NumericValueMetricProducer::Interval& interval1 = it->second.intervals[0];
1765     optional<Value>& base1 =
1766             valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat())->second.dimExtras[0];
1767     EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
1768     EXPECT_EQ(true, base1.has_value());
1769     EXPECT_EQ(3, base1.value().long_value);
1770     EXPECT_EQ(0, interval1.sampleSize);
1771     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
1772     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
1773     vector<shared_ptr<LogEvent>> allData;
1774 
1775     allData.clear();
1776     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
1777     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
1778 
1779     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
1780     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1781     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
1782     EXPECT_EQ(true, base1.has_value());
1783     EXPECT_EQ(11, base1.value().long_value);
1784 
1785     auto itBase2 = valueProducer->mDimInfos.begin();
1786     for (; itBase2 != valueProducer->mDimInfos.end(); itBase2++) {
1787         if (itBase2->second.dimExtras[0] != base1) {
1788             break;
1789         }
1790     }
1791     optional<Value>& base2 = itBase2->second.dimExtras[0];
1792     EXPECT_TRUE(base2 != base1);
1793     EXPECT_EQ(2, itBase2->first.getValues()[0].mValue.int_value);
1794     EXPECT_EQ(true, base2.has_value());
1795     EXPECT_EQ(4, base2.value().long_value);
1796     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
1797 
1798     // next pull somehow did not happen, skip to end of bucket 3
1799     // This pull is incomplete since it's missing dimension 1. Will cause mDimInfos to be trimmed
1800     allData.clear();
1801     allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 2, 5));
1802     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
1803 
1804     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1805     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1806     EXPECT_EQ(2, valueProducer->mDimInfos.begin()->first.getValues()[0].mValue.int_value);
1807     optional<Value>& base3 = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1808     EXPECT_EQ(true, base3.has_value());
1809     EXPECT_EQ(5, base3.value().long_value);
1810     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
1811     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
1812 
1813     allData.clear();
1814     allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 13));
1815     allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 1, 5));
1816     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket5StartTimeNs);
1817 
1818     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1819     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
1820     optional<Value>& base4 = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1821     optional<Value>& base5 = std::next(valueProducer->mDimInfos.begin())->second.dimExtras[0];
1822 
1823     EXPECT_EQ(true, base4.has_value());
1824     EXPECT_EQ(5, base4.value().long_value);
1825     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
1826     EXPECT_EQ(true, base5.has_value());
1827     EXPECT_EQ(13, base5.value().long_value);
1828 
1829     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
1830 }
1831 
1832 /*
1833  * Tests trim unused dimension key if no new data is seen in an entire bucket.
1834  */
TEST(NumericValueMetricProducerTest,TestTrimUnusedDimensionKey)1835 TEST(NumericValueMetricProducerTest, TestTrimUnusedDimensionKey) {
1836     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
1837     metric.mutable_dimensions_in_what()->set_field(tagId);
1838     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
1839 
1840     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1841     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
1842             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
1843                                 vector<std::shared_ptr<LogEvent>>* data) {
1844                 data->clear();
1845                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
1846                 return true;
1847             }));
1848 
1849     sp<NumericValueMetricProducer> valueProducer =
1850             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
1851                                                                                   metric);
1852 
1853     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1854     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1855     auto iter = valueProducer->mCurrentSlicedBucket.begin();
1856     auto& interval1 = iter->second.intervals[0];
1857     auto iterBase = valueProducer->mDimInfos.begin();
1858     auto& base1 = iterBase->second.dimExtras[0];
1859     EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
1860     EXPECT_EQ(true, base1.has_value());
1861     EXPECT_EQ(3, base1.value().long_value);
1862     EXPECT_EQ(0, interval1.sampleSize);
1863     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
1864 
1865     vector<shared_ptr<LogEvent>> allData;
1866     allData.clear();
1867     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
1868     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
1869     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
1870 
1871     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1872     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
1873     EXPECT_EQ(true, base1.has_value());
1874     EXPECT_EQ(11, base1.value().long_value);
1875     EXPECT_FALSE(iterBase->second.seenNewData);
1876     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs}, {0},
1877                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1878 
1879     auto itBase = valueProducer->mDimInfos.begin();
1880     for (; itBase != valueProducer->mDimInfos.end(); itBase++) {
1881         if (itBase != iterBase) {
1882             break;
1883         }
1884     }
1885     EXPECT_TRUE(itBase != iterBase);
1886     auto base2 = itBase->second.dimExtras[0];
1887     EXPECT_EQ(2, itBase->first.getValues()[0].mValue.int_value);
1888     EXPECT_EQ(true, base2.has_value());
1889     EXPECT_EQ(4, base2.value().long_value);
1890     EXPECT_FALSE(itBase->second.seenNewData);
1891 
1892     // next pull somehow did not happen, skip to end of bucket 3
1893     allData.clear();
1894     allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 2, 5));
1895     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
1896     // Only one dimension left. One was trimmed.
1897     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1898     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1899     base2 = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1900     EXPECT_EQ(2, valueProducer->mDimInfos.begin()->first.getValues()[0].mValue.int_value);
1901     EXPECT_EQ(true, base2.has_value());
1902     EXPECT_EQ(5, base2.value().long_value);
1903     EXPECT_FALSE(valueProducer->mDimInfos.begin()->second.seenNewData);
1904     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs}, {0},
1905                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
1906 
1907     allData.clear();
1908     allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 14));
1909     allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 1, 14));
1910     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket5StartTimeNs);
1911 
1912     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1913     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
1914 
1915     allData.clear();
1916     allData.push_back(CreateTwoValueLogEvent(tagId, bucket6StartTimeNs + 1, 1, 19));
1917     allData.push_back(CreateTwoValueLogEvent(tagId, bucket6StartTimeNs + 1, 2, 20));
1918     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket6StartTimeNs);
1919 
1920     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1921     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
1922 
1923     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
1924     // Dimension = 2
1925     auto iterator = valueProducer->mPastBuckets.begin();
1926     ASSERT_EQ(1, iterator->first.getDimensionKeyInWhat().getValues().size());
1927     EXPECT_EQ(2, iterator->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
1928     ASSERT_EQ(2, iterator->second.size());
1929     EXPECT_EQ(bucket4StartTimeNs, iterator->second[0].mBucketStartNs);
1930     EXPECT_EQ(bucket5StartTimeNs, iterator->second[0].mBucketEndNs);
1931     EXPECT_EQ(9, iterator->second[0].aggregates[0].long_value);
1932     EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
1933     EXPECT_EQ(bucket5StartTimeNs, iterator->second[1].mBucketStartNs);
1934     EXPECT_EQ(bucket6StartTimeNs, iterator->second[1].mBucketEndNs);
1935     EXPECT_EQ(6, iterator->second[1].aggregates[0].long_value);
1936     EXPECT_EQ(bucketSizeNs, iterator->second[1].mConditionTrueNs);
1937     iterator++;
1938     // Dimension = 1
1939     ASSERT_EQ(1, iterator->first.getDimensionKeyInWhat().getValues().size());
1940     EXPECT_EQ(1, iterator->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
1941     ASSERT_EQ(2, iterator->second.size());
1942     EXPECT_EQ(bucketStartTimeNs, iterator->second[0].mBucketStartNs);
1943     EXPECT_EQ(bucket2StartTimeNs, iterator->second[0].mBucketEndNs);
1944     EXPECT_EQ(8, iterator->second[0].aggregates[0].long_value);
1945     EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
1946     EXPECT_EQ(bucket5StartTimeNs, iterator->second[1].mBucketStartNs);
1947     EXPECT_EQ(bucket6StartTimeNs, iterator->second[1].mBucketEndNs);
1948     EXPECT_EQ(5, iterator->second[1].aggregates[0].long_value);
1949     EXPECT_EQ(bucketSizeNs, iterator->second[1].mConditionTrueNs);
1950 }
1951 
TEST(NumericValueMetricProducerTest,TestResetBaseOnPullFailAfterConditionChange_EndOfBucket)1952 TEST(NumericValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
1953     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
1954 
1955     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1956     // Used by onConditionChanged.
1957     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _))
1958             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
1959                                 vector<std::shared_ptr<LogEvent>>* data) {
1960                 data->clear();
1961                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
1962                 return true;
1963             }));
1964 
1965     sp<NumericValueMetricProducer> valueProducer =
1966             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
1967                     pullerManager, metric, ConditionState::kFalse);
1968 
1969     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
1970     // has one slice
1971     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
1972     NumericValueMetricProducer::Interval& curInterval =
1973             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
1974     optional<Value>& curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
1975     EXPECT_EQ(true, curBase.has_value());
1976     EXPECT_EQ(100, curBase.value().long_value);
1977     EXPECT_EQ(0, curInterval.sampleSize);
1978 
1979     vector<shared_ptr<LogEvent>> allData;
1980     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_FAIL, bucket2StartTimeNs);
1981     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
1982     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
1983     EXPECT_EQ(false, curBase.has_value());
1984     EXPECT_EQ(false, valueProducer->mHasGlobalBase);
1985     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
1986     ASSERT_EQ(1UL, valueProducer->mSkippedBuckets.size());
1987 }
1988 
TEST(NumericValueMetricProducerTest,TestResetBaseOnPullFailAfterConditionChange)1989 TEST(NumericValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
1990     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
1991 
1992     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
1993     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
1994             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
1995                                 vector<std::shared_ptr<LogEvent>>* data) {
1996                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);  // Condition change to true.
1997                 data->clear();
1998                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
1999                 return true;
2000             }))
2001             .WillOnce(Return(false));
2002 
2003     sp<NumericValueMetricProducer> valueProducer =
2004             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2005                     pullerManager, metric, ConditionState::kFalse);
2006 
2007     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
2008 
2009     // has one slice
2010     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2011     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2012     NumericValueMetricProducer::Interval& curInterval =
2013             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2014     optional<Value>& curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2015     EXPECT_EQ(true, curBase.has_value());
2016     EXPECT_EQ(100, curBase.value().long_value);
2017     EXPECT_EQ(0, curInterval.sampleSize);
2018     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
2019 
2020     valueProducer->onConditionChanged(false, bucketStartTimeNs + 20);
2021 
2022     // has one slice
2023     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2024     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2025     EXPECT_EQ(0, curInterval.sampleSize);
2026     EXPECT_EQ(false, curBase.has_value());
2027     EXPECT_EQ(false, valueProducer->mHasGlobalBase);
2028 }
2029 
TEST(NumericValueMetricProducerTest,TestResetBaseOnPullFailBeforeConditionChange)2030 TEST(NumericValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
2031     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2032 
2033     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2034     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2035             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2036                                 vector<std::shared_ptr<LogEvent>>* data) {
2037                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
2038                 data->clear();
2039                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 50));
2040                 return false;
2041             }))
2042             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2043                                 vector<std::shared_ptr<LogEvent>>* data) {
2044                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1);  // Condition change to false.
2045                 data->clear();
2046                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
2047                 return true;
2048             }));
2049 
2050     sp<NumericValueMetricProducer> valueProducer =
2051             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2052                     pullerManager, metric, ConditionState::kFalse);
2053 
2054     valueProducer->onConditionChanged(true, bucketStartTimeNs);
2055     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2056     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
2057 
2058     valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
2059     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2060     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2061     NumericValueMetricProducer::Interval& curInterval =
2062             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2063     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2064     EXPECT_EQ(false, curBase.has_value());
2065     EXPECT_EQ(0, curInterval.sampleSize);
2066     EXPECT_EQ(false, valueProducer->mHasGlobalBase);
2067 }
2068 
TEST(NumericValueMetricProducerTest,TestResetBaseOnPullDelayExceeded)2069 TEST(NumericValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
2070     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2071     metric.set_condition(StringToId("SCREEN_ON"));
2072     metric.set_max_pull_delay_sec(0);
2073 
2074     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2075     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _))
2076             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
2077                                 vector<std::shared_ptr<LogEvent>>* data) {
2078                 data->clear();
2079                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 120));
2080                 return true;
2081             }));
2082 
2083     sp<NumericValueMetricProducer> valueProducer =
2084             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2085                     pullerManager, metric, ConditionState::kFalse);
2086 
2087     // Max delay is set to 0 so pull will exceed max delay.
2088     valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
2089     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2090 }
2091 
TEST(NumericValueMetricProducerTest,TestResetBaseOnPullTooLate)2092 TEST(NumericValueMetricProducerTest, TestResetBaseOnPullTooLate) {
2093     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2094 
2095     sp<EventMatcherWizard> eventMatcherWizard =
2096             createEventMatcherWizard(tagId, logEventMatcherIndex);
2097     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
2098     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2099 
2100     sp<NumericValueMetricProducer> valueProducer =
2101             NumericValueMetricProducerTestHelper::createValueProducer(
2102                     pullerManager, metric, tagId, ConditionState::kFalse,
2103                     /*slicedStateAtoms=*/{},
2104                     /*stateGroupMap=*/{}, bucket2StartTimeNs, bucket2StartTimeNs,
2105                     eventMatcherWizard);
2106 
2107     // Event should be skipped since it is from previous bucket.
2108     // Pull should not be called.
2109     valueProducer->onConditionChanged(true, bucketStartTimeNs);
2110     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2111 }
2112 
TEST(NumericValueMetricProducerTest,TestBaseSetOnConditionChange)2113 TEST(NumericValueMetricProducerTest, TestBaseSetOnConditionChange) {
2114     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2115 
2116     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2117     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _))
2118             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
2119                                 vector<std::shared_ptr<LogEvent>>* data) {
2120                 data->clear();
2121                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100));
2122                 return true;
2123             }));
2124 
2125     sp<NumericValueMetricProducer> valueProducer =
2126             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2127                     pullerManager, metric, ConditionState::kFalse);
2128 
2129     valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
2130     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2131     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2132     NumericValueMetricProducer::Interval& curInterval =
2133             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2134     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2135     EXPECT_EQ(true, curBase.has_value());
2136     EXPECT_EQ(100, curBase.value().long_value);
2137     EXPECT_EQ(0, curInterval.sampleSize);
2138     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
2139 }
2140 
2141 /*
2142  * Tests that a bucket is marked invalid when a condition change pull fails.
2143  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenOneConditionFailed)2144 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed) {
2145     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2146 
2147     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2148     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2149             // First onConditionChanged
2150             .WillOnce(Return(false))
2151             // Second onConditionChanged
2152             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2153                                 vector<std::shared_ptr<LogEvent>>* data) {
2154                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
2155                 data->clear();
2156                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
2157                 return true;
2158             }));
2159 
2160     sp<NumericValueMetricProducer> valueProducer =
2161             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2162                     pullerManager, metric, ConditionState::kTrue);
2163 
2164     // Bucket start.
2165     vector<shared_ptr<LogEvent>> allData;
2166     allData.clear();
2167     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110));
2168     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucketStartTimeNs);
2169 
2170     // This will fail and should invalidate the whole bucket since we do not have all the data
2171     // needed to compute the metric value when the screen was on.
2172     valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
2173     valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
2174 
2175     // Bucket end.
2176     allData.clear();
2177     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140));
2178     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2179 
2180     valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
2181 
2182     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
2183     // Contains base from last pull which was successful.
2184     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2185     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2186     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2187     EXPECT_EQ(true, curBase.has_value());
2188     EXPECT_EQ(140, curBase.value().long_value);
2189     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
2190 
2191     // Check dump report.
2192     ProtoOutputStream output;
2193     std::set<string> strSet;
2194     valueProducer->onDumpReport(bucket2StartTimeNs + 10, false /* include partial bucket */, true,
2195                                 FAST /* dumpLatency */, &strSet, &output);
2196 
2197     StatsLogReport report = outputStreamToProto(&output);
2198     EXPECT_TRUE(report.has_value_metrics());
2199     ASSERT_EQ(0, report.value_metrics().data_size());
2200     ASSERT_EQ(1, report.value_metrics().skipped_size());
2201 
2202     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
2203               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
2204     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
2205               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
2206     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
2207 
2208     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
2209     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
2210     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
2211 }
2212 
2213 /*
2214  * Tests that a bucket is marked invalid when the guardrail is hit.
2215  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenGuardRailHit)2216 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit) {
2217     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2218     metric.mutable_dimensions_in_what()->set_field(tagId);
2219     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
2220     metric.set_condition(StringToId("SCREEN_ON"));
2221 
2222     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2223     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 2, _))
2224             // First onConditionChanged
2225             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
2226                                 vector<std::shared_ptr<LogEvent>>* data) {
2227                 for (int i = 0; i < 2000; i++) {
2228                     data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i));
2229                 }
2230                 return true;
2231             }));
2232 
2233     sp<NumericValueMetricProducer> valueProducer =
2234             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2235                     pullerManager, metric, ConditionState::kFalse);
2236 
2237     ASSERT_EQ(false, StatsdStats::getInstance().hasHitDimensionGuardrail(metricId));
2238     valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
2239     EXPECT_EQ(true, valueProducer->mCurrentBucketIsSkipped);
2240     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2241     ASSERT_EQ(0UL, valueProducer->mSkippedBuckets.size());
2242     ASSERT_EQ(true, StatsdStats::getInstance().hasHitDimensionGuardrail(metricId));
2243 
2244     // Bucket 2 start.
2245     vector<shared_ptr<LogEvent>> allData;
2246     allData.clear();
2247     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 10));
2248     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2249 
2250     // First bucket added to mSkippedBuckets after flush.
2251     ASSERT_EQ(1UL, valueProducer->mSkippedBuckets.size());
2252 
2253     // Check dump report.
2254     ProtoOutputStream output;
2255     std::set<string> strSet;
2256     valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
2257                                 true, FAST /* dumpLatency */, &strSet, &output);
2258     ASSERT_EQ(true, StatsdStats::getInstance().hasHitDimensionGuardrail(metricId));
2259 
2260     StatsLogReport report = outputStreamToProto(&output);
2261     EXPECT_TRUE(report.dimension_guardrail_hit());
2262     EXPECT_TRUE(report.has_value_metrics());
2263     ASSERT_EQ(0, report.value_metrics().data_size());
2264     ASSERT_EQ(1, report.value_metrics().skipped_size());
2265 
2266     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
2267               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
2268     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
2269               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
2270     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
2271 
2272     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
2273     EXPECT_EQ(BucketDropReason::DIMENSION_GUARDRAIL_REACHED, dropEvent.drop_reason());
2274     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
2275 }
2276 
2277 /*
2278  * Tests that a bucket is marked invalid when the bucket's initial pull fails.
2279  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenInitialPullFailed)2280 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) {
2281     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2282 
2283     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2284     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2285             // First onConditionChanged
2286             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2287                                 vector<std::shared_ptr<LogEvent>>* data) {
2288                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 2);
2289                 data->clear();
2290                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120));
2291                 return true;
2292             }))
2293             // Second onConditionChanged
2294             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2295                                 vector<std::shared_ptr<LogEvent>>* data) {
2296                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
2297                 data->clear();
2298                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
2299                 return true;
2300             }));
2301 
2302     sp<NumericValueMetricProducer> valueProducer =
2303             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2304                     pullerManager, metric, ConditionState::kTrue);
2305 
2306     // Bucket start.
2307     vector<shared_ptr<LogEvent>> allData;
2308     allData.clear();
2309     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110));
2310     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_FAIL, bucketStartTimeNs);
2311 
2312     valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
2313     valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
2314 
2315     // Bucket end.
2316     allData.clear();
2317     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140));
2318     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2319 
2320     valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
2321 
2322     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
2323     // Contains base from last pull which was successful.
2324     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2325     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2326     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2327     EXPECT_EQ(true, curBase.has_value());
2328     EXPECT_EQ(140, curBase.value().long_value);
2329     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
2330 
2331     // Check dump report.
2332     ProtoOutputStream output;
2333     std::set<string> strSet;
2334     valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
2335                                 true, FAST /* dumpLatency */, &strSet, &output);
2336 
2337     StatsLogReport report = outputStreamToProto(&output);
2338     EXPECT_TRUE(report.has_value_metrics());
2339     ASSERT_EQ(0, report.value_metrics().data_size());
2340     ASSERT_EQ(1, report.value_metrics().skipped_size());
2341 
2342     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
2343               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
2344     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
2345               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
2346     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
2347 
2348     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
2349     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
2350     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
2351 }
2352 
2353 /*
2354  * Tests that a bucket is marked invalid when the bucket's final pull fails
2355  * (i.e. failed pull on bucket boundary).
2356  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenLastPullFailed)2357 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) {
2358     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2359 
2360     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2361     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2362             // First onConditionChanged
2363             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2364                                 vector<std::shared_ptr<LogEvent>>* data) {
2365                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 2);
2366                 data->clear();
2367                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120));
2368                 return true;
2369             }))
2370             // Second onConditionChanged
2371             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2372                                 vector<std::shared_ptr<LogEvent>>* data) {
2373                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
2374                 data->clear();
2375                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
2376                 return true;
2377             }));
2378 
2379     sp<NumericValueMetricProducer> valueProducer =
2380             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2381                     pullerManager, metric, ConditionState::kTrue);
2382 
2383     // Bucket start.
2384     vector<shared_ptr<LogEvent>> allData;
2385     allData.clear();
2386     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110));
2387     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucketStartTimeNs);
2388 
2389     valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
2390     valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
2391 
2392     // Bucket end.
2393     allData.clear();
2394     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140));
2395     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_FAIL, bucket2StartTimeNs);
2396 
2397     valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
2398 
2399     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
2400     // Last pull failed so base has been reset.
2401     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2402     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2403     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2404     EXPECT_EQ(false, curBase.has_value());
2405     EXPECT_EQ(false, valueProducer->mHasGlobalBase);
2406 
2407     // Check dump report.
2408     ProtoOutputStream output;
2409     std::set<string> strSet;
2410     valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
2411                                 true, FAST /* dumpLatency */, &strSet, &output);
2412 
2413     StatsLogReport report = outputStreamToProto(&output);
2414     EXPECT_TRUE(report.has_value_metrics());
2415     ASSERT_EQ(0, report.value_metrics().data_size());
2416     ASSERT_EQ(1, report.value_metrics().skipped_size());
2417 
2418     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
2419               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
2420     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
2421               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
2422     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
2423 
2424     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
2425     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
2426     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis());
2427 }
2428 
TEST(NumericValueMetricProducerTest,TestEmptyDataResetsBase_onDataPulled)2429 TEST(NumericValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
2430     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2431     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2432     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
2433             // Start bucket.
2434             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
2435                                 vector<std::shared_ptr<LogEvent>>* data) {
2436                 data->clear();
2437                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
2438                 return true;
2439             }));
2440 
2441     sp<NumericValueMetricProducer> valueProducer =
2442             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
2443                                                                                   metric);
2444 
2445     // Bucket 2 start.
2446     vector<shared_ptr<LogEvent>> allData;
2447     allData.clear();
2448     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
2449     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2450     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2451     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2452     EXPECT_EQ(valueProducer->mDimInfos.begin()->second.seenNewData, false);
2453     ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
2454     ASSERT_EQ(0UL, valueProducer->mSkippedBuckets.size());
2455 
2456     // Bucket 3 empty.
2457     allData.clear();
2458     allData.push_back(CreateNoValuesLogEvent(tagId, bucket3StartTimeNs + 1));
2459     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
2460     // Data has been trimmed.
2461     ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
2462     ASSERT_EQ(1UL, valueProducer->mSkippedBuckets.size());
2463     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2464     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
2465 
2466     // Bucket 4 start.
2467     allData.clear();
2468     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 150));
2469     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
2470     ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
2471     ASSERT_EQ(2UL, valueProducer->mSkippedBuckets.size());
2472     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2473     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2474 
2475     // Bucket 5 start.
2476     allData.clear();
2477     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket5StartTimeNs + 1, 170));
2478     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket5StartTimeNs);
2479     assertPastBucketValuesSingleKey(
2480             valueProducer->mPastBuckets, {107, 20}, {bucketSizeNs, bucketSizeNs}, {0, 0},
2481             {bucketStartTimeNs, bucket4StartTimeNs}, {bucket2StartTimeNs, bucket5StartTimeNs});
2482     ASSERT_EQ(2UL, valueProducer->mSkippedBuckets.size());
2483     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2484     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2485 }
2486 
TEST(NumericValueMetricProducerTest,TestEmptyDataResetsBase_onConditionChanged)2487 TEST(NumericValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
2488     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2489 
2490     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2491     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2492             // First onConditionChanged
2493             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2494                                 vector<std::shared_ptr<LogEvent>>* data) {
2495                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
2496                 data->clear();
2497                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
2498                 return true;
2499             }))
2500             // Empty pull when change to false
2501             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2502                                 vector<std::shared_ptr<LogEvent>>* data) {
2503                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20);
2504                 data->clear();
2505                 return true;
2506             }))
2507             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2508                                 vector<std::shared_ptr<LogEvent>>* data) {
2509                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30);
2510                 data->clear();
2511                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
2512                 return true;
2513             }));
2514 
2515     sp<NumericValueMetricProducer> valueProducer =
2516             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2517                     pullerManager, metric, ConditionState::kFalse);
2518 
2519     valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
2520     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2521     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2522     NumericValueMetricProducer::Interval& curInterval =
2523             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2524     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2525     EXPECT_EQ(true, curBase.has_value());
2526     EXPECT_EQ(0, curInterval.sampleSize);
2527     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
2528 
2529     // Empty pull.
2530     valueProducer->onConditionChanged(false, bucketStartTimeNs + 20);
2531     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2532     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
2533     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2534     EXPECT_EQ(0, curInterval.sampleSize);
2535     EXPECT_EQ(false, valueProducer->mHasGlobalBase);
2536 
2537     valueProducer->onConditionChanged(true, bucketStartTimeNs + 30);
2538     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2539     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2540     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2541     EXPECT_EQ(0, curInterval.sampleSize);
2542     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2543     EXPECT_EQ(true, curBase.has_value());
2544     EXPECT_EQ(10, curBase.value().long_value);
2545     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
2546 
2547     vector<shared_ptr<LogEvent>> allData;
2548     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
2549     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2550     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2551     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2552     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2553     EXPECT_EQ(true, curBase.has_value());
2554     EXPECT_EQ(120, curBase.value().long_value);
2555     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
2556     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {110}, {bucketSizeNs - 20}, {0},
2557                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
2558 }
2559 
TEST(NumericValueMetricProducerTest,TestEmptyDataResetsBase_onBucketBoundary)2560 TEST(NumericValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
2561     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2562 
2563     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2564     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2565             // First onConditionChanged
2566             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2567                                 vector<std::shared_ptr<LogEvent>>* data) {
2568                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
2569                 data->clear();
2570                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
2571                 return true;
2572             }))
2573             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2574                                 vector<std::shared_ptr<LogEvent>>* data) {
2575                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 11);
2576                 data->clear();
2577                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 2));
2578                 return true;
2579             }))
2580             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2581                                 vector<std::shared_ptr<LogEvent>>* data) {
2582                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 12);
2583                 data->clear();
2584                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 5));
2585                 return true;
2586             }));
2587 
2588     sp<NumericValueMetricProducer> valueProducer =
2589             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2590                     pullerManager, metric, ConditionState::kFalse);
2591 
2592     valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
2593     valueProducer->onConditionChanged(false, bucketStartTimeNs + 11);
2594     valueProducer->onConditionChanged(true, bucketStartTimeNs + 12);
2595     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2596     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2597     NumericValueMetricProducer::Interval& curInterval =
2598             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2599     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2600     EXPECT_EQ(true, curBase.has_value());
2601     EXPECT_TRUE(curInterval.hasValue());
2602     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
2603 
2604     // End of bucket
2605     vector<shared_ptr<LogEvent>> allData;
2606     allData.clear();
2607     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2608     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2609     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
2610 
2611     ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
2612     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {1}, {bucketSizeNs - 12 + 1}, {0},
2613                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
2614 }
2615 
TEST(NumericValueMetricProducerTest,TestPartialResetOnBucketBoundaries)2616 TEST(NumericValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
2617     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2618     metric.mutable_dimensions_in_what()->set_field(tagId);
2619     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
2620     metric.set_condition(StringToId("SCREEN_ON"));
2621 
2622     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2623     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _))
2624             // First onConditionChanged
2625             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
2626                                 vector<std::shared_ptr<LogEvent>>* data) {
2627                 data->clear();
2628                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
2629                 return true;
2630             }));
2631 
2632     sp<NumericValueMetricProducer> valueProducer =
2633             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2634                     pullerManager, metric, ConditionState::kFalse);
2635 
2636     valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
2637     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2638     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2639 
2640     // End of bucket
2641     vector<shared_ptr<LogEvent>> allData;
2642     allData.clear();
2643     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 2));
2644     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2645 
2646     // Key 1 should be removed from mDimInfos since in not present in the most pull.
2647     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2648     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2649     auto baseInfoIter = valueProducer->mDimInfos.begin();
2650     EXPECT_EQ(true, baseInfoIter->second.dimExtras[0].has_value());
2651     EXPECT_EQ(2, baseInfoIter->second.dimExtras[0].value().long_value);
2652 
2653     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
2654 }
2655 
TEST_P(NumericValueMetricProducerTest_PartialBucket,TestFullBucketResetWhenLastBucketInvalid)2656 TEST_P(NumericValueMetricProducerTest_PartialBucket, TestFullBucketResetWhenLastBucketInvalid) {
2657     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2658 
2659     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2660     int64_t partialBucketSplitTimeNs = bucketStartTimeNs + bucketSizeNs / 2;
2661     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2662             // Initialization.
2663             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2664                                 vector<std::shared_ptr<LogEvent>>* data) {
2665                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
2666                 data->clear();
2667                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
2668                 return true;
2669             }))
2670             // notifyAppUpgrade.
2671             .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
2672                                                         const int64_t eventTimeNs,
2673                                                         vector<std::shared_ptr<LogEvent>>* data) {
2674                 EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
2675                 data->clear();
2676                 data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 10));
2677                 return true;
2678             }));
2679     sp<NumericValueMetricProducer> valueProducer =
2680             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
2681                                                                                   metric);
2682 
2683     sp<AlarmMonitor> alarmMonitor;
2684     Alert alert;
2685     alert.set_id(101);
2686     alert.set_metric_id(metricId);
2687     alert.set_trigger_if_sum_gt(100);
2688     alert.set_num_buckets(1);
2689     alert.set_refractory_period_secs(3);
2690     sp<AnomalyTracker> anomalyTracker =
2691             valueProducer->addAnomalyTracker(alert, alarmMonitor, UPDATE_NEW, bucketStartTimeNs);
2692     ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
2693 
2694     switch (GetParam()) {
2695         case APP_UPGRADE:
2696             valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
2697             break;
2698         case BOOT_COMPLETE:
2699             valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
2700             break;
2701     }
2702     EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
2703     EXPECT_EQ(0, valueProducer->getCurrentBucketNum());
2704     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9},
2705                                     {partialBucketSplitTimeNs - bucketStartTimeNs}, {0},
2706                                     {bucketStartTimeNs}, {partialBucketSplitTimeNs});
2707     ASSERT_EQ(1UL, valueProducer->mCurrentFullBucket.size());
2708 
2709     vector<shared_ptr<LogEvent>> allData;
2710     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 4));
2711     // Pull fails and arrives late.
2712     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_FAIL, bucket3StartTimeNs + 1);
2713     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9},
2714                                     {partialBucketSplitTimeNs - bucketStartTimeNs}, {0},
2715                                     {bucketStartTimeNs}, {partialBucketSplitTimeNs});
2716     ASSERT_EQ(1, valueProducer->mSkippedBuckets.size());
2717     ASSERT_EQ(2, valueProducer->mSkippedBuckets[0].dropEvents.size());
2718     EXPECT_EQ(PULL_FAILED, valueProducer->mSkippedBuckets[0].dropEvents[0].reason);
2719     EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[0].dropEvents[1].reason);
2720     EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs);
2721     EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs);
2722     ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
2723 }
2724 
TEST(NumericValueMetricProducerTest,TestBucketBoundariesOnConditionChange)2725 TEST(NumericValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
2726     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2727     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2728     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2729             // Second onConditionChanged.
2730             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2731                                 vector<std::shared_ptr<LogEvent>>* data) {
2732                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
2733                 data->clear();
2734                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 10, 5));
2735                 return true;
2736             }))
2737             // Third onConditionChanged.
2738             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2739                                 vector<std::shared_ptr<LogEvent>>* data) {
2740                 EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 10);
2741                 data->clear();
2742                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 10, 7));
2743                 return true;
2744             }));
2745 
2746     sp<NumericValueMetricProducer> valueProducer =
2747             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2748                     pullerManager, metric, ConditionState::kUnknown);
2749 
2750     valueProducer->onConditionChanged(false, bucketStartTimeNs);
2751     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2752 
2753     // End of first bucket
2754     vector<shared_ptr<LogEvent>> allData;
2755     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 4));
2756     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 1);
2757     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2758 
2759     valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
2760     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2761     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2762     auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2763     auto curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2764     EXPECT_EQ(true, curBase.has_value());
2765     EXPECT_EQ(5, curBase.value().long_value);
2766     EXPECT_EQ(0, curInterval.sampleSize);
2767 
2768     valueProducer->onConditionChanged(false, bucket3StartTimeNs + 10);
2769     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
2770     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
2771 
2772     // Bucket should have been completed.
2773     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {bucketSizeNs - 10}, {10},
2774                                     {bucket2StartTimeNs}, {bucket3StartTimeNs});
2775 }
2776 
TEST(NumericValueMetricProducerTest,TestLateOnDataPulledWithoutDiff)2777 TEST(NumericValueMetricProducerTest, TestLateOnDataPulledWithoutDiff) {
2778     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2779     metric.set_use_diff(false);
2780 
2781     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2782     sp<NumericValueMetricProducer> valueProducer =
2783             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
2784                                                                                   metric);
2785 
2786     vector<shared_ptr<LogEvent>> allData;
2787     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
2788     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucketStartTimeNs + 30);
2789 
2790     allData.clear();
2791     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 20));
2792     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2793 
2794     // Bucket should have been completed.
2795     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs}, {0},
2796                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
2797 }
2798 
TEST(NumericValueMetricProducerTest,TestLateOnDataPulledWithDiff)2799 TEST(NumericValueMetricProducerTest, TestLateOnDataPulledWithDiff) {
2800     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2801 
2802     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2803     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
2804             // Initialization.
2805             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
2806                                 vector<std::shared_ptr<LogEvent>>* data) {
2807                 data->clear();
2808                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
2809                 return true;
2810             }));
2811 
2812     sp<NumericValueMetricProducer> valueProducer =
2813             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
2814                                                                                   metric);
2815 
2816     vector<shared_ptr<LogEvent>> allData;
2817     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
2818     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucketStartTimeNs + 30);
2819 
2820     allData.clear();
2821     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 20));
2822     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2823 
2824     // Bucket should have been completed.
2825     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19}, {bucketSizeNs}, {0},
2826                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
2827 }
2828 
TEST_P(NumericValueMetricProducerTest_PartialBucket,TestBucketBoundariesOnPartialBucket)2829 TEST_P(NumericValueMetricProducerTest_PartialBucket, TestBucketBoundariesOnPartialBucket) {
2830     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2831 
2832     int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 2;
2833     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2834     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2835             // Initialization.
2836             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2837                                 vector<std::shared_ptr<LogEvent>>* data) {
2838                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
2839                 data->clear();
2840                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
2841                 return true;
2842             }))
2843             // notifyAppUpgrade.
2844             .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
2845                                                         const int64_t eventTimeNs,
2846                                                         vector<std::shared_ptr<LogEvent>>* data) {
2847                 EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
2848                 data->clear();
2849                 data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 10));
2850                 return true;
2851             }));
2852 
2853     sp<NumericValueMetricProducer> valueProducer =
2854             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
2855                                                                                   metric);
2856 
2857     switch (GetParam()) {
2858         case APP_UPGRADE:
2859             valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
2860             break;
2861         case BOOT_COMPLETE:
2862             valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
2863             break;
2864     }
2865 
2866     // Bucket should have been completed.
2867     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9}, {bucketSizeNs}, {2},
2868                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
2869 }
2870 
TEST(NumericValueMetricProducerTest,TestDataIsNotUpdatedWhenNoConditionChanged)2871 TEST(NumericValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
2872     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2873 
2874     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2875     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2876             // First on condition changed.
2877             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2878                                 vector<std::shared_ptr<LogEvent>>* data) {
2879                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
2880                 data->clear();
2881                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
2882                 return true;
2883             }))
2884             // Second on condition changed.
2885             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2886                                 vector<std::shared_ptr<LogEvent>>* data) {
2887                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
2888                 data->clear();
2889                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
2890                 return true;
2891             }));
2892 
2893     sp<NumericValueMetricProducer> valueProducer =
2894             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2895                     pullerManager, metric, ConditionState::kFalse);
2896 
2897     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
2898     valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
2899     valueProducer->onConditionChanged(false, bucketStartTimeNs + 12);
2900 
2901     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
2902     auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
2903     auto curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
2904     EXPECT_TRUE(curInterval.hasValue());
2905     EXPECT_EQ(2, curInterval.aggregate.long_value);
2906 
2907     vector<shared_ptr<LogEvent>> allData;
2908     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 10));
2909     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 1);
2910 
2911     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {2}, {0}, {bucketStartTimeNs},
2912                                     {bucket2StartTimeNs});
2913 }
2914 
2915 // TODO: b/145705635 fix or delete this test
TEST(NumericValueMetricProducerTest,TestBucketInvalidIfGlobalBaseIsNotSet)2916 TEST(NumericValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
2917     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
2918 
2919     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2920     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
2921             // First condition change.
2922             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2923                                 vector<std::shared_ptr<LogEvent>>* data) {
2924                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
2925                 data->clear();
2926                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
2927                 return true;
2928             }))
2929             // 2nd condition change.
2930             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2931                                 vector<std::shared_ptr<LogEvent>>* data) {
2932                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 8);
2933                 data->clear();
2934                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1));
2935                 return true;
2936             }))
2937             // 3rd condition change.
2938             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
2939                                 vector<std::shared_ptr<LogEvent>>* data) {
2940                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
2941                 data->clear();
2942                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1));
2943                 return true;
2944             }));
2945 
2946     sp<NumericValueMetricProducer> valueProducer =
2947             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
2948                     pullerManager, metric, ConditionState::kFalse);
2949     valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
2950 
2951     vector<shared_ptr<LogEvent>> allData;
2952     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 3, 10));
2953     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_FAIL, bucketStartTimeNs + 3);
2954 
2955     allData.clear();
2956     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 20));
2957     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_FAIL, bucket2StartTimeNs);
2958 
2959     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 8);
2960     valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
2961 
2962     allData.clear();
2963     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 30));
2964     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2965 
2966     // There was not global base available so all buckets are invalid.
2967     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {}, {}, {}, {});
2968 }
2969 
TEST(NumericValueMetricProducerTest,TestFastDumpWithoutCurrentBucket)2970 TEST(NumericValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
2971     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
2972 
2973     sp<EventMatcherWizard> eventMatcherWizard =
2974             createEventMatcherWizard(tagId, logEventMatcherIndex);
2975     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
2976     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
2977     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
2978             // Initial pull.
2979             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
2980                                 vector<std::shared_ptr<LogEvent>>* data) {
2981                 data->clear();
2982                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1));
2983                 return true;
2984             }));
2985 
2986     sp<NumericValueMetricProducer> valueProducer =
2987             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
2988                                                                                   metric);
2989 
2990     vector<shared_ptr<LogEvent>> allData;
2991     allData.clear();
2992     allData.push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 1, tagId, 2, 2));
2993     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
2994 
2995     ProtoOutputStream output;
2996     std::set<string> strSet;
2997     valueProducer->onDumpReport(bucket4StartTimeNs, false /* include recent buckets */, true, FAST,
2998                                 &strSet, &output);
2999 
3000     StatsLogReport report = outputStreamToProto(&output);
3001     // Previous bucket is part of the report, and the current bucket is not skipped.
3002     ASSERT_EQ(1, report.value_metrics().data_size());
3003     EXPECT_EQ(0, report.value_metrics().data(0).bucket_info(0).bucket_num());
3004     ASSERT_EQ(0, report.value_metrics().skipped_size());
3005 }
3006 
TEST(NumericValueMetricProducerTest,TestPullNeededNoTimeConstraints)3007 TEST(NumericValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
3008     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
3009 
3010     sp<EventMatcherWizard> eventMatcherWizard =
3011             createEventMatcherWizard(tagId, logEventMatcherIndex);
3012     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
3013     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3014     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3015             // Initial pull.
3016             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3017                                 vector<std::shared_ptr<LogEvent>>* data) {
3018                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
3019                 data->clear();
3020                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1));
3021                 return true;
3022             }))
3023             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3024                                 vector<std::shared_ptr<LogEvent>>* data) {
3025                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
3026                 data->clear();
3027                 data->push_back(
3028                         CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10, tagId, 3, 3));
3029                 return true;
3030             }));
3031 
3032     sp<NumericValueMetricProducer> valueProducer =
3033             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
3034                                                                                   metric);
3035 
3036     ProtoOutputStream output;
3037     std::set<string> strSet;
3038     valueProducer->onDumpReport(bucketStartTimeNs + 10, true /* include recent buckets */, true,
3039                                 NO_TIME_CONSTRAINTS, &strSet, &output);
3040 
3041     StatsLogReport report = outputStreamToProto(&output);
3042     ASSERT_EQ(1, report.value_metrics().data_size());
3043     ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
3044     EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
3045 }
3046 
TEST(NumericValueMetricProducerTest,TestPulledData_noDiff_withoutCondition)3047 TEST(NumericValueMetricProducerTest, TestPulledData_noDiff_withoutCondition) {
3048     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
3049     metric.set_use_diff(false);
3050 
3051     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3052     sp<NumericValueMetricProducer> valueProducer =
3053             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
3054                                                                                   metric);
3055 
3056     vector<shared_ptr<LogEvent>> allData;
3057     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 10));
3058     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 30);
3059 
3060     // Bucket should have been completed.
3061     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs}, {30},
3062                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
3063     ASSERT_EQ(0, valueProducer->mCurrentSlicedBucket.size());
3064     // TODO: mDimInfos is not needed for non-diffed data, but an entry is still created.
3065     ASSERT_EQ(1, valueProducer->mDimInfos.size());
3066 }
3067 
TEST(NumericValueMetricProducerTest,TestPulledData_noDiff_withMultipleConditionChanges)3068 TEST(NumericValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges) {
3069     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3070     metric.set_use_diff(false);
3071 
3072     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3073     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3074             // condition becomes true
3075             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3076                                 vector<std::shared_ptr<LogEvent>>* data) {
3077                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
3078                 data->clear();
3079                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
3080                 return true;
3081             }))
3082             // condition becomes false
3083             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3084                                 vector<std::shared_ptr<LogEvent>>* data) {
3085                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
3086                 data->clear();
3087                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 20));
3088                 return true;
3089             }));
3090     sp<NumericValueMetricProducer> valueProducer =
3091             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3092                     pullerManager, metric, ConditionState::kFalse);
3093 
3094     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
3095     valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
3096     // has one slice
3097     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
3098     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
3099     NumericValueMetricProducer::Interval curInterval =
3100             valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
3101     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
3102     EXPECT_EQ(false, curBase.has_value());
3103     EXPECT_TRUE(curInterval.hasValue());
3104     EXPECT_EQ(20, curInterval.aggregate.long_value);
3105 
3106     // Now the alarm is delivered. Condition is off though.
3107     vector<shared_ptr<LogEvent>> allData;
3108     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 110));
3109     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
3110 
3111     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8}, {0},
3112                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
3113     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
3114     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
3115     curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
3116     EXPECT_EQ(false, curBase.has_value());
3117 }
3118 
TEST(NumericValueMetricProducerTest,TestPulledData_noDiff_bucketBoundaryTrue)3119 TEST(NumericValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) {
3120     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3121     metric.set_use_diff(false);
3122 
3123     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3124     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _))
3125             // condition becomes true
3126             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
3127                                 vector<std::shared_ptr<LogEvent>>* data) {
3128                 data->clear();
3129                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
3130                 return true;
3131             }));
3132     sp<NumericValueMetricProducer> valueProducer =
3133             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3134                     pullerManager, metric, ConditionState::kFalse);
3135 
3136     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
3137 
3138     // Now the alarm is delivered. Condition is on.
3139     vector<shared_ptr<LogEvent>> allData;
3140     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 30));
3141     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
3142 
3143     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8}, {0},
3144                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
3145     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
3146     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
3147     optional<Value> curBase = valueProducer->mDimInfos.begin()->second.dimExtras[0];
3148     EXPECT_EQ(false, curBase.has_value());
3149 }
3150 
TEST(NumericValueMetricProducerTest,TestPulledData_noDiff_bucketBoundaryFalse)3151 TEST(NumericValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse) {
3152     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3153     metric.set_use_diff(false);
3154 
3155     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3156     sp<NumericValueMetricProducer> valueProducer =
3157             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3158                     pullerManager, metric, ConditionState::kFalse);
3159 
3160     // Now the alarm is delivered. Condition is off though.
3161     vector<shared_ptr<LogEvent>> allData;
3162     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 30));
3163     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
3164 
3165     // Condition was always false.
3166     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {}, {}, {}, {});
3167 }
3168 
TEST(NumericValueMetricProducerTest,TestPulledData_noDiff_withFailure)3169 TEST(NumericValueMetricProducerTest, TestPulledData_noDiff_withFailure) {
3170     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3171     metric.set_use_diff(false);
3172 
3173     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3174     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3175             // condition becomes true
3176             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3177                                 vector<std::shared_ptr<LogEvent>>* data) {
3178                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
3179                 data->clear();
3180                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
3181                 return true;
3182             }))
3183             .WillOnce(Return(false));
3184     sp<NumericValueMetricProducer> valueProducer =
3185             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3186                     pullerManager, metric, ConditionState::kFalse);
3187 
3188     valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
3189     valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
3190     // First event is skipped because the metric is not diffed, so no entry is created in the map
3191     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
3192     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
3193 
3194     // Now the alarm is delivered. Condition is off though.
3195     vector<shared_ptr<LogEvent>> allData;
3196     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 30));
3197     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
3198     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
3199     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
3200 
3201     // No buckets, we had a failure.
3202     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {}, {}, {}, {});
3203 }
3204 
3205 /*
3206  * Test that DUMP_REPORT_REQUESTED dump reason is logged.
3207  *
3208  * For the bucket to be marked invalid during a dump report requested,
3209  * three things must be true:
3210  * - we want to include the current partial bucket
3211  * - we need a pull (metric is pulled and condition is true)
3212  * - the dump latency must be FAST
3213  */
3214 
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenDumpReportRequested)3215 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenDumpReportRequested) {
3216     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3217 
3218     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3219     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 20, _))
3220             // Condition change to true.
3221             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
3222                                 vector<std::shared_ptr<LogEvent>>* data) {
3223                 data->clear();
3224                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 10));
3225                 return true;
3226             }));
3227 
3228     sp<NumericValueMetricProducer> valueProducer =
3229             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3230                     pullerManager, metric, ConditionState::kFalse);
3231 
3232     // Condition change event.
3233     valueProducer->onConditionChanged(true, bucketStartTimeNs + 20);
3234 
3235     // Check dump report.
3236     ProtoOutputStream output;
3237     std::set<string> strSet;
3238     valueProducer->onDumpReport(bucketStartTimeNs + 40, true /* include recent buckets */, true,
3239                                 FAST /* dumpLatency */, &strSet, &output);
3240     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
3241     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
3242 
3243     StatsLogReport report = outputStreamToProto(&output);
3244     EXPECT_TRUE(report.has_value_metrics());
3245     ASSERT_EQ(0, report.value_metrics().data_size());
3246     ASSERT_EQ(1, report.value_metrics().skipped_size());
3247 
3248     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3249               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3250     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 40),
3251               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3252     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3253 
3254     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3255     EXPECT_EQ(BucketDropReason::DUMP_REPORT_REQUESTED, dropEvent.drop_reason());
3256     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 40), dropEvent.drop_time_millis());
3257 }
3258 
3259 /*
3260  * Test that EVENT_IN_WRONG_BUCKET dump reason is logged for a late condition
3261  * change event (i.e. the condition change occurs in the wrong bucket).
3262  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenConditionEventWrongBucket)3263 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionEventWrongBucket) {
3264     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3265 
3266     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3267     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 50, _))
3268             // Condition change to true.
3269             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
3270                                 vector<std::shared_ptr<LogEvent>>* data) {
3271                 data->clear();
3272                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
3273                 return true;
3274             }));
3275 
3276     sp<NumericValueMetricProducer> valueProducer =
3277             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3278                     pullerManager, metric, ConditionState::kFalse);
3279 
3280     // Condition change event.
3281     valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
3282 
3283     // Bucket boundary pull.
3284     vector<shared_ptr<LogEvent>> allData;
3285     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 15));
3286     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 1);
3287 
3288     // Late condition change event.
3289     valueProducer->onConditionChanged(false, bucket2StartTimeNs - 100);
3290 
3291     // Check dump report.
3292     ProtoOutputStream output;
3293     std::set<string> strSet;
3294     valueProducer->onDumpReport(bucket2StartTimeNs + 100, true /* include recent buckets */, true,
3295                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3296 
3297     StatsLogReport report = outputStreamToProto(&output);
3298     EXPECT_TRUE(report.has_value_metrics());
3299     ASSERT_EQ(1, report.value_metrics().data_size());
3300     ASSERT_EQ(1, report.value_metrics().skipped_size());
3301 
3302     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
3303               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3304     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
3305               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3306     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3307 
3308     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3309     EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
3310     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs - 100), dropEvent.drop_time_millis());
3311 }
3312 
3313 /*
3314  * Test that EVENT_IN_WRONG_BUCKET dump reason is logged for a late accumulate
3315  * event (i.e. the accumulate events call occurs in the wrong bucket).
3316  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenAccumulateEventWrongBucket)3317 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenAccumulateEventWrongBucket) {
3318     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3319 
3320     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3321     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3322             // Condition change to true.
3323             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3324                                 vector<std::shared_ptr<LogEvent>>* data) {
3325                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
3326                 data->clear();
3327                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
3328                 return true;
3329             }))
3330             // Dump report requested.
3331             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3332                                 vector<std::shared_ptr<LogEvent>>* data) {
3333                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 100);
3334                 data->clear();
3335                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 100, 15));
3336                 return true;
3337             }));
3338 
3339     sp<NumericValueMetricProducer> valueProducer =
3340             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3341                     pullerManager, metric, ConditionState::kFalse);
3342 
3343     // Condition change event.
3344     valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
3345 
3346     // Bucket boundary pull.
3347     vector<shared_ptr<LogEvent>> allData;
3348     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 15));
3349     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 1);
3350 
3351     allData.clear();
3352     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs - 100, 20));
3353 
3354     // Late accumulateEvents event.
3355     valueProducer->accumulateEvents(allData, bucket2StartTimeNs - 100, bucket2StartTimeNs - 100);
3356 
3357     // Check dump report.
3358     ProtoOutputStream output;
3359     std::set<string> strSet;
3360     valueProducer->onDumpReport(bucket2StartTimeNs + 100, true /* include recent buckets */, true,
3361                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3362 
3363     StatsLogReport report = outputStreamToProto(&output);
3364     EXPECT_TRUE(report.has_value_metrics());
3365     ASSERT_EQ(1, report.value_metrics().data_size());
3366     ASSERT_EQ(1, report.value_metrics().skipped_size());
3367 
3368     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
3369               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3370     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
3371               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3372     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3373 
3374     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3375     EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
3376     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs - 100), dropEvent.drop_time_millis());
3377 }
3378 
3379 /*
3380  * Test that CONDITION_UNKNOWN dump reason is logged due to an unknown condition
3381  * when a metric is initialized.
3382  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenConditionUnknown)3383 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown) {
3384     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3385 
3386     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3387     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3388             // Condition change to true.
3389             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3390                                 vector<std::shared_ptr<LogEvent>>* data) {
3391                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
3392                 data->clear();
3393                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
3394                 return true;
3395             }))
3396             // Dump report requested.
3397             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3398                                 vector<std::shared_ptr<LogEvent>>* data) {
3399                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10000);
3400                 data->clear();
3401                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 100, 15));
3402                 return true;
3403             }));
3404 
3405     sp<NumericValueMetricProducer> valueProducer =
3406             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3407                     pullerManager, metric, ConditionState::kUnknown);
3408 
3409     // Condition change event.
3410     valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
3411 
3412     // Check dump report.
3413     ProtoOutputStream output;
3414     std::set<string> strSet;
3415     int64_t dumpReportTimeNs = bucketStartTimeNs + 10000;
3416     valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
3417                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3418 
3419     StatsLogReport report = outputStreamToProto(&output);
3420     EXPECT_TRUE(report.has_value_metrics());
3421     ASSERT_EQ(0, report.value_metrics().data_size());
3422     ASSERT_EQ(1, report.value_metrics().skipped_size());
3423 
3424     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3425               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3426     EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
3427               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3428     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3429 
3430     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3431     EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
3432     EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
3433 }
3434 
3435 /*
3436  * Test that PULL_FAILED dump reason is logged due to a pull failure in
3437  * #pullAndMatchEventsLocked.
3438  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenPullFailed)3439 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenPullFailed) {
3440     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3441 
3442     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3443     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3444             // Condition change to true.
3445             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3446                                 vector<std::shared_ptr<LogEvent>>* data) {
3447                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
3448                 data->clear();
3449                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
3450                 return true;
3451             }))
3452             // Dump report requested, pull fails.
3453             .WillOnce(Return(false));
3454 
3455     sp<NumericValueMetricProducer> valueProducer =
3456             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3457                     pullerManager, metric, ConditionState::kFalse);
3458 
3459     // Condition change event.
3460     valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
3461 
3462     // Check dump report.
3463     ProtoOutputStream output;
3464     std::set<string> strSet;
3465     int64_t dumpReportTimeNs = bucketStartTimeNs + 10000;
3466     valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
3467                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3468 
3469     StatsLogReport report = outputStreamToProto(&output);
3470     EXPECT_TRUE(report.has_value_metrics());
3471     ASSERT_EQ(0, report.value_metrics().data_size());
3472     ASSERT_EQ(1, report.value_metrics().skipped_size());
3473 
3474     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3475               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3476     EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
3477               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3478     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3479 
3480     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3481     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3482     EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
3483 }
3484 
3485 /*
3486  * Test that MULTIPLE_BUCKETS_SKIPPED dump reason is logged when a log event
3487  * skips over more than one bucket.
3488  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestInvalidBucketWhenMultipleBucketsSkipped)3489 TEST(NumericValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenMultipleBucketsSkipped) {
3490     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3491 
3492     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3493     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3494             // Condition change to true.
3495             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3496                                 vector<std::shared_ptr<LogEvent>>* data) {
3497                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
3498                 data->clear();
3499                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
3500                 return true;
3501             }))
3502             // Dump report requested.
3503             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3504                                 vector<std::shared_ptr<LogEvent>>* data) {
3505                 EXPECT_EQ(eventTimeNs, bucket4StartTimeNs + 10);
3506                 data->clear();
3507                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1000, 15));
3508                 return true;
3509             }));
3510 
3511     sp<NumericValueMetricProducer> valueProducer =
3512             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3513                     pullerManager, metric, ConditionState::kFalse);
3514 
3515     // Condition change event.
3516     valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
3517 
3518     // Condition change event that skips forward by three buckets.
3519     valueProducer->onConditionChanged(false, bucket4StartTimeNs + 10);
3520     // Ensure data structures are appropriately trimmed when multiple buckets are skipped.
3521     ASSERT_EQ(valueProducer->mCurrentSlicedBucket.size(), 0);
3522     ASSERT_EQ(valueProducer->mDimInfos.size(), 1);
3523 
3524     int64_t dumpTimeNs = bucket4StartTimeNs + 1000;
3525 
3526     // Check dump report.
3527     ProtoOutputStream output;
3528     std::set<string> strSet;
3529     valueProducer->onDumpReport(dumpTimeNs, true /* include current buckets */, true,
3530                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3531 
3532     StatsLogReport report = outputStreamToProto(&output);
3533     EXPECT_TRUE(report.has_value_metrics());
3534     ASSERT_EQ(0, report.value_metrics().data_size());
3535     ASSERT_EQ(2, report.value_metrics().skipped_size());
3536 
3537     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3538               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3539     EXPECT_EQ(NanoToMillis(bucket4StartTimeNs),
3540               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3541     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3542 
3543     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3544     EXPECT_EQ(BucketDropReason::MULTIPLE_BUCKETS_SKIPPED, dropEvent.drop_reason());
3545     EXPECT_EQ(NanoToMillis(bucket4StartTimeNs + 10), dropEvent.drop_time_millis());
3546 
3547     // This bucket is skipped because a dumpReport with include current buckets is called.
3548     // This creates a new bucket from bucket4StartTimeNs to dumpTimeNs in which we have no data
3549     // since the condition is false for the entire bucket interval.
3550     EXPECT_EQ(NanoToMillis(bucket4StartTimeNs),
3551               report.value_metrics().skipped(1).start_bucket_elapsed_millis());
3552     EXPECT_EQ(NanoToMillis(dumpTimeNs),
3553               report.value_metrics().skipped(1).end_bucket_elapsed_millis());
3554     ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size());
3555 
3556     dropEvent = report.value_metrics().skipped(1).drop_event(0);
3557     EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
3558     EXPECT_EQ(NanoToMillis(dumpTimeNs), dropEvent.drop_time_millis());
3559 }
3560 
3561 /*
3562  * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
3563  * is smaller than the "min_bucket_size_nanos" specified in the metric config.
3564  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestBucketDropWhenBucketTooSmall)3565 TEST(NumericValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
3566     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3567     metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
3568 
3569     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3570     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3571             // Condition change to true.
3572             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3573                                 vector<std::shared_ptr<LogEvent>>* data) {
3574                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
3575                 data->clear();
3576                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
3577                 return true;
3578             }))
3579             // Dump report requested.
3580             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3581                                 vector<std::shared_ptr<LogEvent>>* data) {
3582                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 9000000);
3583                 data->clear();
3584                 data->push_back(
3585                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 9000000, 15));
3586                 return true;
3587             }));
3588 
3589     sp<NumericValueMetricProducer> valueProducer =
3590             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3591                     pullerManager, metric, ConditionState::kFalse);
3592 
3593     // Condition change event.
3594     valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
3595 
3596     // Check dump report.
3597     ProtoOutputStream output;
3598     std::set<string> strSet;
3599     int64_t dumpReportTimeNs = bucketStartTimeNs + 9000000;
3600     valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
3601                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3602 
3603     StatsLogReport report = outputStreamToProto(&output);
3604     EXPECT_TRUE(report.has_value_metrics());
3605     ASSERT_EQ(0, report.value_metrics().data_size());
3606     ASSERT_EQ(1, report.value_metrics().skipped_size());
3607 
3608     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3609               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3610     EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
3611               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3612     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3613 
3614     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3615     EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
3616     EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
3617 }
3618 
3619 /*
3620  * Test that NO_DATA dump reason is logged when a flushed bucket contains no data.
3621  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestBucketDropWhenDataUnavailable)3622 TEST(NumericValueMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable) {
3623     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3624 
3625     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3626 
3627     sp<NumericValueMetricProducer> valueProducer =
3628             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3629                     pullerManager, metric, ConditionState::kFalse);
3630 
3631     // Check dump report.
3632     ProtoOutputStream output;
3633     std::set<string> strSet;
3634     int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000;  // 10 seconds
3635     valueProducer->onDumpReport(dumpReportTimeNs, true /* include current bucket */, true,
3636                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3637 
3638     StatsLogReport report = outputStreamToProto(&output);
3639     EXPECT_TRUE(report.has_value_metrics());
3640     ASSERT_EQ(0, report.value_metrics().data_size());
3641     ASSERT_EQ(1, report.value_metrics().skipped_size());
3642 
3643     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3644               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3645     EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
3646               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3647     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3648 
3649     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3650     EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
3651     EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
3652 }
3653 
3654 /*
3655  * Test that all buckets are dropped due to condition unknown until the first onConditionChanged.
3656  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestConditionUnknownMultipleBuckets)3657 TEST(NumericValueMetricProducerTest_BucketDrop, TestConditionUnknownMultipleBuckets) {
3658     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3659 
3660     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3661     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3662             // Condition change to true.
3663             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3664                                 vector<std::shared_ptr<LogEvent>>* data) {
3665                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC);
3666                 data->clear();
3667                 data->push_back(CreateRepeatedValueLogEvent(
3668                         tagId, bucket2StartTimeNs + 10 * NS_PER_SEC, 10));
3669                 return true;
3670             }))
3671             // Dump report requested.
3672             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3673                                 vector<std::shared_ptr<LogEvent>>* data) {
3674                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 15 * NS_PER_SEC);
3675                 data->clear();
3676                 data->push_back(CreateRepeatedValueLogEvent(
3677                         tagId, bucket2StartTimeNs + 15 * NS_PER_SEC, 15));
3678                 return true;
3679             }));
3680 
3681     sp<NumericValueMetricProducer> valueProducer =
3682             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3683                     pullerManager, metric, ConditionState::kUnknown);
3684 
3685     // Bucket should be dropped because of condition unknown.
3686     int64_t appUpgradeTimeNs = bucketStartTimeNs + 5 * NS_PER_SEC;
3687     valueProducer->notifyAppUpgrade(appUpgradeTimeNs);
3688 
3689     // Bucket also dropped due to condition unknown
3690     vector<shared_ptr<LogEvent>> allData;
3691     allData.clear();
3692     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 3));
3693     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
3694 
3695     // This bucket is also dropped due to condition unknown.
3696     int64_t conditionChangeTimeNs = bucket2StartTimeNs + 10 * NS_PER_SEC;
3697     valueProducer->onConditionChanged(true, conditionChangeTimeNs);
3698 
3699     // Check dump report.
3700     ProtoOutputStream output;
3701     std::set<string> strSet;
3702     int64_t dumpReportTimeNs = bucket2StartTimeNs + 15 * NS_PER_SEC;  // 15 seconds
3703     valueProducer->onDumpReport(dumpReportTimeNs, true /* include current bucket */, true,
3704                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3705 
3706     StatsLogReport report = outputStreamToProto(&output);
3707     EXPECT_TRUE(report.has_value_metrics());
3708     ASSERT_EQ(0, report.value_metrics().data_size());
3709     ASSERT_EQ(3, report.value_metrics().skipped_size());
3710 
3711     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3712               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3713     EXPECT_EQ(NanoToMillis(appUpgradeTimeNs),
3714               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3715     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3716 
3717     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3718     EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
3719     EXPECT_EQ(NanoToMillis(appUpgradeTimeNs), dropEvent.drop_time_millis());
3720 
3721     EXPECT_EQ(NanoToMillis(appUpgradeTimeNs),
3722               report.value_metrics().skipped(1).start_bucket_elapsed_millis());
3723     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
3724               report.value_metrics().skipped(1).end_bucket_elapsed_millis());
3725     ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size());
3726 
3727     dropEvent = report.value_metrics().skipped(1).drop_event(0);
3728     EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
3729     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis());
3730 
3731     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
3732               report.value_metrics().skipped(2).start_bucket_elapsed_millis());
3733     EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
3734               report.value_metrics().skipped(2).end_bucket_elapsed_millis());
3735     ASSERT_EQ(1, report.value_metrics().skipped(2).drop_event_size());
3736 
3737     dropEvent = report.value_metrics().skipped(2).drop_event(0);
3738     EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
3739     EXPECT_EQ(NanoToMillis(conditionChangeTimeNs), dropEvent.drop_time_millis());
3740 }
3741 
3742 /*
3743  * Test that a skipped bucket is logged when a forced bucket split occurs when the previous bucket
3744  * was not flushed in time.
3745  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestBucketDropWhenForceBucketSplitBeforeBucketFlush)3746 TEST(NumericValueMetricProducerTest_BucketDrop,
3747      TestBucketDropWhenForceBucketSplitBeforeBucketFlush) {
3748     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3749 
3750     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3751     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3752             // Condition change to true.
3753             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3754                                 vector<std::shared_ptr<LogEvent>>* data) {
3755                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
3756                 data->clear();
3757                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
3758                 return true;
3759             }))
3760             // App Update.
3761             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3762                                 vector<std::shared_ptr<LogEvent>>* data) {
3763                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1000);
3764                 data->clear();
3765                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1000, 15));
3766                 return true;
3767             }));
3768 
3769     sp<NumericValueMetricProducer> valueProducer =
3770             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3771                     pullerManager, metric, ConditionState::kFalse);
3772 
3773     // Condition changed event
3774     int64_t conditionChangeTimeNs = bucketStartTimeNs + 10;
3775     valueProducer->onConditionChanged(true, conditionChangeTimeNs);
3776 
3777     // App update event.
3778     int64_t appUpdateTimeNs = bucket2StartTimeNs + 1000;
3779     valueProducer->notifyAppUpgrade(appUpdateTimeNs);
3780 
3781     // Check dump report.
3782     ProtoOutputStream output;
3783     std::set<string> strSet;
3784     int64_t dumpReportTimeNs = bucket2StartTimeNs + 10000000000;  // 10 seconds
3785     valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true,
3786                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
3787 
3788     StatsLogReport report = outputStreamToProto(&output);
3789     EXPECT_TRUE(report.has_value_metrics());
3790     ASSERT_EQ(1, report.value_metrics().data_size());
3791     ASSERT_EQ(1, report.value_metrics().skipped_size());
3792 
3793     ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
3794     auto data = report.value_metrics().data(0);
3795     ASSERT_EQ(0, data.bucket_info(0).bucket_num());
3796     EXPECT_EQ(5, data.bucket_info(0).values(0).value_long());
3797 
3798     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
3799               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3800     EXPECT_EQ(NanoToMillis(appUpdateTimeNs),
3801               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3802     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
3803 
3804     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3805     EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
3806     EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
3807 }
3808 
3809 /*
3810  * Test multiple bucket drop events in the same bucket.
3811  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestMultipleBucketDropEvents)3812 TEST(NumericValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) {
3813     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3814 
3815     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3816     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _))
3817             // Condition change to true.
3818             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
3819                                 vector<std::shared_ptr<LogEvent>>* data) {
3820                 data->clear();
3821                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
3822                 return true;
3823             }));
3824 
3825     sp<NumericValueMetricProducer> valueProducer =
3826             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3827                     pullerManager, metric, ConditionState::kUnknown);
3828 
3829     // Condition change event.
3830     valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
3831 
3832     // Check dump report.
3833     ProtoOutputStream output;
3834     std::set<string> strSet;
3835     int64_t dumpReportTimeNs = bucketStartTimeNs + 1000;
3836     valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
3837                                 FAST /* dumpLatency */, &strSet, &output);
3838 
3839     StatsLogReport report = outputStreamToProto(&output);
3840     EXPECT_TRUE(report.has_value_metrics());
3841     ASSERT_EQ(0, report.value_metrics().data_size());
3842     ASSERT_EQ(1, report.value_metrics().skipped_size());
3843 
3844     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3845               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3846     EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
3847               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3848     ASSERT_EQ(2, report.value_metrics().skipped(0).drop_event_size());
3849 
3850     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3851     EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
3852     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 10), dropEvent.drop_time_millis());
3853 
3854     dropEvent = report.value_metrics().skipped(0).drop_event(1);
3855     EXPECT_EQ(BucketDropReason::DUMP_REPORT_REQUESTED, dropEvent.drop_reason());
3856     EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
3857 }
3858 
3859 /*
3860  * Test that the number of logged bucket drop events is capped at the maximum.
3861  * The maximum is currently 10 and is set in MetricProducer::maxDropEventsReached().
3862  */
TEST(NumericValueMetricProducerTest_BucketDrop,TestMaxBucketDropEvents)3863 TEST(NumericValueMetricProducerTest_BucketDrop, TestMaxBucketDropEvents) {
3864     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
3865 
3866     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3867     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3868             // First condition change event.
3869             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3870                                 vector<std::shared_ptr<LogEvent>>* data) {
3871                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
3872                 for (int i = 0; i < 2000; i++) {
3873                     data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i));
3874                 }
3875                 return true;
3876             }))
3877             .WillOnce(Return(false))
3878             .WillOnce(Return(false))
3879             .WillOnce(Return(false))
3880             .WillOnce(Return(false))
3881             .WillOnce(Return(false))
3882             .WillOnce(Return(false))
3883             .WillOnce(Return(false))
3884             .WillOnce(Return(false))
3885             .WillOnce(Return(false))
3886             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3887                                 vector<std::shared_ptr<LogEvent>>* data) {
3888                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 220);
3889                 data->clear();
3890                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 220, 10));
3891                 return true;
3892             }));
3893 
3894     sp<NumericValueMetricProducer> valueProducer =
3895             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
3896                     pullerManager, metric, ConditionState::kUnknown);
3897 
3898     // First condition change event causes guardrail to be reached.
3899     valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
3900 
3901     // 2-10 condition change events result in failed pulls.
3902     valueProducer->onConditionChanged(false, bucketStartTimeNs + 30);
3903     valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
3904     valueProducer->onConditionChanged(false, bucketStartTimeNs + 70);
3905     valueProducer->onConditionChanged(true, bucketStartTimeNs + 90);
3906     valueProducer->onConditionChanged(false, bucketStartTimeNs + 100);
3907     valueProducer->onConditionChanged(true, bucketStartTimeNs + 150);
3908     valueProducer->onConditionChanged(false, bucketStartTimeNs + 170);
3909     valueProducer->onConditionChanged(true, bucketStartTimeNs + 190);
3910     valueProducer->onConditionChanged(false, bucketStartTimeNs + 200);
3911 
3912     // Condition change event 11
3913     valueProducer->onConditionChanged(true, bucketStartTimeNs + 220);
3914 
3915     // Check dump report.
3916     ProtoOutputStream output;
3917     std::set<string> strSet;
3918     int64_t dumpReportTimeNs = bucketStartTimeNs + 1000;
3919     // Because we already have 10 dump events in the current bucket,
3920     // this case should not be added to the list of dump events.
3921     valueProducer->onDumpReport(bucketStartTimeNs + 1000, true /* include recent buckets */, true,
3922                                 FAST /* dumpLatency */, &strSet, &output);
3923 
3924     StatsLogReport report = outputStreamToProto(&output);
3925     EXPECT_TRUE(report.has_value_metrics());
3926     ASSERT_EQ(0, report.value_metrics().data_size());
3927     ASSERT_EQ(1, report.value_metrics().skipped_size());
3928 
3929     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
3930               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
3931     EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
3932               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
3933     ASSERT_EQ(10, report.value_metrics().skipped(0).drop_event_size());
3934 
3935     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
3936     EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
3937     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 10), dropEvent.drop_time_millis());
3938 
3939     dropEvent = report.value_metrics().skipped(0).drop_event(1);
3940     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3941     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 30), dropEvent.drop_time_millis());
3942 
3943     dropEvent = report.value_metrics().skipped(0).drop_event(2);
3944     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3945     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 50), dropEvent.drop_time_millis());
3946 
3947     dropEvent = report.value_metrics().skipped(0).drop_event(3);
3948     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3949     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 70), dropEvent.drop_time_millis());
3950 
3951     dropEvent = report.value_metrics().skipped(0).drop_event(4);
3952     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3953     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 90), dropEvent.drop_time_millis());
3954 
3955     dropEvent = report.value_metrics().skipped(0).drop_event(5);
3956     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3957     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 100), dropEvent.drop_time_millis());
3958 
3959     dropEvent = report.value_metrics().skipped(0).drop_event(6);
3960     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3961     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 150), dropEvent.drop_time_millis());
3962 
3963     dropEvent = report.value_metrics().skipped(0).drop_event(7);
3964     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3965     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 170), dropEvent.drop_time_millis());
3966 
3967     dropEvent = report.value_metrics().skipped(0).drop_event(8);
3968     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3969     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 190), dropEvent.drop_time_millis());
3970 
3971     dropEvent = report.value_metrics().skipped(0).drop_event(9);
3972     EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
3973     EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 200), dropEvent.drop_time_millis());
3974 }
3975 
3976 /*
3977  * Test metric with a simple sliced state
3978  * - Increasing values
3979  * - Using diff
3980  * - Second field is value field
3981  */
TEST(NumericValueMetricProducerTest,TestSlicedState)3982 TEST(NumericValueMetricProducerTest, TestSlicedState) {
3983     // Set up NumericValueMetricProducer.
3984     ValueMetric metric =
3985             NumericValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE");
3986     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
3987     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
3988             // NumericValueMetricProducer initialized.
3989             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3990                                 vector<std::shared_ptr<LogEvent>>* data) {
3991                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
3992                 data->clear();
3993                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
3994                 return true;
3995             }))
3996             // Screen state change to ON.
3997             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
3998                                 vector<std::shared_ptr<LogEvent>>* data) {
3999                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5 * NS_PER_SEC);
4000                 data->clear();
4001                 data->push_back(
4002                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5 * NS_PER_SEC, 5));
4003                 return true;
4004             }))
4005             // Screen state change to OFF.
4006             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4007                                 vector<std::shared_ptr<LogEvent>>* data) {
4008                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
4009                 data->clear();
4010                 data->push_back(
4011                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 9));
4012                 return true;
4013             }))
4014             // Screen state change to ON.
4015             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4016                                 vector<std::shared_ptr<LogEvent>>* data) {
4017                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15 * NS_PER_SEC);
4018                 data->clear();
4019                 data->push_back(CreateRepeatedValueLogEvent(
4020                         tagId, bucketStartTimeNs + 15 * NS_PER_SEC, 21));
4021                 return true;
4022             }))
4023             // Dump report requested.
4024             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4025                                 vector<std::shared_ptr<LogEvent>>* data) {
4026                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
4027                 data->clear();
4028                 data->push_back(CreateRepeatedValueLogEvent(
4029                         tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 30));
4030                 return true;
4031             }));
4032 
4033     StateManager::getInstance().clear();
4034     sp<NumericValueMetricProducer> valueProducer =
4035             NumericValueMetricProducerTestHelper::createValueProducerWithState(
4036                     pullerManager, metric, {util::SCREEN_STATE_CHANGED}, {});
4037     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
4038 
4039     // Set up StateManager and check that StateTrackers are initialized.
4040     StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
4041     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
4042     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
4043 
4044     // Bucket status after metric initialized.
4045     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
4046     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4047     // Base for dimension key {
4048     auto it = valueProducer->mCurrentSlicedBucket.begin();
4049     auto itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4050     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4051     EXPECT_EQ(3, itBase->second.dimExtras[0].value().long_value);
4052     EXPECT_TRUE(itBase->second.hasCurrentState);
4053     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4054     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4055               itBase->second.currentState.getValues()[0].mValue.int_value);
4056     // Value for dimension, state key {{}, kStateUnknown}
4057     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4058     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4059     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4060               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4061     EXPECT_EQ(0, it->second.intervals[0].sampleSize);
4062     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
4063 
4064     // Bucket status after screen state change kStateUnknown->ON.
4065     auto screenEvent = CreateScreenStateChangedEvent(
4066             bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
4067     StateManager::getInstance().onLogEvent(*screenEvent);
4068     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4069     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4070     // Base for dimension key {}
4071     it = valueProducer->mCurrentSlicedBucket.begin();
4072     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4073     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4074     EXPECT_EQ(5, itBase->second.dimExtras[0].value().long_value);
4075     EXPECT_TRUE(itBase->second.hasCurrentState);
4076     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4077     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
4078               itBase->second.currentState.getValues()[0].mValue.int_value);
4079     // Value for dimension, state key {{}, ON}
4080     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4081     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4082     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
4083               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4084     EXPECT_EQ(0, it->second.intervals.size());
4085     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
4086     // Value for dimension, state key {{}, kStateUnknown}
4087     it++;
4088     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4089     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4090     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4091               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4092     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4093     EXPECT_EQ(2, it->second.intervals[0].aggregate.long_value);
4094     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4095                          bucketStartTimeNs + 5 * NS_PER_SEC);
4096 
4097     // Bucket status after screen state change ON->OFF.
4098     screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
4099                                                 android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
4100     StateManager::getInstance().onLogEvent(*screenEvent);
4101     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
4102     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4103     // Base for dimension key {}
4104     it = valueProducer->mCurrentSlicedBucket.begin();
4105     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4106     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4107     EXPECT_EQ(9, itBase->second.dimExtras[0].value().long_value);
4108     EXPECT_TRUE(itBase->second.hasCurrentState);
4109     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
4110               itBase->second.currentState.getValues()[0].mValue.int_value);
4111     // Value for dimension, state key {{}, OFF}
4112     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4113     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4114     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
4115               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4116     EXPECT_EQ(0, it->second.intervals.size());
4117     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
4118     // Value for dimension, state key {{}, ON}
4119     it++;
4120     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4121     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4122     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
4123               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4124     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4125     EXPECT_EQ(4, it->second.intervals[0].aggregate.long_value);
4126     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4127                          bucketStartTimeNs + 10 * NS_PER_SEC);
4128     // Value for dimension, state key {{}, kStateUnknown}
4129     it++;
4130     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4131     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4132     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4133               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4134     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4135     EXPECT_EQ(2, it->second.intervals[0].aggregate.long_value);
4136     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4137                          bucketStartTimeNs + 5 * NS_PER_SEC);
4138 
4139     // Bucket status after screen state change OFF->ON.
4140     screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC,
4141                                                 android::view::DisplayStateEnum::DISPLAY_STATE_ON);
4142     StateManager::getInstance().onLogEvent(*screenEvent);
4143     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
4144     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4145     // Base for dimension key {}
4146     it = valueProducer->mCurrentSlicedBucket.begin();
4147     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4148     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4149     EXPECT_EQ(21, itBase->second.dimExtras[0].value().long_value);
4150     EXPECT_TRUE(itBase->second.hasCurrentState);
4151     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4152     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
4153               itBase->second.currentState.getValues()[0].mValue.int_value);
4154     // Value for dimension, state key {{}, OFF}
4155     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4156     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4157     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
4158               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4159     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4160     EXPECT_EQ(12, it->second.intervals[0].aggregate.long_value);
4161     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4162                          bucketStartTimeNs + 15 * NS_PER_SEC);
4163     // Value for dimension, state key {{}, ON}
4164     it++;
4165     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4166     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4167     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
4168               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4169     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4170     EXPECT_EQ(4, it->second.intervals[0].aggregate.long_value);
4171     assertConditionTimer(it->second.conditionTimer, true, 5 * NS_PER_SEC,
4172                          bucketStartTimeNs + 15 * NS_PER_SEC);
4173     // Value for dimension, state key {{}, kStateUnknown}
4174     it++;
4175     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4176     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4177     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4178               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4179     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4180     EXPECT_EQ(2, it->second.intervals[0].aggregate.long_value);
4181     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4182                          bucketStartTimeNs + 5 * NS_PER_SEC);
4183 
4184     // Start dump report and check output.
4185     ProtoOutputStream output;
4186     std::set<string> strSet;
4187     valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
4188                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
4189                                 &strSet, &output);
4190 
4191     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
4192     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4193     // Base for dimension key {}
4194     it = valueProducer->mCurrentSlicedBucket.begin();
4195     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4196     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4197     EXPECT_EQ(30, itBase->second.dimExtras[0].value().long_value);
4198     EXPECT_TRUE(itBase->second.hasCurrentState);
4199     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4200     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
4201               itBase->second.currentState.getValues()[0].mValue.int_value);
4202     // Value for dimension, state key {{}, ON}
4203     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4204     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4205     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
4206               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4207     EXPECT_EQ(it->second.intervals[0].sampleSize, 0);
4208     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 50 * NS_PER_SEC);
4209 
4210     StatsLogReport report = outputStreamToProto(&output);
4211     EXPECT_TRUE(report.has_value_metrics());
4212     ASSERT_EQ(3, report.value_metrics().data_size());
4213 
4214     // {{}, kStateUnknown}
4215     auto data = report.value_metrics().data(0);
4216     ASSERT_EQ(1, data.bucket_info_size());
4217     EXPECT_EQ(2, data.bucket_info(0).values(0).value_long());
4218     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
4219     EXPECT_TRUE(data.slice_by_state(0).has_value());
4220     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
4221     EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
4222 
4223     // {{}, ON}
4224     data = report.value_metrics().data(1);
4225     ASSERT_EQ(1, data.bucket_info_size());
4226     EXPECT_EQ(13, data.bucket_info(0).values(0).value_long());
4227     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
4228     EXPECT_TRUE(data.slice_by_state(0).has_value());
4229     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
4230     EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
4231 
4232     // {{}, OFF}
4233     data = report.value_metrics().data(2);
4234     ASSERT_EQ(1, data.bucket_info_size());
4235     EXPECT_EQ(12, data.bucket_info(0).values(0).value_long());
4236     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
4237     EXPECT_TRUE(data.slice_by_state(0).has_value());
4238     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
4239     EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
4240 }
4241 
4242 /*
4243  * Test metric with sliced state with map
4244  * - Increasing values
4245  * - Using diff
4246  * - Second field is value field
4247  */
TEST(NumericValueMetricProducerTest,TestSlicedStateWithMap)4248 TEST(NumericValueMetricProducerTest, TestSlicedStateWithMap) {
4249     // Set up NumericValueMetricProducer.
4250     ValueMetric metric =
4251             NumericValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE_ONOFF");
4252     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
4253     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
4254             // NumericValueMetricProducer initialized.
4255             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4256                                 vector<std::shared_ptr<LogEvent>>* data) {
4257                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
4258                 data->clear();
4259                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
4260                 return true;
4261             }))
4262             // Screen state change to ON.
4263             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4264                                 vector<std::shared_ptr<LogEvent>>* data) {
4265                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5 * NS_PER_SEC);
4266                 data->clear();
4267                 data->push_back(
4268                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5 * NS_PER_SEC, 5));
4269                 return true;
4270             }))
4271             // Screen state change to VR has no pull because it is in the same
4272             // state group as ON.
4273 
4274             // Screen state change to ON has no pull because it is in the same
4275             // state group as VR.
4276 
4277             // Screen state change to OFF.
4278             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4279                                 vector<std::shared_ptr<LogEvent>>* data) {
4280                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15 * NS_PER_SEC);
4281                 data->clear();
4282                 data->push_back(CreateRepeatedValueLogEvent(
4283                         tagId, bucketStartTimeNs + 15 * NS_PER_SEC, 21));
4284                 return true;
4285             }))
4286             // Dump report requested.
4287             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4288                                 vector<std::shared_ptr<LogEvent>>* data) {
4289                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
4290                 data->clear();
4291                 data->push_back(CreateRepeatedValueLogEvent(
4292                         tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 30));
4293                 return true;
4294             }));
4295 
4296     const StateMap& stateMap =
4297             CreateScreenStateOnOffMap(/*screen on id=*/321, /*screen off id=*/123);
4298     const StateMap_StateGroup screenOnGroup = stateMap.group(0);
4299     const StateMap_StateGroup screenOffGroup = stateMap.group(1);
4300 
4301     unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
4302     for (auto group : stateMap.group()) {
4303         for (auto value : group.value()) {
4304             stateGroupMap[SCREEN_STATE_ATOM_ID][value] = group.group_id();
4305         }
4306     }
4307 
4308     StateManager::getInstance().clear();
4309     sp<NumericValueMetricProducer> valueProducer =
4310             NumericValueMetricProducerTestHelper::createValueProducerWithState(
4311                     pullerManager, metric, {util::SCREEN_STATE_CHANGED}, stateGroupMap);
4312 
4313     // Set up StateManager and check that StateTrackers are initialized.
4314     StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
4315     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
4316     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
4317 
4318     // Bucket status after metric initialized.
4319     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
4320     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4321     // Base for dimension key {}
4322     auto it = valueProducer->mCurrentSlicedBucket.begin();
4323     auto itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4324     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4325     EXPECT_EQ(3, itBase->second.dimExtras[0].value().long_value);
4326     EXPECT_TRUE(itBase->second.hasCurrentState);
4327     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4328     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4329               itBase->second.currentState.getValues()[0].mValue.int_value);
4330     // Value for dimension, state key {{}, {kStateUnknown}}
4331     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4332     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4333     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4334               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4335     EXPECT_EQ(0, it->second.intervals[0].sampleSize);
4336     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
4337 
4338     // Bucket status after screen state change kStateUnknown->ON.
4339     auto screenEvent = CreateScreenStateChangedEvent(
4340             bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
4341     StateManager::getInstance().onLogEvent(*screenEvent);
4342     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4343     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4344     // Base for dimension key {}
4345     it = valueProducer->mCurrentSlicedBucket.begin();
4346     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4347     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4348     EXPECT_EQ(5, itBase->second.dimExtras[0].value().long_value);
4349     EXPECT_TRUE(itBase->second.hasCurrentState);
4350     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4351     EXPECT_EQ(screenOnGroup.group_id(),
4352               itBase->second.currentState.getValues()[0].mValue.long_value);
4353     // Value for dimension, state key {{}, ON GROUP}
4354     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4355     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4356     EXPECT_EQ(screenOnGroup.group_id(),
4357               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4358     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
4359     // Value for dimension, state key {{}, kStateUnknown}
4360     it++;
4361     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4362     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4363     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4364               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4365     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4366     EXPECT_EQ(2, it->second.intervals[0].aggregate.long_value);
4367     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4368                          bucketStartTimeNs + 5 * NS_PER_SEC);
4369 
4370     // Bucket status after screen state change ON->VR.
4371     // Both ON and VR are in the same state group, so the base should not change.
4372     screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
4373                                                 android::view::DisplayStateEnum::DISPLAY_STATE_VR);
4374     StateManager::getInstance().onLogEvent(*screenEvent);
4375     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4376     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4377     // Base for dimension key {}
4378     it = valueProducer->mCurrentSlicedBucket.begin();
4379     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4380     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4381     EXPECT_EQ(5, itBase->second.dimExtras[0].value().long_value);
4382     EXPECT_TRUE(itBase->second.hasCurrentState);
4383     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4384     EXPECT_EQ(screenOnGroup.group_id(),
4385               itBase->second.currentState.getValues()[0].mValue.int_value);
4386     // Value for dimension, state key {{}, ON GROUP}
4387     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4388     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4389     EXPECT_EQ(screenOnGroup.group_id(),
4390               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4391     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
4392     // Value for dimension, state key {{}, kStateUnknown}
4393     it++;
4394     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4395     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4396     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4397               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4398     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4399     EXPECT_EQ(2, it->second.intervals[0].aggregate.long_value);
4400     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4401                          bucketStartTimeNs + 5 * NS_PER_SEC);
4402 
4403     // Bucket status after screen state change VR->ON.
4404     // Both ON and VR are in the same state group, so the base should not change.
4405     screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 12 * NS_PER_SEC,
4406                                                 android::view::DisplayStateEnum::DISPLAY_STATE_ON);
4407     StateManager::getInstance().onLogEvent(*screenEvent);
4408     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4409     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4410     // Base for dimension key {}
4411     it = valueProducer->mCurrentSlicedBucket.begin();
4412     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4413     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4414     EXPECT_EQ(5, itBase->second.dimExtras[0].value().long_value);
4415     EXPECT_TRUE(itBase->second.hasCurrentState);
4416     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4417     EXPECT_EQ(screenOnGroup.group_id(),
4418               itBase->second.currentState.getValues()[0].mValue.int_value);
4419     // Value for dimension, state key {{}, ON GROUP}
4420     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4421     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4422     EXPECT_EQ(screenOnGroup.group_id(),
4423               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4424     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
4425     // Value for dimension, state key {{}, kStateUnknown}
4426     it++;
4427     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4428     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4429     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4430               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4431     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4432     EXPECT_EQ(2, it->second.intervals[0].aggregate.long_value);
4433     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4434                          bucketStartTimeNs + 5 * NS_PER_SEC);
4435 
4436     // Bucket status after screen state change VR->OFF.
4437     screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC,
4438                                                 android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
4439     StateManager::getInstance().onLogEvent(*screenEvent);
4440     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
4441     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4442     // Base for dimension key {}
4443     it = valueProducer->mCurrentSlicedBucket.begin();
4444     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4445     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4446     EXPECT_EQ(21, itBase->second.dimExtras[0].value().long_value);
4447     EXPECT_TRUE(itBase->second.hasCurrentState);
4448     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4449     EXPECT_EQ(screenOffGroup.group_id(),
4450               itBase->second.currentState.getValues()[0].mValue.int_value);
4451     // Value for dimension, state key {{}, OFF GROUP}
4452     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4453     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4454     EXPECT_EQ(screenOffGroup.group_id(),
4455               it->first.getStateValuesKey().getValues()[0].mValue.long_value);
4456     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 15 * NS_PER_SEC);
4457     // Value for dimension, state key {{}, ON GROUP}
4458     it++;
4459     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4460     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4461     EXPECT_EQ(screenOnGroup.group_id(),
4462               it->first.getStateValuesKey().getValues()[0].mValue.long_value);
4463     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4464     EXPECT_EQ(16, it->second.intervals[0].aggregate.long_value);
4465     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
4466                          bucketStartTimeNs + 15 * NS_PER_SEC);
4467     // Value for dimension, state key {{}, kStateUnknown}
4468     it++;
4469     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4470     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4471     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4472               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4473     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
4474     EXPECT_EQ(2, it->second.intervals[0].aggregate.long_value);
4475     assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
4476                          bucketStartTimeNs + 5 * NS_PER_SEC);
4477 
4478     // Start dump report and check output.
4479     ProtoOutputStream output;
4480     std::set<string> strSet;
4481     valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
4482                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
4483                                 &strSet, &output);
4484 
4485     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
4486     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4487     // Base for dimension key {}
4488     it = valueProducer->mCurrentSlicedBucket.begin();
4489     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4490     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
4491     EXPECT_EQ(30, itBase->second.dimExtras[0].value().long_value);
4492     EXPECT_TRUE(itBase->second.hasCurrentState);
4493     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4494     EXPECT_EQ(screenOffGroup.group_id(),
4495               itBase->second.currentState.getValues()[0].mValue.int_value);
4496     // Value for dimension, state key {{}, OFF GROUP}
4497     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4498     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4499     EXPECT_EQ(screenOffGroup.group_id(),
4500               it->first.getStateValuesKey().getValues()[0].mValue.long_value);
4501     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 50 * NS_PER_SEC);
4502 
4503     StatsLogReport report = outputStreamToProto(&output);
4504     EXPECT_TRUE(report.has_value_metrics());
4505     ASSERT_EQ(3, report.value_metrics().data_size());
4506 
4507     // {{}, kStateUnknown}
4508     auto data = report.value_metrics().data(0);
4509     ASSERT_EQ(1, data.bucket_info_size());
4510     EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
4511     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
4512     EXPECT_TRUE(data.slice_by_state(0).has_value());
4513     EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
4514     EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
4515 
4516     // {{}, ON GROUP}
4517     data = report.value_metrics().data(1);
4518     ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
4519     EXPECT_EQ(16, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
4520     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
4521     EXPECT_TRUE(data.slice_by_state(0).has_group_id());
4522     EXPECT_EQ(screenOnGroup.group_id(), data.slice_by_state(0).group_id());
4523     EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
4524 
4525     // {{}, OFF GROUP}
4526     data = report.value_metrics().data(2);
4527     ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
4528     EXPECT_EQ(9, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
4529     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
4530     EXPECT_TRUE(data.slice_by_state(0).has_group_id());
4531     EXPECT_EQ(screenOffGroup.group_id(), data.slice_by_state(0).group_id());
4532     EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
4533 }
4534 
4535 /*
4536  * Test metric that slices by state with a primary field and has dimensions
4537  * - Increasing values
4538  * - Using diff
4539  * - Second field is value field
4540  */
TEST(NumericValueMetricProducerTest,TestSlicedStateWithPrimaryField_WithDimensions)4541 TEST(NumericValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
4542     // Set up NumericValueMetricProducer.
4543     ValueMetric metric =
4544             NumericValueMetricProducerTestHelper::createMetricWithState("UID_PROCESS_STATE");
4545     metric.mutable_dimensions_in_what()->set_field(tagId);
4546     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
4547     metric.set_condition_correction_threshold_nanos(0);
4548 
4549     MetricStateLink* stateLink = metric.add_state_link();
4550     stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
4551     auto fieldsInWhat = stateLink->mutable_fields_in_what();
4552     *fieldsInWhat = CreateDimensions(tagId, {1 /* uid */});
4553     auto fieldsInState = stateLink->mutable_fields_in_state();
4554     *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
4555 
4556     /*
4557     NOTE: "1" denotes uid 1 and "2" denotes uid 2.
4558                     bucket # 1                            bucket # 2
4559     10     20     30     40     50     60     70     80     90    100    110    120 (seconds)
4560     |------------------------------------------|---------------------------------|--
4561 
4562                                                                                     (kStateUnknown)
4563     1
4564     |-------------|
4565           20
4566 
4567     2
4568     |----------------------------|
4569                  40
4570 
4571                                                                                     (FOREGROUND)
4572                   1                                                       1
4573                   |----------------------------|-------------|            |------|
4574                                40                     20                     10
4575 
4576 
4577                                                                                     (BACKGROUND)
4578                                                              1
4579                                                              |------------|
4580                                                                    20
4581                                  2
4582                                  |-------------|---------------------------------|
4583                                        20                      50
4584     */
4585     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
4586     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
4587             // NumericValueMetricProducer initialized.
4588             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4589                                 vector<std::shared_ptr<LogEvent>>* data) {
4590                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
4591                 data->clear();
4592                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1 /*uid*/, 3));
4593                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 2 /*uid*/, 7));
4594                 return true;
4595             }))
4596             // Uid 1 process state change from kStateUnknown -> Foreground
4597             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4598                                 vector<std::shared_ptr<LogEvent>>* data) {
4599                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
4600                 data->clear();
4601                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
4602                                                        1 /*uid*/, 6));
4603                 // This event should be skipped.
4604                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
4605                                                        2 /*uid*/, 8));
4606                 return true;
4607             }))
4608             // Uid 2 process state change from kStateUnknown -> Background
4609             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4610                                 vector<std::shared_ptr<LogEvent>>* data) {
4611                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
4612                 data->clear();
4613                 // This event should be skipped.
4614                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
4615                                                        1 /*uid*/, 12));
4616                 data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
4617                                                        2 /*uid*/, 9));
4618                 return true;
4619             }))
4620             // Uid 1 process state change from Foreground -> Background
4621             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4622                                 vector<std::shared_ptr<LogEvent>>* data) {
4623                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 20 * NS_PER_SEC);
4624                 data->clear();
4625                 data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20 * NS_PER_SEC,
4626                                                        1 /*uid*/, 13));
4627                 // This event should be skipped.
4628                 data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20 * NS_PER_SEC,
4629                                                        2 /*uid*/, 11));
4630                 return true;
4631             }))
4632             // Uid 1 process state change from Background -> Foreground
4633             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4634                                 vector<std::shared_ptr<LogEvent>>* data) {
4635                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 40 * NS_PER_SEC);
4636                 data->clear();
4637                 data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40 * NS_PER_SEC,
4638                                                        1 /*uid*/, 17));
4639 
4640                 // This event should be skipped.
4641                 data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40 * NS_PER_SEC,
4642                                                        2 /*uid */, 15));
4643                 return true;
4644             }))
4645             // Dump report pull.
4646             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4647                                 vector<std::shared_ptr<LogEvent>>* data) {
4648                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
4649                 data->clear();
4650                 data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50 * NS_PER_SEC,
4651                                                        1 /*uid*/, 21));
4652                 data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50 * NS_PER_SEC,
4653                                                        2 /*uid*/, 20));
4654                 return true;
4655             }));
4656 
4657     StateManager::getInstance().clear();
4658     sp<NumericValueMetricProducer> valueProducer =
4659             NumericValueMetricProducerTestHelper::createValueProducerWithState(
4660                     pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {});
4661 
4662     // Set up StateManager and check that StateTrackers are initialized.
4663     StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
4664     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
4665     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
4666 
4667     // Bucket status after metric initialized.
4668     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4669     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
4670 
4671     // Bucket status after uid 1 process state change kStateUnknown -> Foreground.
4672     auto uidProcessEvent =
4673             CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
4674                                               android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
4675     StateManager::getInstance().onLogEvent(*uidProcessEvent);
4676     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
4677     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
4678 
4679     // Bucket status after uid 2 process state change kStateUnknown -> Background.
4680     uidProcessEvent =
4681             CreateUidProcessStateChangedEvent(bucketStartTimeNs + 40 * NS_PER_SEC, 2 /* uid */,
4682                                               android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
4683     StateManager::getInstance().onLogEvent(*uidProcessEvent);
4684     ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
4685     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
4686 
4687     // Pull at end of first bucket.
4688     vector<shared_ptr<LogEvent>> allData;
4689     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 10));
4690     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs, 2 /*uid*/, 15));
4691     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 1);
4692 
4693     // Ensure the MetricDimensionKeys for the current state are kept.
4694     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4695     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
4696     auto it = valueProducer->mCurrentSlicedBucket.begin();  // dimension, state key {2, BACKGROUND}
4697     EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
4698     EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
4699     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4700     EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
4701               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4702     it++;  // dimension, state key {1, FOREGROUND}
4703     EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
4704     EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
4705     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4706     EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
4707               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4708 
4709     // Bucket status after uid 1 process state change from Foreground -> Background.
4710     uidProcessEvent =
4711             CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
4712                                               android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
4713     StateManager::getInstance().onLogEvent(*uidProcessEvent);
4714     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
4715     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
4716 
4717     // Bucket status after uid 1 process state change Background->Foreground.
4718     uidProcessEvent =
4719             CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 40 * NS_PER_SEC, 1 /* uid */,
4720                                               android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
4721     StateManager::getInstance().onLogEvent(*uidProcessEvent);
4722     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
4723     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
4724 
4725     // Start dump report and check output.
4726     ProtoOutputStream output;
4727     std::set<string> strSet;
4728     int64_t dumpReportTimeNs = bucket2StartTimeNs + 50 * NS_PER_SEC;
4729     valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
4730                                 NO_TIME_CONSTRAINTS, &strSet, &output);
4731 
4732     StatsLogReport report = outputStreamToProto(&output);
4733     backfillDimensionPath(&report);
4734     backfillStartEndTimestamp(&report);
4735     EXPECT_TRUE(report.has_value_metrics());
4736     StatsLogReport::ValueMetricDataWrapper valueMetrics;
4737     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
4738     ASSERT_EQ(5, valueMetrics.data_size());
4739     ASSERT_EQ(0, report.value_metrics().skipped_size());
4740 
4741     // {uid 1, kStateUnknown}
4742     ValueMetricData data = valueMetrics.data(0);
4743     ASSERT_EQ(1, data.bucket_info_size());
4744     ValidateUidDimension(data.dimensions_in_what(), tagId, 1);
4745     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
4746                        -1 /*StateTracker::kStateUnknown*/);
4747     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {3},
4748                         20 * NS_PER_SEC, 0);
4749 
4750     // {uid 1, FOREGROUND}
4751     data = valueMetrics.data(1);
4752     ASSERT_EQ(2, data.bucket_info_size());
4753     ValidateUidDimension(data.dimensions_in_what(), tagId, 1);
4754     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
4755                        android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);
4756     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {4},
4757                         40 * NS_PER_SEC, 1);
4758     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, dumpReportTimeNs, {7},
4759                         30 * NS_PER_SEC, -1);
4760 
4761     // {uid 1, BACKGROUND}
4762     data = valueMetrics.data(2);
4763     ASSERT_EQ(1, data.bucket_info_size());
4764     ValidateUidDimension(data.dimensions_in_what(), tagId, 1);
4765     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
4766                        android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND);
4767     ValidateValueBucket(data.bucket_info(0), bucket2StartTimeNs, dumpReportTimeNs, {4},
4768                         20 * NS_PER_SEC, -1);
4769 
4770     // {uid 2, kStateUnknown}
4771     data = valueMetrics.data(3);
4772     ASSERT_EQ(1, data.bucket_info_size());
4773     ValidateUidDimension(data.dimensions_in_what(), tagId, 2);
4774     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
4775                        -1 /*StateTracker::kStateUnknown*/);
4776     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {2},
4777                         40 * NS_PER_SEC, -1);
4778 
4779     // {uid 2, BACKGROUND}
4780     data = valueMetrics.data(4);
4781     ASSERT_EQ(2, data.bucket_info_size());
4782     ValidateUidDimension(data.dimensions_in_what(), tagId, 2);
4783     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
4784                        android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND);
4785     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {6},
4786                         20 * NS_PER_SEC, 1);
4787     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, dumpReportTimeNs, {5},
4788                         50 * NS_PER_SEC, -1);
4789 }
4790 
4791 /*
4792  * Test slicing condition_true_nanos by state for metric that slices by state when data is not
4793  * present in pulled data during a state change.
4794  */
TEST(NumericValueMetricProducerTest,TestSlicedStateWithMissingDataInStateChange)4795 TEST(NumericValueMetricProducerTest, TestSlicedStateWithMissingDataInStateChange) {
4796     // Set up NumericValueMetricProducer.
4797     ValueMetric metric =
4798             NumericValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
4799     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
4800     /*
4801     NOTE: "-" means that the data was not present in the pulled data.
4802 
4803                              bucket # 1
4804     10         20         30         40         50         60   (seconds)
4805     |-------------------------------------------------------|--
4806     x                                                           (kStateUnknown)
4807     |-----------|
4808          10
4809 
4810                 x                               x               (ON)
4811                 |---------------------|         |-----------|
4812                            20                        10
4813 
4814                                       -                         (OFF)
4815     */
4816     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
4817             // NumericValueMetricProducer initialized.
4818             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4819                                 vector<std::shared_ptr<LogEvent>>* data) {
4820                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
4821                 data->clear();
4822                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
4823                 return true;
4824             }))
4825             // Battery saver mode state changed to ON.
4826             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4827                                 vector<std::shared_ptr<LogEvent>>* data) {
4828                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
4829                 data->clear();
4830                 data->push_back(
4831                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 5));
4832                 return true;
4833             }))
4834             // Battery saver mode state changed to OFF but data for dimension key {} is not present
4835             // in the pulled data.
4836             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4837                                 vector<std::shared_ptr<LogEvent>>* data) {
4838                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
4839                 data->clear();
4840                 return true;
4841             }))
4842             // Battery saver mode state changed to ON.
4843             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4844                                 vector<std::shared_ptr<LogEvent>>* data) {
4845                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
4846                 data->clear();
4847                 data->push_back(
4848                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 7));
4849                 return true;
4850             }))
4851             // Dump report pull.
4852             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
4853                                 vector<std::shared_ptr<LogEvent>>* data) {
4854                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
4855                 data->clear();
4856                 data->push_back(CreateRepeatedValueLogEvent(
4857                         tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 15));
4858                 return true;
4859             }));
4860 
4861     StateManager::getInstance().clear();
4862     sp<NumericValueMetricProducer> valueProducer =
4863             NumericValueMetricProducerTestHelper::createValueProducerWithState(
4864                     pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
4865     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
4866 
4867     // Set up StateManager and check that StateTrackers are initialized.
4868     StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
4869                                                  valueProducer);
4870     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
4871     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
4872                          util::BATTERY_SAVER_MODE_STATE_CHANGED));
4873 
4874     // Bucket status after metric initialized.
4875     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
4876     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4877     // Base for dimension key {}
4878     auto it = valueProducer->mCurrentSlicedBucket.begin();
4879     auto itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4880     EXPECT_TRUE(itBase->second.hasCurrentState);
4881     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4882     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4883               itBase->second.currentState.getValues()[0].mValue.int_value);
4884     // Value for dimension, state key {{}, kStateUnknown}
4885     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4886     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4887     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
4888               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4889     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
4890 
4891     // Bucket status after battery saver mode ON event.
4892     unique_ptr<LogEvent> batterySaverOnEvent =
4893             CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
4894     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
4895 
4896     // Base for dimension key {}
4897 
4898     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4899     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4900     it = valueProducer->mCurrentSlicedBucket.begin();
4901     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4902     EXPECT_TRUE(itBase->second.hasCurrentState);
4903     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4904     EXPECT_EQ(BatterySaverModeStateChanged::ON,
4905               itBase->second.currentState.getValues()[0].mValue.int_value);
4906     // Value for key {{}, ON}
4907     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4908     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4909     EXPECT_EQ(BatterySaverModeStateChanged::ON,
4910               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4911     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
4912 
4913     // Value for key {{}, -1}
4914     it++;
4915     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4916     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4917     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
4918               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4919     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
4920                          bucketStartTimeNs + 10 * NS_PER_SEC);
4921 
4922     // Bucket status after battery saver mode OFF event which is not present
4923     // in the pulled data.
4924     unique_ptr<LogEvent> batterySaverOffEvent =
4925             CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC);
4926     StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
4927 
4928     // Base for dimension key {} is cleared.
4929     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
4930     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4931     it = valueProducer->mCurrentSlicedBucket.begin();
4932     // Value for key {{}, ON}
4933     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4934     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4935     EXPECT_EQ(BatterySaverModeStateChanged::ON,
4936               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4937     assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
4938                          bucketStartTimeNs + 30 * NS_PER_SEC);
4939 
4940     // Value for key {{}, -1}
4941     it++;
4942     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4943     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4944     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
4945               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4946     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
4947                          bucketStartTimeNs + 10 * NS_PER_SEC);
4948 
4949     // Bucket status after battery saver mode ON event.
4950     batterySaverOnEvent =
4951             CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 40 * NS_PER_SEC);
4952     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
4953 
4954     // Base for dimension key {}
4955     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
4956     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
4957     it = valueProducer->mCurrentSlicedBucket.begin();
4958     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
4959     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
4960     EXPECT_EQ(BatterySaverModeStateChanged::ON,
4961               itBase->second.currentState.getValues()[0].mValue.int_value);
4962     // Value for key {{}, ON}
4963     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4964     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4965     EXPECT_EQ(BatterySaverModeStateChanged::ON,
4966               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4967     assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
4968                          bucketStartTimeNs + 40 * NS_PER_SEC);
4969 
4970     // Value for key {{}, -1}
4971     it++;
4972     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
4973     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
4974     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
4975               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
4976     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
4977                          bucketStartTimeNs + 10 * NS_PER_SEC);
4978 
4979     // Start dump report and check output.
4980     ProtoOutputStream output;
4981     std::set<string> strSet;
4982     valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
4983                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
4984                                 &strSet, &output);
4985 
4986     StatsLogReport report = outputStreamToProto(&output);
4987     backfillDimensionPath(&report);
4988     backfillStartEndTimestamp(&report);
4989     EXPECT_TRUE(report.has_value_metrics());
4990     ASSERT_EQ(2, report.value_metrics().data_size());
4991 
4992     // {{}, kStateUnknown}
4993     ValueMetricData data = report.value_metrics().data(0);
4994     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
4995     EXPECT_EQ(-1 /*StateTracker::kUnknown*/, data.slice_by_state(0).value());
4996     ASSERT_EQ(1, data.bucket_info_size());
4997     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC,
4998                         {2}, 10 * NS_PER_SEC, -1);
4999 
5000     // {{}, ON}
5001     data = report.value_metrics().data(1);
5002     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
5003     EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
5004     ASSERT_EQ(1, data.bucket_info_size());
5005     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC,
5006                         {8}, 30 * NS_PER_SEC, -1);
5007 }
5008 
5009 /*
5010  * Test for metric that slices by state when data is not present in pulled data
5011  * during an event and then a flush occurs for the current bucket. With the new
5012  * condition timer behavior, a "new" MetricDimensionKey is inserted into
5013  * `mCurrentSlicedBucket` before intervals are closed/added to that new
5014  * MetricDimensionKey.
5015  */
TEST(NumericValueMetricProducerTest,TestSlicedStateWithMissingDataThenFlushBucket)5016 TEST(NumericValueMetricProducerTest, TestSlicedStateWithMissingDataThenFlushBucket) {
5017     // Set up NumericValueMetricProducer.
5018     ValueMetric metric =
5019             NumericValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
5020     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
5021     /*
5022     NOTE: "-" means that the data was not present in the pulled data.
5023 
5024                              bucket # 1
5025     10         20         30         40         50         60   (seconds)
5026     |-------------------------------------------------------|--
5027     -                                                           (kStateUnknown)
5028 
5029                 -                                               (ON)
5030     */
5031     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
5032             // NumericValueMetricProducer initialized  but data for dimension key {} is not present
5033             // in the pulled data..
5034             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5035                                 vector<std::shared_ptr<LogEvent>>* data) {
5036                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
5037                 data->clear();
5038                 return true;
5039             }))
5040             // Battery saver mode state changed to ON but data for dimension key {} is not present
5041             // in the pulled data.
5042             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5043                                 vector<std::shared_ptr<LogEvent>>* data) {
5044                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
5045                 data->clear();
5046                 return true;
5047             }))
5048             // Dump report pull.
5049             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5050                                 vector<std::shared_ptr<LogEvent>>* data) {
5051                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
5052                 data->clear();
5053                 data->push_back(CreateRepeatedValueLogEvent(
5054                         tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 15));
5055                 return true;
5056             }));
5057 
5058     StateManager::getInstance().clear();
5059     sp<NumericValueMetricProducer> valueProducer =
5060             NumericValueMetricProducerTestHelper::createValueProducerWithState(
5061                     pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
5062     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
5063 
5064     // Set up StateManager and check that StateTrackers are initialized.
5065     StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
5066                                                  valueProducer);
5067     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
5068     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
5069                          util::BATTERY_SAVER_MODE_STATE_CHANGED));
5070 
5071     // Bucket status after metric initialized.
5072     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
5073     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
5074 
5075     // Bucket status after battery saver mode ON event which is not present
5076     // in the pulled data.
5077     unique_ptr<LogEvent> batterySaverOnEvent =
5078             CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
5079     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
5080 
5081     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
5082     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
5083 
5084     // Start dump report and check output.
5085     ProtoOutputStream output;
5086     std::set<string> strSet;
5087     valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
5088                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
5089                                 &strSet, &output);
5090 
5091     StatsLogReport report = outputStreamToProto(&output);
5092     EXPECT_TRUE(report.has_value_metrics());
5093     ASSERT_EQ(0, report.value_metrics().data_size());
5094     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
5095     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5096 }
5097 
TEST(NumericValueMetricProducerTest,TestSlicedStateWithNoPullOnBucketBoundary)5098 TEST(NumericValueMetricProducerTest, TestSlicedStateWithNoPullOnBucketBoundary) {
5099     // Set up NumericValueMetricProducer.
5100     ValueMetric metric =
5101             NumericValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
5102     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
5103     /*
5104                  bucket # 1                         bucket # 2
5105     10    20    30    40    50    60    70    80   90   100   110   120  (seconds)
5106     |------------------------------------|---------------------------|--
5107     x                                                                    (kStateUnknown)
5108     |-----|
5109       10
5110           x                                              x               (ON)
5111           |-----|                                        |-----------|
5112              10                                               20
5113                 x                                                        (OFF)
5114                 |------------------------|
5115                           40
5116     */
5117     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
5118             // NumericValueMetricProducer initialized.
5119             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5120                                 vector<std::shared_ptr<LogEvent>>* data) {
5121                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
5122                 data->clear();
5123                 data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
5124                 return true;
5125             }))
5126             // Battery saver mode state changed to ON.
5127             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5128                                 vector<std::shared_ptr<LogEvent>>* data) {
5129                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
5130                 data->clear();
5131                 data->push_back(
5132                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 5));
5133                 return true;
5134             }))
5135             // Battery saver mode state changed to OFF.
5136             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5137                                 vector<std::shared_ptr<LogEvent>>* data) {
5138                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
5139                 data->clear();
5140                 data->push_back(
5141                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 7));
5142                 return true;
5143             }))
5144             // Battery saver mode state changed to ON.
5145             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5146                                 vector<std::shared_ptr<LogEvent>>* data) {
5147                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
5148                 data->clear();
5149                 data->push_back(CreateRepeatedValueLogEvent(
5150                         tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 10));
5151                 return true;
5152             }))
5153             // Dump report pull.
5154             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5155                                 vector<std::shared_ptr<LogEvent>>* data) {
5156                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
5157                 data->clear();
5158                 data->push_back(CreateRepeatedValueLogEvent(
5159                         tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 15));
5160                 return true;
5161             }));
5162 
5163     StateManager::getInstance().clear();
5164     sp<NumericValueMetricProducer> valueProducer =
5165             NumericValueMetricProducerTestHelper::createValueProducerWithState(
5166                     pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
5167     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
5168 
5169     // Set up StateManager and check that StateTrackers are initialized.
5170     StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
5171                                                  valueProducer);
5172     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
5173     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
5174                          util::BATTERY_SAVER_MODE_STATE_CHANGED));
5175 
5176     // Bucket status after metric initialized.
5177     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
5178     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5179     auto it = valueProducer->mCurrentSlicedBucket.begin();
5180     auto itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
5181     EXPECT_TRUE(itBase->second.hasCurrentState);
5182     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5183     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
5184               itBase->second.currentState.getValues()[0].mValue.int_value);
5185     // Value for dimension, state key {{}, kStateUnknown}
5186     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5187     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5188     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
5189               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5190     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
5191 
5192     // Bucket status after battery saver mode ON event.
5193     unique_ptr<LogEvent> batterySaverOnEvent =
5194             CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
5195     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
5196 
5197     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5198     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
5199     it = valueProducer->mCurrentSlicedBucket.begin();
5200     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
5201     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5202     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5203               itBase->second.currentState.getValues()[0].mValue.int_value);
5204     // Value for key {{}, ON}
5205     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5206     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5207     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5208               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5209     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
5210 
5211     // Value for key {{}, -1}
5212     it++;
5213     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5214     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5215     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
5216               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5217     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
5218                          bucketStartTimeNs + 10 * NS_PER_SEC);
5219 
5220     // Bucket status after battery saver mode OFF event.
5221     unique_ptr<LogEvent> batterySaverOffEvent =
5222             CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 20 * NS_PER_SEC);
5223     StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
5224 
5225     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5226     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
5227     it = valueProducer->mCurrentSlicedBucket.begin();
5228     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
5229     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5230     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
5231               itBase->second.currentState.getValues()[0].mValue.int_value);
5232     // Value for key {{}, OFF}
5233     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5234     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5235     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
5236               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5237     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
5238 
5239     // Value for key {{}, ON}
5240     it++;
5241     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5242     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5243     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5244               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5245     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
5246                          bucketStartTimeNs + 20 * NS_PER_SEC);
5247 
5248     // Value for key {{}, -1}
5249     it++;
5250     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5251     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5252     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
5253               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5254     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
5255                          bucketStartTimeNs + 10 * NS_PER_SEC);
5256 
5257     // Bucket status after battery saver mode ON event.
5258     batterySaverOnEvent =
5259             CreateBatterySaverOnEvent(/*timestamp=*/bucket2StartTimeNs + 30 * NS_PER_SEC);
5260     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
5261 
5262     // Bucket split. all MetricDimensionKeys other than the current state key are trimmed.
5263     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5264     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
5265     it = valueProducer->mCurrentSlicedBucket.begin();
5266     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
5267     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5268     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5269               itBase->second.currentState.getValues()[0].mValue.int_value);
5270     // Value for key {{}, ON}
5271     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5272     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5273     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5274               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5275     assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 30 * NS_PER_SEC);
5276 
5277     // Start dump report and check output.
5278     ProtoOutputStream output;
5279     std::set<string> strSet;
5280     valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
5281                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
5282                                 &strSet, &output);
5283     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5284     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
5285 
5286     StatsLogReport report = outputStreamToProto(&output);
5287     backfillDimensionPath(&report);
5288     backfillStartEndTimestamp(&report);
5289     EXPECT_TRUE(report.has_value_metrics());
5290     ASSERT_EQ(3, report.value_metrics().data_size());
5291 
5292     // {{}, kStateUnknown}
5293     ValueMetricData data = report.value_metrics().data(0);
5294     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
5295     EXPECT_EQ(-1 /*StateTracker::kUnknown*/, data.slice_by_state(0).value());
5296     ASSERT_EQ(1, data.bucket_info_size());
5297     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {2},
5298                         10 * NS_PER_SEC, -1);
5299 
5300     // {{}, ON}
5301     data = report.value_metrics().data(1);
5302     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
5303     EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
5304     ASSERT_EQ(2, data.bucket_info_size());
5305     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {2},
5306                         10 * NS_PER_SEC, -1);
5307     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs,
5308                         bucket2StartTimeNs + 50 * NS_PER_SEC, {5}, 20 * NS_PER_SEC, -1);
5309 
5310     // {{}, OFF}
5311     data = report.value_metrics().data(2);
5312     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
5313     EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value());
5314     ASSERT_EQ(1, data.bucket_info_size());
5315     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {3},
5316                         40 * NS_PER_SEC, -1);
5317 }
5318 
5319 /*
5320  * Test slicing condition_true_nanos by state for metric that slices by state when data is not
5321  * present in pulled data during a condition change.
5322  */
TEST(NumericValueMetricProducerTest,TestSlicedStateWithDataMissingInConditionChange)5323 TEST(NumericValueMetricProducerTest, TestSlicedStateWithDataMissingInConditionChange) {
5324     // Set up NumericValueMetricProducer.
5325     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithConditionAndState(
5326             "BATTERY_SAVER_MODE_STATE");
5327     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
5328     /*
5329     NOTE: "-" means that the data was not present in the pulled data.
5330 
5331                              bucket # 1
5332     10         20         30         40         50         60   (seconds)
5333     |-------------------------------------------------------|--
5334 
5335     T                                 F         T               (Condition)
5336                x                                       x        (ON)
5337                |----------------------|         -      |----|
5338                          20                               5
5339                                            x                    (OFF)
5340     */
5341     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
5342             // Battery saver mode state changed to ON.
5343             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5344                                 vector<std::shared_ptr<LogEvent>>* data) {
5345                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
5346                 data->clear();
5347                 data->push_back(
5348                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 3));
5349                 return true;
5350             }))
5351             // Condition changed to false.
5352             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5353                                 vector<std::shared_ptr<LogEvent>>* data) {
5354                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
5355                 data->clear();
5356                 data->push_back(
5357                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5));
5358                 return true;
5359             }))
5360             // Condition changed to true but data for dimension key {} is not present in the
5361             // pulled data.
5362             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5363                                 vector<std::shared_ptr<LogEvent>>* data) {
5364                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
5365                 data->clear();
5366                 return true;
5367             }))
5368             // Battery saver mode state changed to ON.
5369             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5370                                 vector<std::shared_ptr<LogEvent>>* data) {
5371                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 45 * NS_PER_SEC);
5372                 data->clear();
5373                 data->push_back(CreateRepeatedValueLogEvent(
5374                         tagId, bucketStartTimeNs + 45 * NS_PER_SEC, 14));
5375                 return true;
5376             }))
5377             // Dump report pull.
5378             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5379                                 vector<std::shared_ptr<LogEvent>>* data) {
5380                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
5381                 data->clear();
5382                 data->push_back(CreateRepeatedValueLogEvent(
5383                         tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 20));
5384                 return true;
5385             }));
5386 
5387     StateManager::getInstance().clear();
5388     sp<NumericValueMetricProducer> valueProducer =
5389             NumericValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
5390                     pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {},
5391                     ConditionState::kTrue);
5392     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
5393 
5394     // Set up StateManager and check that StateTrackers are initialized.
5395     StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
5396                                                  valueProducer);
5397     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
5398     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
5399                          util::BATTERY_SAVER_MODE_STATE_CHANGED));
5400 
5401     // Bucket status after battery saver mode ON event.
5402     unique_ptr<LogEvent> batterySaverOnEvent =
5403             CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
5404     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
5405     // Base for dimension key {}
5406     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5407     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
5408     auto it = valueProducer->mCurrentSlicedBucket.begin();
5409     auto itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
5410     EXPECT_TRUE(itBase->second.hasCurrentState);
5411     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5412     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5413               itBase->second.currentState.getValues()[0].mValue.int_value);
5414     // Value for key {{}, ON}
5415     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5416     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5417     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5418               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5419     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
5420 
5421     // Value for key {{}, -1}
5422     it++;
5423     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5424     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5425     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
5426               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5427     assertConditionTimer(it->second.conditionTimer, false, 0, 0);
5428 
5429     // Bucket status after condition change to false.
5430     valueProducer->onConditionChanged(false, bucketStartTimeNs + 30 * NS_PER_SEC);
5431     // Base for dimension key {}
5432     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5433     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
5434     it = valueProducer->mCurrentSlicedBucket.begin();
5435     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
5436     EXPECT_TRUE(itBase->second.hasCurrentState);
5437     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5438     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5439               itBase->second.currentState.getValues()[0].mValue.int_value);
5440     // Value for key {{}, ON}
5441     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5442     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5443     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5444               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5445     assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
5446                          bucketStartTimeNs + 30 * NS_PER_SEC);
5447 
5448     // Value for key {{}, -1}
5449     it++;
5450     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5451     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5452     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
5453               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5454     assertConditionTimer(it->second.conditionTimer, false, 0, 0);
5455 
5456     unique_ptr<LogEvent> batterySaverOffEvent =
5457             CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 35 * NS_PER_SEC);
5458     StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
5459     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5460     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
5461 
5462     // Bucket status after condition change to true.
5463     valueProducer->onConditionChanged(true, bucketStartTimeNs + 40 * NS_PER_SEC);
5464     // Base for dimension key {}. The pull returned no data, so mDimInfos is trimmed.
5465     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
5466     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
5467     it = valueProducer->mCurrentSlicedBucket.begin();
5468     // Value for key {{}, ON}
5469     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5470     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5471     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5472               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5473     assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
5474                          bucketStartTimeNs + 30 * NS_PER_SEC);
5475 
5476     // Value for key {{}, -1}
5477     it++;
5478     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5479     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5480     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
5481               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5482     assertConditionTimer(it->second.conditionTimer, false, 0, 0);
5483 
5484     batterySaverOnEvent =
5485             CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 45 * NS_PER_SEC);
5486     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
5487     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5488     itBase = valueProducer->mDimInfos.find(it->first.getDimensionKeyInWhat());
5489     EXPECT_TRUE(itBase->second.hasCurrentState);
5490     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5491     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5492               itBase->second.currentState.getValues()[0].mValue.int_value);
5493     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
5494 
5495     // Start dump report and check output.
5496     ProtoOutputStream output;
5497     std::set<string> strSet;
5498     valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
5499                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
5500                                 &strSet, &output);
5501     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5502     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
5503 
5504     StatsLogReport report = outputStreamToProto(&output);
5505     backfillDimensionPath(&report);
5506     backfillStartEndTimestamp(&report);
5507     EXPECT_TRUE(report.has_value_metrics());
5508     ASSERT_EQ(1, report.value_metrics().data_size());
5509 
5510     // {{}, ON}
5511     ValueMetricData data = report.value_metrics().data(0);
5512     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
5513     EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
5514     ASSERT_EQ(1, data.bucket_info_size());
5515     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC,
5516                         {2 + 6}, 25 * NS_PER_SEC, -1);
5517 }
5518 
5519 /*
5520  * Test slicing condition_true_nanos by state for metric that slices by state with a primary field,
5521  * condition, and has multiple dimensions.
5522  */
TEST(NumericValueMetricProducerTest,TestSlicedStateWithMultipleDimensions)5523 TEST(NumericValueMetricProducerTest, TestSlicedStateWithMultipleDimensions) {
5524     // Set up NumericValueMetricProducer.
5525     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithConditionAndState(
5526             "UID_PROCESS_STATE");
5527     metric.mutable_dimensions_in_what()->set_field(tagId);
5528     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
5529     metric.mutable_dimensions_in_what()->add_child()->set_field(3);
5530 
5531     MetricStateLink* stateLink = metric.add_state_link();
5532     stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
5533     auto fieldsInWhat = stateLink->mutable_fields_in_what();
5534     *fieldsInWhat = CreateDimensions(tagId, {1 /* uid */});
5535     auto fieldsInState = stateLink->mutable_fields_in_state();
5536     *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
5537 
5538     /*
5539                     bucket # 1                            bucket # 2
5540     10     20     30     40     50     60     70     80     90    100    110    120 (seconds)
5541     |------------------------------------------|---------------------------------|--
5542 
5543     T                           F   T                                               (Condition)
5544                                                                                     (FOREGROUND)
5545            x                                                                        {1, 14}
5546            |------|
5547               10
5548 
5549            x                                                                        {1, 16}
5550            |------|
5551               10
5552                                                                    x                {2, 8}
5553                                                                    |-------------|
5554                                                                          20
5555 
5556                                                                                     (BACKGROUND)
5557                   x                                                                 {1, 14}
5558                   |-------------|   |----------|---------------------------------|
5559                         20              15                     50
5560 
5561                   x                                                                 {1, 16}
5562                   |-------------|   |----------|---------------------------------|
5563                         20              15                     50
5564 
5565                      x                                                              {2, 8}
5566                      |----------|   |----------|-------------------|
5567                          15             15              30
5568     */
5569     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
5570     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
5571             // Uid 1 process state change from kStateUnknown -> Foreground
5572             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5573                                 vector<std::shared_ptr<LogEvent>>* data) {
5574                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
5575                 data->clear();
5576                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
5577                                                          1 /*uid*/, 3, 14 /*tag*/));
5578                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
5579                                                          1 /*uid*/, 3, 16 /*tag*/));
5580 
5581                 // This event should be skipped.
5582                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
5583                                                          2 /*uid*/, 5, 8 /*tag*/));
5584                 return true;
5585             }))
5586             // Uid 1 process state change from Foreground -> Background
5587             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5588                                 vector<std::shared_ptr<LogEvent>>* data) {
5589                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
5590                 data->clear();
5591                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
5592                                                          1 /*uid*/, 5, 14 /*tag*/));
5593                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
5594                                                          1 /*uid*/, 5, 16 /*tag*/));
5595 
5596                 // This event should be skipped.
5597                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
5598                                                          2 /*uid*/, 7, 8 /*tag*/));
5599 
5600                 return true;
5601             }))
5602             // Uid 2 process state change from kStateUnknown -> Background
5603             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5604                                 vector<std::shared_ptr<LogEvent>>* data) {
5605                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 25 * NS_PER_SEC);
5606                 data->clear();
5607                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
5608                                                          2 /*uid*/, 9, 8 /*tag*/));
5609 
5610                 // This event should be skipped.
5611                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
5612                                                          1 /*uid*/, 9, 14 /* tag */));
5613 
5614                 // This event should be skipped.
5615                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
5616                                                          1 /*uid*/, 9, 16 /* tag */));
5617 
5618                 return true;
5619             }))
5620             // Condition changed to false.
5621             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5622                                 vector<std::shared_ptr<LogEvent>>* data) {
5623                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
5624                 data->clear();
5625                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
5626                                                          1 /*uid*/, 11, 14 /* tag */));
5627                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
5628                                                          1 /*uid*/, 11, 16 /* tag */));
5629                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
5630                                                          2 /*uid*/, 11, 8 /*tag*/));
5631 
5632                 return true;
5633             }))
5634             // Condition changed to true.
5635             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5636                                 vector<std::shared_ptr<LogEvent>>* data) {
5637                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 45 * NS_PER_SEC);
5638                 data->clear();
5639                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
5640                                                          1 /*uid*/, 13, 14 /* tag */));
5641                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
5642                                                          1 /*uid*/, 13, 16 /* tag */));
5643                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
5644                                                          2 /*uid*/, 13, 8 /*tag*/));
5645                 return true;
5646             }))
5647             // Uid 2 process state change from Background -> Foreground
5648             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5649                                 vector<std::shared_ptr<LogEvent>>* data) {
5650                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
5651                 data->clear();
5652                 data->push_back(CreateThreeValueLogEvent(
5653                         tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /*uid*/, 18, 8 /*tag*/));
5654 
5655                 // This event should be skipped.
5656                 data->push_back(CreateThreeValueLogEvent(
5657                         tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 14 /* tag */));
5658                 // This event should be skipped.
5659                 data->push_back(CreateThreeValueLogEvent(
5660                         tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 16 /* tag */));
5661 
5662                 return true;
5663             }))
5664             // Dump report pull.
5665             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5666                                 vector<std::shared_ptr<LogEvent>>* data) {
5667                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
5668                 data->clear();
5669                 data->push_back(CreateThreeValueLogEvent(
5670                         tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 21, 14 /* tag */));
5671                 data->push_back(CreateThreeValueLogEvent(
5672                         tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 21, 16 /* tag */));
5673                 data->push_back(CreateThreeValueLogEvent(
5674                         tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 2 /*uid*/, 21, 8 /*tag*/));
5675                 return true;
5676             }));
5677 
5678     StateManager::getInstance().clear();
5679     sp<NumericValueMetricProducer> valueProducer =
5680             NumericValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
5681                     pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {}, ConditionState::kTrue);
5682     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
5683 
5684     // Set up StateManager and check that StateTrackers are initialized.
5685     StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
5686     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
5687     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
5688 
5689     // Condition is true.
5690     auto uidProcessEvent =
5691             CreateUidProcessStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC, 1 /* uid */,
5692                                               android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
5693     StateManager::getInstance().onLogEvent(*uidProcessEvent);
5694     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
5695     ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
5696 
5697     uidProcessEvent =
5698             CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
5699                                               android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
5700     StateManager::getInstance().onLogEvent(*uidProcessEvent);
5701     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
5702     ASSERT_EQ(6UL, valueProducer->mCurrentSlicedBucket.size());
5703 
5704     uidProcessEvent =
5705             CreateUidProcessStateChangedEvent(bucketStartTimeNs + 25 * NS_PER_SEC, 2 /* uid */,
5706                                               android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
5707     StateManager::getInstance().onLogEvent(*uidProcessEvent);
5708     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
5709     ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
5710 
5711     valueProducer->onConditionChanged(false, bucketStartTimeNs + 40 * NS_PER_SEC);
5712     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
5713     ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
5714 
5715     valueProducer->onConditionChanged(true, bucketStartTimeNs + 45 * NS_PER_SEC);
5716     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
5717     ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
5718 
5719     // Pull at end of first bucket.
5720     vector<shared_ptr<LogEvent>> allData;
5721     allData.push_back(
5722             CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 14 /* tag */));
5723     allData.push_back(
5724             CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 16 /* tag */));
5725     allData.push_back(
5726             CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 2 /*uid*/, 13, 8 /*tag*/));
5727     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 1);
5728 
5729     // Buckets flushed. MetricDimensionKeys not corresponding to the current state are removed.
5730     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
5731     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
5732     ASSERT_EQ(5UL, valueProducer->mPastBuckets.size());
5733 
5734     uidProcessEvent =
5735             CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /* uid */,
5736                                               android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
5737     StateManager::getInstance().onLogEvent(*uidProcessEvent);
5738     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
5739     ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
5740 
5741     // Start dump report and check output.
5742     ProtoOutputStream output;
5743     std::set<string> strSet;
5744     valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
5745                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
5746                                 &strSet, &output);
5747     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
5748     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
5749 
5750     StatsLogReport report = outputStreamToProto(&output);
5751     backfillDimensionPath(&report);
5752     backfillStartEndTimestamp(&report);
5753     EXPECT_TRUE(report.has_value_metrics());
5754     StatsLogReport::ValueMetricDataWrapper valueMetrics;
5755     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
5756     ASSERT_EQ(6, valueMetrics.data_size());
5757     ASSERT_EQ(0, report.value_metrics().skipped_size());
5758 
5759     // {{uid 1, tag 14}, FOREGROUND}.
5760     ValueMetricData data = valueMetrics.data(0);
5761     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
5762     EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
5763               data.slice_by_state(0).value());
5764     ASSERT_EQ(1, data.bucket_info_size());
5765     EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
5766 
5767     // {{uid 1, tag 16}, BACKGROUND}.
5768     data = valueMetrics.data(1);
5769     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
5770     EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
5771               data.slice_by_state(0).value());
5772     ASSERT_EQ(2, data.bucket_info_size());
5773     EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
5774     EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
5775 
5776     // {{uid 1, tag 16}, FOREGROUND}.
5777     data = valueMetrics.data(2);
5778     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
5779     EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
5780               data.slice_by_state(0).value());
5781     ASSERT_EQ(1, data.bucket_info_size());
5782     EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
5783 
5784     // {{uid 1, tag 14}, BACKGROUND}.
5785     data = valueMetrics.data(3);
5786     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
5787     EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
5788               data.slice_by_state(0).value());
5789     ASSERT_EQ(2, data.bucket_info_size());
5790     EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
5791     EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
5792 
5793     // {{uid 2, tag 8}, FOREGROUND}.
5794     data = valueMetrics.data(4);
5795     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
5796     EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
5797               data.slice_by_state(0).value());
5798     ASSERT_EQ(1, data.bucket_info_size());
5799     EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
5800 
5801     // {{uid 2, tag 8}, BACKGROUND}.
5802     data = valueMetrics.data(5);
5803     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
5804     EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
5805               data.slice_by_state(0).value());
5806     ASSERT_EQ(2, data.bucket_info_size());
5807     EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
5808     EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
5809 }
5810 
TEST(NumericValueMetricProducerTest,TestSlicedStateWithCondition)5811 TEST(NumericValueMetricProducerTest, TestSlicedStateWithCondition) {
5812     // Set up NumericValueMetricProducer.
5813     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithConditionAndState(
5814             "BATTERY_SAVER_MODE_STATE");
5815     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
5816     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
5817             // Condition changed to true.
5818             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5819                                 vector<std::shared_ptr<LogEvent>>* data) {
5820                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
5821                 data->clear();
5822                 data->push_back(
5823                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 3));
5824                 return true;
5825             }))
5826             // Battery saver mode state changed to OFF.
5827             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5828                                 vector<std::shared_ptr<LogEvent>>* data) {
5829                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
5830                 data->clear();
5831                 data->push_back(
5832                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5));
5833                 return true;
5834             }))
5835             // Condition changed to false.
5836             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
5837                                 vector<std::shared_ptr<LogEvent>>* data) {
5838                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC);
5839                 data->clear();
5840                 data->push_back(CreateRepeatedValueLogEvent(
5841                         tagId, bucket2StartTimeNs + 10 * NS_PER_SEC, 15));
5842                 return true;
5843             }));
5844 
5845     StateManager::getInstance().clear();
5846     sp<NumericValueMetricProducer> valueProducer =
5847             NumericValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
5848                     pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {},
5849                     ConditionState::kFalse);
5850     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
5851 
5852     // Set up StateManager and check that StateTrackers are initialized.
5853     StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
5854                                                  valueProducer);
5855     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
5856     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
5857                          util::BATTERY_SAVER_MODE_STATE_CHANGED));
5858 
5859     // Bucket status after battery saver mode ON event.
5860     // Condition is false so we do nothing.
5861     unique_ptr<LogEvent> batterySaverOnEvent =
5862             CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
5863     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
5864     EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
5865     EXPECT_EQ(0UL, valueProducer->mDimInfos.size());
5866 
5867     // Bucket status after condition change to true.
5868     valueProducer->onConditionChanged(true, bucketStartTimeNs + 20 * NS_PER_SEC);
5869     // Base for dimension key {}
5870     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5871     std::unordered_map<HashableDimensionKey,
5872                        NumericValueMetricProducer::DimensionsInWhatInfo>::iterator itBase =
5873             valueProducer->mDimInfos.find(DEFAULT_DIMENSION_KEY);
5874     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
5875     EXPECT_EQ(3, itBase->second.dimExtras[0].value().long_value);
5876     EXPECT_TRUE(itBase->second.hasCurrentState);
5877     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5878     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5879               itBase->second.currentState.getValues()[0].mValue.int_value);
5880     // Value for key {{}, ON}
5881     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
5882     std::unordered_map<MetricDimensionKey, NumericValueMetricProducer::CurrentBucket>::iterator it =
5883             valueProducer->mCurrentSlicedBucket.begin();
5884     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5885     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5886     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5887               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5888     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
5889     // Value for key {{}, -1}
5890     it++;
5891     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5892     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5893     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
5894               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5895     EXPECT_EQ(0, it->second.intervals[0].sampleSize);
5896     assertConditionTimer(it->second.conditionTimer, false, 0, 0);
5897 
5898     // Bucket status after battery saver mode OFF event.
5899     unique_ptr<LogEvent> batterySaverOffEvent =
5900             CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC);
5901     StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
5902     // Base for dimension key {}
5903     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5904     itBase = valueProducer->mDimInfos.find(DEFAULT_DIMENSION_KEY);
5905     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
5906     EXPECT_EQ(5, itBase->second.dimExtras[0].value().long_value);
5907     EXPECT_TRUE(itBase->second.hasCurrentState);
5908     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5909     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
5910               itBase->second.currentState.getValues()[0].mValue.int_value);
5911     // Value for key {{}, OFF}
5912     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
5913     it = valueProducer->mCurrentSlicedBucket.begin();
5914     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5915     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5916     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
5917               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5918     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
5919     // Value for key {{}, ON}
5920     it++;
5921     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5922     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5923     EXPECT_EQ(BatterySaverModeStateChanged::ON,
5924               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5925     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
5926     EXPECT_EQ(2, it->second.intervals[0].aggregate.long_value);
5927     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
5928                          bucketStartTimeNs + 30 * NS_PER_SEC);
5929     // Value for key {{}, -1}
5930     it++;
5931     assertConditionTimer(it->second.conditionTimer, false, 0, 0);
5932 
5933     // Pull at end of first bucket.
5934     vector<shared_ptr<LogEvent>> allData;
5935     allData.clear();
5936     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 11));
5937     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
5938 
5939     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
5940     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
5941     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5942     // Base for dimension key {}
5943     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5944     itBase = valueProducer->mDimInfos.find(DEFAULT_DIMENSION_KEY);
5945     EXPECT_TRUE(itBase->second.dimExtras[0].has_value());
5946     EXPECT_EQ(11, itBase->second.dimExtras[0].value().long_value);
5947     EXPECT_TRUE(itBase->second.hasCurrentState);
5948     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5949     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
5950               itBase->second.currentState.getValues()[0].mValue.int_value);
5951     // Value for key {{}, OFF}
5952     it = valueProducer->mCurrentSlicedBucket.begin();
5953     assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
5954 
5955     // Bucket 2 status after condition change to false.
5956     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC);
5957     // Base for dimension key {}
5958     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
5959     itBase = valueProducer->mDimInfos.find(DEFAULT_DIMENSION_KEY);
5960     EXPECT_FALSE(itBase->second.dimExtras[0].has_value());
5961     EXPECT_TRUE(itBase->second.hasCurrentState);
5962     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
5963     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
5964               itBase->second.currentState.getValues()[0].mValue.int_value);
5965     // Value for key {{}, OFF}
5966     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
5967     it = valueProducer->mCurrentSlicedBucket.begin();
5968     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
5969     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
5970     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
5971               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
5972     EXPECT_GT(it->second.intervals[0].sampleSize, 0);
5973     EXPECT_EQ(4, it->second.intervals[0].aggregate.long_value);
5974     assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
5975                          bucket2StartTimeNs + 10 * NS_PER_SEC);
5976 
5977     // Start dump report and check output.
5978     ProtoOutputStream output;
5979     std::set<string> strSet;
5980     valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
5981                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
5982                                 &strSet, &output);
5983 
5984     StatsLogReport report = outputStreamToProto(&output);
5985     EXPECT_TRUE(report.has_value_metrics());
5986     ASSERT_EQ(2, report.value_metrics().data_size());
5987 
5988     ValueMetricData data = report.value_metrics().data(0);
5989     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
5990     EXPECT_TRUE(data.slice_by_state(0).has_value());
5991     EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
5992     ASSERT_EQ(1, data.bucket_info_size());
5993     EXPECT_EQ(2, data.bucket_info(0).values(0).value_long());
5994     EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
5995 
5996     data = report.value_metrics().data(1);
5997     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
5998     EXPECT_TRUE(data.slice_by_state(0).has_value());
5999     EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value());
6000     ASSERT_EQ(2, data.bucket_info_size());
6001     EXPECT_EQ(6, data.bucket_info(0).values(0).value_long());
6002     EXPECT_EQ(4, data.bucket_info(1).values(0).value_long());
6003     EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
6004     EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
6005 }
6006 
TEST(NumericValueMetricProducerTest,TestSlicedStateWithConditionFalseMultipleBuckets)6007 TEST(NumericValueMetricProducerTest, TestSlicedStateWithConditionFalseMultipleBuckets) {
6008     // Set up NumericValueMetricProducer.
6009     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithConditionAndState(
6010             "BATTERY_SAVER_MODE_STATE");
6011     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6012     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6013             // Condition changed to true.
6014             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6015                                 vector<std::shared_ptr<LogEvent>>* data) {
6016                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
6017                 data->clear();
6018                 data->push_back(
6019                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 3));
6020                 return true;
6021             }))
6022             // Battery saver mode state changed to OFF.
6023             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6024                                 vector<std::shared_ptr<LogEvent>>* data) {
6025                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
6026                 data->clear();
6027                 data->push_back(
6028                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5));
6029                 return true;
6030             }))
6031             // Condition changed to false.
6032             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6033                                 vector<std::shared_ptr<LogEvent>>* data) {
6034                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
6035                 data->clear();
6036                 data->push_back(
6037                         CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 9));
6038                 return true;
6039             }))
6040             // Condition changed to true.
6041             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6042                                 vector<std::shared_ptr<LogEvent>>* data) {
6043                 EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 10 * NS_PER_SEC);
6044                 data->clear();
6045                 data->push_back(CreateRepeatedValueLogEvent(
6046                         tagId, bucket3StartTimeNs + 10 * NS_PER_SEC, 35));
6047                 return true;
6048             }))
6049             // Dump report pull.
6050             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6051                                 vector<std::shared_ptr<LogEvent>>* data) {
6052                 EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 30 * NS_PER_SEC);
6053                 data->clear();
6054                 data->push_back(CreateRepeatedValueLogEvent(
6055                         tagId, bucket3StartTimeNs + 30 * NS_PER_SEC, 53));
6056                 return true;
6057             }));
6058 
6059     StateManager::getInstance().clear();
6060     sp<NumericValueMetricProducer> valueProducer =
6061             NumericValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
6062                     pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {},
6063                     ConditionState::kFalse);
6064     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
6065 
6066     // Set up StateManager and check that StateTrackers are initialized.
6067     StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
6068                                                  valueProducer);
6069     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
6070     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
6071                          util::BATTERY_SAVER_MODE_STATE_CHANGED));
6072 
6073     // Bucket status after battery saver mode ON event.
6074     // Condition is false so we do nothing.
6075     unique_ptr<LogEvent> batterySaverOnEvent =
6076             CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
6077     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
6078     EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
6079     EXPECT_EQ(0UL, valueProducer->mDimInfos.size());
6080 
6081     // Bucket status after condition change to true.
6082     valueProducer->onConditionChanged(true, bucketStartTimeNs + 20 * NS_PER_SEC);
6083     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
6084     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
6085 
6086     // Bucket status after battery saver mode OFF event.
6087     unique_ptr<LogEvent> batterySaverOffEvent =
6088             CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC);
6089     StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
6090     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
6091     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
6092 
6093     // Bucket status after condition change to false.
6094     valueProducer->onConditionChanged(false, bucketStartTimeNs + 40 * NS_PER_SEC);
6095     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
6096     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
6097 
6098     // Pull at end of first bucket.
6099     vector<shared_ptr<LogEvent>> allData;
6100     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 11));
6101     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
6102     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
6103     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
6104     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
6105 
6106     // Battery saver mode ON event. Nothing change since the condition is false.
6107     batterySaverOnEvent =
6108             CreateBatterySaverOnEvent(/*timestamp=*/bucket2StartTimeNs + 30 * NS_PER_SEC);
6109     StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
6110 
6111     // Pull at end of second bucket. Since no new data is seen, mDimInfos will be cleared.
6112     allData.clear();
6113     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 15));
6114     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
6115     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
6116     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
6117     ASSERT_EQ(0UL, valueProducer->mDimInfos.size());
6118 
6119     // Bucket2 status after condition change to true.
6120     valueProducer->onConditionChanged(true, bucket3StartTimeNs + 10 * NS_PER_SEC);
6121     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
6122     // This currently keys into the old state key, which is unknown since mDimInfos was cleared.
6123     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
6124 
6125     // Start dump report and check output.
6126     ProtoOutputStream output;
6127     std::set<string> strSet;
6128     valueProducer->onDumpReport(bucket3StartTimeNs + 30 * NS_PER_SEC,
6129                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
6130                                 &strSet, &output);
6131 
6132     StatsLogReport report = outputStreamToProto(&output);
6133     backfillDimensionPath(&report);
6134     backfillStartEndTimestamp(&report);
6135     EXPECT_TRUE(report.has_value_metrics());
6136     ASSERT_EQ(2, report.value_metrics().data_size());
6137 
6138     ValueMetricData data = report.value_metrics().data(0);
6139     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
6140     EXPECT_TRUE(data.slice_by_state(0).has_value());
6141     EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
6142     ASSERT_EQ(2, data.bucket_info_size());
6143     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {2},
6144                         10 * NS_PER_SEC, -1);
6145     ValidateValueBucket(data.bucket_info(1), bucket3StartTimeNs,
6146                         bucket3StartTimeNs + 30 * NS_PER_SEC, {18}, 20 * NS_PER_SEC, -1);
6147 
6148     data = report.value_metrics().data(1);
6149     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
6150     EXPECT_TRUE(data.slice_by_state(0).has_value());
6151     EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value());
6152     ASSERT_EQ(1, data.bucket_info_size());
6153     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {4},
6154                         10 * NS_PER_SEC, -1);
6155 }
6156 
6157 /*
6158  * Test slicing by state for metric that slices by state with a primary field,
6159  * has multiple dimensions, and a pull that returns incomplete data.
6160  */
TEST(NumericValueMetricProducerTest,TestSlicedStateWithMultipleDimensionsMissingDataInPull)6161 TEST(NumericValueMetricProducerTest, TestSlicedStateWithMultipleDimensionsMissingDataInPull) {
6162     // Set up NumericValueMetricProducer.
6163     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithConditionAndState(
6164             "UID_PROCESS_STATE");
6165     metric.mutable_dimensions_in_what()->set_field(tagId);
6166     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
6167     metric.mutable_dimensions_in_what()->add_child()->set_field(3);
6168 
6169     MetricStateLink* stateLink = metric.add_state_link();
6170     stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
6171     auto fieldsInWhat = stateLink->mutable_fields_in_what();
6172     *fieldsInWhat = CreateDimensions(tagId, {1 /* uid */});
6173     auto fieldsInState = stateLink->mutable_fields_in_state();
6174     *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
6175     /*
6176                     bucket # 1                            bucket # 2
6177     10     20     30     40     50     60     70     80     90    100    110    120 (seconds)
6178     |------------------------------------------|---------------------------------|--
6179                                                                                     (kUnknown)
6180     x                                                                               {1, 14}
6181     |-------------|
6182           20
6183     x             -                                                                 {1, 16}
6184     |-------------|
6185           20
6186     x                                                                               {2, 8}
6187     |-----------------|
6188             25
6189                                                                                     {FOREGROUND}
6190                                                                    x                {2, 8}
6191                                                                    |-------------|
6192                                                                          20
6193                                                                                     (BACKGROUND)
6194                   x                                                                 {1, 14}
6195                   |----------------------------|---------------------------------|
6196                                40                              50
6197                   -                                                                 {1, 16}
6198                                                |---------------------------------|
6199                                                                50
6200                      x                         -                                    {2, 8}
6201                      |-------------------------|
6202                                 45
6203     */
6204     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6205     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6206             // Initial Pull
6207             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6208                                 vector<std::shared_ptr<LogEvent>>* data) {
6209                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
6210                 data->clear();
6211                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, 1 /*uid*/, 1,
6212                                                          14 /*tag*/));
6213                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, 1 /*uid*/, 1,
6214                                                          16 /*tag*/));
6215                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, 2 /*uid*/, 1,
6216                                                          8 /*tag*/));
6217                 return true;
6218             }))
6219             // Uid 1 process state change from kStateUnknown -> Background. Tag 16 is missing.
6220             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6221                                 vector<std::shared_ptr<LogEvent>>* data) {
6222                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
6223                 data->clear();
6224                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
6225                                                          1 /*uid*/, 5, 14 /*tag*/));
6226                 // This event should be skipped.
6227                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
6228                                                          2 /*uid*/, 7, 8 /*tag*/));
6229                 return true;
6230             }))
6231             // Uid 2 process state change from kStateUnknown -> Background
6232             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6233                                 vector<std::shared_ptr<LogEvent>>* data) {
6234                 EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 25 * NS_PER_SEC);
6235                 data->clear();
6236                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
6237                                                          2 /*uid*/, 8, 8 /*tag*/));
6238                 // This event should be skipped.
6239                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
6240                                                          1 /*uid*/, 8, 14 /* tag */));
6241                 // This event should be skipped.
6242                 data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
6243                                                          1 /*uid*/, 8, 16 /* tag */));
6244                 return true;
6245             }))
6246             // Uid 2 process state change from Background -> Foreground
6247             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6248                                 vector<std::shared_ptr<LogEvent>>* data) {
6249                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
6250                 data->clear();
6251                 data->push_back(CreateThreeValueLogEvent(
6252                         tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /*uid*/, 18, 8 /*tag*/));
6253                 // This event should be skipped.
6254                 data->push_back(CreateThreeValueLogEvent(
6255                         tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 14 /* tag */));
6256                 // This event should be skipped.
6257                 data->push_back(CreateThreeValueLogEvent(
6258                         tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 16 /* tag */));
6259                 return true;
6260             }))
6261             // Dump report pull.
6262             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6263                                 vector<std::shared_ptr<LogEvent>>* data) {
6264                 EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
6265                 data->clear();
6266                 data->push_back(CreateThreeValueLogEvent(
6267                         tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 22, 14 /* tag */));
6268                 data->push_back(CreateThreeValueLogEvent(
6269                         tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 22, 16 /* tag */));
6270                 data->push_back(CreateThreeValueLogEvent(
6271                         tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 2 /*uid*/, 22, 8 /*tag*/));
6272                 return true;
6273             }));
6274 
6275     StateManager::getInstance().clear();
6276     sp<NumericValueMetricProducer> valueProducer =
6277             NumericValueMetricProducerTestHelper::createValueProducerWithState(
6278                     pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {});
6279     EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
6280 
6281     // Set up StateManager and check that StateTrackers are initialized.
6282     StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
6283     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
6284     EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
6285 
6286     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
6287     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
6288 
6289     // Tag 16 is missing and gets trimmed from mDimInfos
6290     auto uidProcessEvent =
6291             CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
6292                                               android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
6293     StateManager::getInstance().onLogEvent(*uidProcessEvent);
6294     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
6295     ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
6296 
6297     uidProcessEvent =
6298             CreateUidProcessStateChangedEvent(bucketStartTimeNs + 25 * NS_PER_SEC, 2 /* uid */,
6299                                               android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
6300     StateManager::getInstance().onLogEvent(*uidProcessEvent);
6301     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
6302     ASSERT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
6303 
6304     // Pull at end of first bucket. Uid 2 is missing and gets trimmed from mDimInfos
6305     vector<shared_ptr<LogEvent>> allData;
6306     allData.push_back(
6307             CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 14 /* tag */));
6308     allData.push_back(
6309             CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 16 /* tag */));
6310     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs + 1);
6311 
6312     // Buckets flushed. MetricDimensionKeys not corresponding to the current state are removed.
6313     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
6314     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
6315     // {1, 16, kUnknown}, {2, 8, BACKGROUND} aren't present since the pulls were missing the dims.
6316     ASSERT_EQ(3UL, valueProducer->mPastBuckets.size());
6317 
6318     uidProcessEvent =
6319             CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /* uid */,
6320                                               android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
6321     StateManager::getInstance().onLogEvent(*uidProcessEvent);
6322     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
6323     ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
6324 
6325     // Start dump report and check output.
6326     ProtoOutputStream output;
6327     std::set<string> strSet;
6328     valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
6329                                 true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
6330                                 &strSet, &output);
6331     ASSERT_EQ(3UL, valueProducer->mDimInfos.size());
6332     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
6333 
6334     StatsLogReport report = outputStreamToProto(&output);
6335     backfillDimensionPath(&report);
6336     backfillStartEndTimestamp(&report);
6337     EXPECT_TRUE(report.has_value_metrics());
6338     StatsLogReport::ValueMetricDataWrapper valueMetrics;
6339     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
6340 
6341     // {1, 16, kUnknown}, {2, 8, BACKGROUND} aren't present since the pulls were missing the dims.
6342     ASSERT_EQ(5, valueMetrics.data_size());
6343     ASSERT_EQ(0, report.value_metrics().skipped_size());
6344 
6345     // {{uid 1, tag 14}, kStateUnknown}.
6346     ValueMetricData data = valueMetrics.data(0);
6347     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
6348                        -1 /*StateTracker::kStateUnknown*/);
6349     EXPECT_EQ(data.dimensions_in_what().field(), tagId);
6350     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
6351     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
6352     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 1);
6353     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 3);
6354     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(), 14);
6355     ASSERT_EQ(1, data.bucket_info_size());
6356     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {4},
6357                         20 * NS_PER_SEC, -1);
6358 
6359     // {{uid 1, tag 14}, BACKGROUND}.
6360     data = valueMetrics.data(1);
6361     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
6362                        android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND);
6363     EXPECT_EQ(data.dimensions_in_what().field(), tagId);
6364     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
6365     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
6366     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 1);
6367     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 3);
6368     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(), 14);
6369     ASSERT_EQ(2, data.bucket_info_size());
6370     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {8},
6371                         40 * NS_PER_SEC, -1);
6372     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs,
6373                         bucket2StartTimeNs + 50 * NS_PER_SEC, {9}, 50 * NS_PER_SEC, -1);
6374 
6375     // {{uid 1, tag 16}, BACKGROUND}.
6376     data = valueMetrics.data(2);
6377     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
6378                        android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND);
6379     EXPECT_EQ(data.dimensions_in_what().field(), tagId);
6380     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
6381     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
6382     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 1);
6383     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 3);
6384     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(), 16);
6385     ASSERT_EQ(1, data.bucket_info_size());
6386     ValidateValueBucket(data.bucket_info(0), bucket2StartTimeNs,
6387                         bucket2StartTimeNs + 50 * NS_PER_SEC, {9}, 50 * NS_PER_SEC, -1);
6388 
6389     // {{uid 2, tag 8}, kStateUnknown}.
6390     data = valueMetrics.data(3);
6391     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
6392                        -1 /*StateTracker::kStateUnknown*/);
6393     EXPECT_EQ(data.dimensions_in_what().field(), tagId);
6394     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
6395     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
6396     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 2);
6397     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 3);
6398     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(), 8);
6399     ASSERT_EQ(1, data.bucket_info_size());
6400     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {7},
6401                         25 * NS_PER_SEC, -1);
6402 
6403     // {{uid 2, tag 8}, FOREGROUND}.
6404     data = valueMetrics.data(4);
6405     ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
6406                        android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);
6407     EXPECT_EQ(data.dimensions_in_what().field(), tagId);
6408     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
6409     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
6410     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 2);
6411     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 3);
6412     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(), 8);
6413     ASSERT_EQ(1, data.bucket_info_size());
6414     ValidateValueBucket(data.bucket_info(0), bucket2StartTimeNs,
6415                         bucket2StartTimeNs + 50 * NS_PER_SEC, {4}, 20 * NS_PER_SEC, -1);
6416 }
6417 
6418 /*
6419  * Test bucket splits when condition is unknown.
6420  */
TEST(NumericValueMetricProducerTest,TestForcedBucketSplitWhenConditionUnknownSkipsBucket)6421 TEST(NumericValueMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket) {
6422     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
6423 
6424     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6425 
6426     sp<NumericValueMetricProducer> valueProducer =
6427             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
6428                     pullerManager, metric, ConditionState::kUnknown);
6429 
6430     // App update event.
6431     int64_t appUpdateTimeNs = bucketStartTimeNs + 1000;
6432     valueProducer->notifyAppUpgrade(appUpdateTimeNs);
6433 
6434     // Check dump report.
6435     ProtoOutputStream output;
6436     std::set<string> strSet;
6437     int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000;  // 10 seconds
6438     valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true,
6439                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
6440 
6441     StatsLogReport report = outputStreamToProto(&output);
6442     EXPECT_TRUE(report.has_value_metrics());
6443     ASSERT_EQ(0, report.value_metrics().data_size());
6444     ASSERT_EQ(1, report.value_metrics().skipped_size());
6445 
6446     EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
6447               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
6448     EXPECT_EQ(NanoToMillis(appUpdateTimeNs),
6449               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
6450     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
6451 
6452     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
6453     EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
6454     EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
6455 }
6456 
TEST(NumericValueMetricProducerTest,TestUploadThreshold)6457 TEST(NumericValueMetricProducerTest, TestUploadThreshold) {
6458     // Create metric with upload threshold and two value fields.
6459     int64_t thresholdValue = 15;
6460     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
6461     metric.mutable_value_field()->add_child()->set_field(3);
6462     metric.mutable_threshold()->set_gt_int(thresholdValue);
6463     *metric.mutable_dimensions_in_what() = CreateDimensions(tagId, {1 /*uid*/});
6464 
6465     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6466 
6467     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6468             // First bucket pull.
6469             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6470                                 vector<std::shared_ptr<LogEvent>>* data) {
6471                 data->clear();
6472                 data->push_back(
6473                         CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 1, 1 /*uid*/, 5, 5));
6474                 data->push_back(
6475                         CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 1, 2 /*uid*/, 5, 5));
6476                 return true;
6477             }))
6478             // Dump report.
6479             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6480                                 vector<std::shared_ptr<LogEvent>>* data) {
6481                 data->clear();
6482                 data->push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 10000000000,
6483                                                          1 /*uid*/, 22, 21));
6484                 data->push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 10000000000,
6485                                                          2 /*uid*/, 30, 10));
6486                 return true;
6487             }));
6488 
6489     sp<NumericValueMetricProducer> valueProducer =
6490             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
6491                                                                                   metric);
6492 
6493     // Bucket 2 start.
6494     vector<shared_ptr<LogEvent>> allData;
6495     allData.clear();
6496     allData.push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 1, 1 /*uid*/, 21, 21));
6497     allData.push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 1, 2 /*uid*/, 20, 5));
6498     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
6499 
6500     // Check dump report.
6501     ProtoOutputStream output;
6502     std::set<string> strSet;
6503     int64_t dumpReportTimeNs = bucket2StartTimeNs + 10000000000;
6504     valueProducer->onDumpReport(dumpReportTimeNs, true /* include current buckets */, true,
6505                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
6506 
6507     StatsLogReport report = outputStreamToProto(&output);
6508     backfillDimensionPath(&report);
6509     backfillStartEndTimestamp(&report);
6510     EXPECT_TRUE(report.has_value_metrics());
6511     StatsLogReport::ValueMetricDataWrapper valueMetrics;
6512     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
6513     ASSERT_EQ(1, valueMetrics.data_size());
6514     ASSERT_EQ(1, report.value_metrics().skipped_size());
6515 
6516     // Check data keyed to uid 1.
6517     ValueMetricData data = valueMetrics.data(0);
6518     ValidateUidDimension(data.dimensions_in_what(), tagId, 1);
6519     ASSERT_EQ(1, data.bucket_info_size());
6520     // First bucket.
6521     // Values pass threshold.
6522     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {16, 16}, -1,
6523                         0);
6524     // Second bucket is dropped because values do not pass threshold.
6525 
6526     // Check data keyed to uid 2.
6527     // First bucket and second bucket are dropped because values do not pass threshold.
6528 
6529     // Check that second bucket has NO_DATA drop reason.
6530     EXPECT_EQ(bucket2StartTimeNs, report.value_metrics().skipped(0).start_bucket_elapsed_nanos());
6531     EXPECT_EQ(dumpReportTimeNs, report.value_metrics().skipped(0).end_bucket_elapsed_nanos());
6532     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
6533     EXPECT_EQ(BucketDropReason::NO_DATA,
6534               report.value_metrics().skipped(0).drop_event(0).drop_reason());
6535 }
6536 
6537 /**
6538  * Tests pulled atoms with conditions and delayed pull on the bucket boundary in respect to
6539  * late alarm and condition is true during the pull
6540  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestAlarmLatePullWhileConditionTrue)6541 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestAlarmLatePullWhileConditionTrue) {
6542     const int64_t pullDelayNs = 1 * NS_PER_SEC;  // 1 sec
6543 
6544     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
6545 
6546     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6547     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6548             // Pull on the initial onConditionChanged
6549             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6550                                 vector<std::shared_ptr<LogEvent>>* data) {
6551                 data->clear();
6552                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
6553                 return true;
6554             }));
6555 
6556     sp<NumericValueMetricProducer> valueProducer =
6557             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
6558                     pullerManager, metric, ConditionState::kFalse);
6559 
6560     valueProducer->onConditionChanged(true, bucketStartTimeNs);
6561 
6562     vector<shared_ptr<LogEvent>> allData;
6563 
6564     // first delayed pull on the bucket #1 edge
6565     allData.clear();
6566     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + pullDelayNs, 10));
6567     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
6568                                 bucket2StartTimeNs + pullDelayNs);
6569 
6570     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
6571     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
6572                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
6573 
6574     // second pull on the bucket #2 boundary on time
6575     allData.clear();
6576     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 15));
6577     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
6578 
6579     // the second pull did close the second bucket with condition duration == bucketSizeNs
6580     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5, 5},
6581                                     {bucketSizeNs, bucketSizeNs}, {pullDelayNs, -pullDelayNs},
6582                                     {bucketStartTimeNs, bucket2StartTimeNs},
6583                                     {bucket2StartTimeNs, bucket3StartTimeNs});
6584 }
6585 
6586 /**
6587  * Tests pulled atoms with conditions and delayed pull on the bucket boundary in respect to
6588  * late alarm and condition is false during the pull
6589  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestAlarmLatePullWhileConditionFalse)6590 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestAlarmLatePullWhileConditionFalse) {
6591     const int64_t delayNs = NS_PER_SEC;              // 1 sec
6592     const int64_t conditionDurationNs = NS_PER_SEC;  // 1 sec
6593 
6594     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
6595 
6596     int increasedValue = 5;
6597     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6598     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6599             .Times(4)
6600             .WillRepeatedly(Invoke([&increasedValue](int tagId, const ConfigKey&,
6601                                                      const int64_t eventTimeNs,
6602                                                      vector<std::shared_ptr<LogEvent>>* data) {
6603                 data->clear();
6604                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, increasedValue));
6605                 increasedValue += 5;
6606                 return true;
6607             }));
6608 
6609     sp<NumericValueMetricProducer> valueProducer =
6610             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
6611                     pullerManager, metric, ConditionState::kFalse);
6612 
6613     valueProducer->onConditionChanged(true, bucketStartTimeNs);
6614     valueProducer->onConditionChanged(false, bucketStartTimeNs + conditionDurationNs);
6615 
6616     vector<shared_ptr<LogEvent>> allData;
6617     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + delayNs, 10));
6618     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
6619                                 bucket2StartTimeNs + delayNs);
6620 
6621     // first delayed pull on the bucket #1 edge
6622     // the delayed pull did close the first bucket with condition duration == conditionDurationNs
6623     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {conditionDurationNs}, {0},
6624                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
6625 
6626     valueProducer->onConditionChanged(true, bucket2StartTimeNs + 2 * delayNs);
6627 
6628     valueProducer->onConditionChanged(false,
6629                                       bucket2StartTimeNs + 2 * delayNs + conditionDurationNs);
6630 
6631     allData.clear();
6632     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 10));
6633     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
6634 
6635     // second pull on the bucket #2 edge is on time
6636     assertPastBucketValuesSingleKey(
6637             valueProducer->mPastBuckets, {5, 5}, {conditionDurationNs, conditionDurationNs}, {0, 0},
6638             {bucketStartTimeNs, bucket2StartTimeNs}, {bucket2StartTimeNs, bucket3StartTimeNs});
6639 }
6640 
6641 /**
6642  * Tests pulled atoms with conditions and delayed pull on the bucket boundary in respect to
6643  * onConditionChanged true to false
6644  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestLatePullOnConditionChangeFalse)6645 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestLatePullOnConditionChangeFalse) {
6646     const int64_t pullDelayNs = 1 * NS_PER_SEC;          // 1 sec
6647     const int64_t arbitraryIntervalNs = 5 * NS_PER_SEC;  // 5 sec interval
6648     const int64_t conditionDurationNs = 1 * NS_PER_SEC;  // 1 sec
6649 
6650     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
6651 
6652     int increasedValue = 5;
6653     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6654     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6655             .Times(4)
6656             .WillRepeatedly(Invoke([&increasedValue](int tagId, const ConfigKey&,
6657                                                      const int64_t eventTimeNs,
6658                                                      vector<std::shared_ptr<LogEvent>>* data) {
6659                 data->clear();
6660                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, increasedValue));
6661                 increasedValue += 5;
6662                 return true;
6663             }));
6664 
6665     sp<NumericValueMetricProducer> valueProducer =
6666             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
6667                     pullerManager, metric, ConditionState::kFalse);
6668 
6669     valueProducer->onConditionChanged(true, bucketStartTimeNs);
6670 
6671     // will force delayed pull & bucket close
6672     valueProducer->onConditionChanged(false, bucket2StartTimeNs + pullDelayNs);
6673 
6674     // first delayed pull on the bucket #1 edge
6675     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
6676     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
6677                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
6678 
6679     // here arbitraryIntervalNs just an arbitrary interval after the delayed pull &
6680     // before the sequence of condition change events
6681     valueProducer->onConditionChanged(true, bucket2StartTimeNs + pullDelayNs + arbitraryIntervalNs);
6682 
6683     valueProducer->onConditionChanged(
6684             false, bucket2StartTimeNs + pullDelayNs + arbitraryIntervalNs + conditionDurationNs);
6685 
6686     vector<shared_ptr<LogEvent>> allData;
6687     allData.clear();
6688     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 30));
6689     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
6690 
6691     // second pull on the bucket #2 edge is on time
6692     // the pull did close the second bucket with condition where
6693     // duration == conditionDurationNs + carryover from first bucket due to delayed pull
6694     assertPastBucketValuesSingleKey(
6695             valueProducer->mPastBuckets, {5, 5}, {bucketSizeNs, pullDelayNs + conditionDurationNs},
6696             {pullDelayNs, -pullDelayNs}, {bucketStartTimeNs, bucket2StartTimeNs},
6697             {bucket2StartTimeNs, bucket3StartTimeNs});
6698 }
6699 
6700 /**
6701  * Tests pulled atoms with conditions and delayed pull on the bucket boundary in respect to
6702  * onConditionChanged false to true
6703  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestLatePullOnConditionChangeTrue)6704 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestLatePullOnConditionChangeTrue) {
6705     const int64_t pullDelayNs = 1 * NS_PER_SEC;                 // 1 sec
6706     const int64_t conditionSwitchIntervalNs = 10 * NS_PER_SEC;  // 10 sec
6707     const int64_t conditionDurationNs = 1 * NS_PER_SEC;         // 1 sec
6708 
6709     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
6710 
6711     int increasedValue = 5;
6712     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6713     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6714             .Times(5)
6715             .WillRepeatedly(Invoke([&increasedValue](int tagId, const ConfigKey&,
6716                                                      const int64_t eventTimeNs,
6717                                                      vector<std::shared_ptr<LogEvent>>* data) {
6718                 data->clear();
6719                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, increasedValue));
6720                 increasedValue += 5;
6721                 return true;
6722             }));
6723 
6724     sp<NumericValueMetricProducer> valueProducer =
6725             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
6726                     pullerManager, metric, ConditionState::kFalse);
6727 
6728     valueProducer->onConditionChanged(true, bucketStartTimeNs);
6729 
6730     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
6731 
6732     valueProducer->onConditionChanged(false, bucketStartTimeNs + conditionDurationNs);
6733 
6734     // will force delayed pull & bucket close
6735     valueProducer->onConditionChanged(true, bucket2StartTimeNs + pullDelayNs);
6736 
6737     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
6738     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {conditionDurationNs}, {0},
6739                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
6740 
6741     valueProducer->onConditionChanged(false,
6742                                       bucket2StartTimeNs + pullDelayNs + conditionDurationNs);
6743 
6744     // will force delayed pull & bucket close
6745     valueProducer->onConditionChanged(true, bucket3StartTimeNs + pullDelayNs);
6746 
6747     // the delayed pull did close the second bucket with condition duration == conditionDurationNs
6748     assertPastBucketValuesSingleKey(
6749             valueProducer->mPastBuckets, {5, 5}, {conditionDurationNs, conditionDurationNs}, {0, 0},
6750             {bucketStartTimeNs, bucket2StartTimeNs}, {bucket2StartTimeNs, bucket3StartTimeNs});
6751 }
6752 
6753 /**
6754  * Tests pulled atoms with conditions and delayed pull on the bucket boundary in respect to
6755  * late alarms. Condition is true during the pull
6756  * With a following events in the middle of the bucket
6757  * 1) onConditionChanged true to false
6758  * 2) onConditionChanged false to true
6759  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestAlarmLatePullWithConditionChanged)6760 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestAlarmLatePullWithConditionChanged) {
6761     const int64_t pullDelayNs = 1 * NS_PER_SEC;                             // 1 sec
6762     const int64_t conditionSwitchIntervalNs = 10 * NS_PER_SEC;              // 10 sec
6763     const int64_t bucket2DelayNs = 5 * NS_PER_SEC;                          // 1 sec
6764     const int64_t bucket1LatePullNs = bucket2StartTimeNs + pullDelayNs;     // 71 sec
6765     const int64_t bucket2LatePullNs = bucket3StartTimeNs + bucket2DelayNs;  // 145 sec
6766 
6767     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
6768 
6769     int increasedValue = 5;
6770     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6771     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6772             .Times(5)
6773             .WillRepeatedly(Invoke([&increasedValue](int tagId, const ConfigKey&,
6774                                                      const int64_t eventTimeNs,
6775                                                      vector<std::shared_ptr<LogEvent>>* data) {
6776                 data->clear();
6777                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, increasedValue));
6778                 increasedValue += 5;
6779                 return true;
6780             }));
6781 
6782     sp<NumericValueMetricProducer> valueProducer =
6783             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
6784                     pullerManager, metric, ConditionState::kFalse);
6785 
6786     valueProducer->onConditionChanged(true, bucketStartTimeNs);
6787 
6788     // will force delayed pull & bucket #1 close
6789     vector<shared_ptr<LogEvent>> allData;
6790     allData.clear();
6791     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket1LatePullNs, 10));
6792     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket1LatePullNs);
6793 
6794     // first delayed pull on the bucket #1 edge
6795     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
6796     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
6797                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
6798 
6799     valueProducer->onConditionChanged(false, bucket1LatePullNs + conditionSwitchIntervalNs);
6800 
6801     valueProducer->onConditionChanged(true, bucket1LatePullNs + 2 * conditionSwitchIntervalNs);
6802 
6803     // will force delayed pull & bucket #2 close
6804     allData.clear();
6805     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2LatePullNs, 25));
6806     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2LatePullNs);
6807 
6808     // second delayed pull on the bucket #2 edge
6809     // the pull did close the second bucket with condition true
6810     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5, 10},
6811                                     {bucketSizeNs, bucketSizeNs - conditionSwitchIntervalNs},
6812                                     {pullDelayNs, -pullDelayNs + bucket2DelayNs},
6813                                     {bucketStartTimeNs, bucket2StartTimeNs},
6814                                     {bucket2StartTimeNs, bucket3StartTimeNs});
6815 
6816     valueProducer->onConditionChanged(false, bucket2LatePullNs + conditionSwitchIntervalNs);
6817 
6818     valueProducer->onConditionChanged(true, bucket2LatePullNs + 3 * conditionSwitchIntervalNs);
6819 
6820     // will force pull on time & bucket #3 close
6821     allData.clear();
6822     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs, 40));
6823     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
6824 
6825     // the pull did close the third bucket with condition true
6826     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5, 10, 15},
6827                                     {bucketSizeNs, bucketSizeNs - conditionSwitchIntervalNs,
6828                                      bucketSizeNs - 2 * conditionSwitchIntervalNs},
6829                                     {pullDelayNs, -pullDelayNs + bucket2DelayNs, -bucket2DelayNs},
6830                                     {bucketStartTimeNs, bucket2StartTimeNs, bucket3StartTimeNs},
6831                                     {bucket2StartTimeNs, bucket3StartTimeNs, bucket4StartTimeNs});
6832 }
6833 
6834 /**
6835  * Tests pulled atoms with no conditions and delayed pull on the bucket boundary
6836  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestAlarmLatePullNoCondition)6837 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestAlarmLatePullNoCondition) {
6838     const int64_t pullDelayNs = 1 * NS_PER_SEC;  // 1 sec
6839 
6840     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
6841 
6842     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6843     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6844             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6845                                 vector<std::shared_ptr<LogEvent>>* data) {
6846                 data->clear();
6847                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
6848                 return true;
6849             }));
6850 
6851     sp<NumericValueMetricProducer> valueProducer =
6852             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
6853                                                                                   metric);
6854 
6855     vector<shared_ptr<LogEvent>> allData;
6856 
6857     // first delayed pull on the bucket #1 edge
6858     allData.clear();
6859     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + pullDelayNs, 10));
6860     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
6861                                 bucket2StartTimeNs + pullDelayNs);
6862 
6863     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
6864     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
6865                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
6866 
6867     // second pull on the bucket #2 boundary on time
6868     allData.clear();
6869     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 15));
6870     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
6871 
6872     // the second pull did close the second bucket with condition duration == bucketSizeNs
6873     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5, 5},
6874                                     {bucketSizeNs, bucketSizeNs}, {pullDelayNs, -pullDelayNs},
6875                                     {bucketStartTimeNs, bucket2StartTimeNs},
6876                                     {bucket2StartTimeNs, bucket3StartTimeNs});
6877 
6878     // third pull on the bucket #3 boundary on time
6879     allData.clear();
6880     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs, 20));
6881     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
6882 
6883     // the third pull did close the third bucket with condition duration == bucketSizeNs
6884     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5, 5, 5},
6885                                     {bucketSizeNs, bucketSizeNs, bucketSizeNs},
6886                                     {pullDelayNs, -pullDelayNs, 0},
6887                                     {bucketStartTimeNs, bucket2StartTimeNs, bucket3StartTimeNs},
6888                                     {bucket2StartTimeNs, bucket3StartTimeNs, bucket4StartTimeNs});
6889 }
6890 
6891 /**
6892  * Tests pulled atoms with no conditions and delayed pull on the bucket boundary
6893  * The skipped bucket is introduced prior delayed pull
6894  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestAlarmLatePullNoConditionWithSkipped)6895 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestAlarmLatePullNoConditionWithSkipped) {
6896     const int64_t pullDelayNs = 1 * NS_PER_SEC;  // 1 sec
6897 
6898     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
6899 
6900     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6901     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
6902             .WillOnce(Return(true));
6903 
6904     sp<NumericValueMetricProducer> valueProducer =
6905             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
6906                                                                                   metric);
6907 
6908     vector<shared_ptr<LogEvent>> allData;
6909 
6910     // first delayed pull on the bucket #1 edge with delay
6911     allData.clear();
6912     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + pullDelayNs, 10));
6913     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
6914                                 bucket2StartTimeNs + pullDelayNs);
6915 
6916     // the delayed pull did close the first bucket which is skipped
6917     // skipped due to bucket does not contains any value
6918     ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
6919     ASSERT_EQ(1UL, valueProducer->mSkippedBuckets.size());
6920 
6921     // second pull on the bucket #2 boundary on time
6922     allData.clear();
6923     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 15));
6924     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
6925 
6926     // the second pull did close the second bucket with condition duration == bucketSizeNs
6927     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs},
6928                                     {-pullDelayNs}, {bucket2StartTimeNs}, {bucket3StartTimeNs});
6929 
6930     // third pull on the bucket #3 boundary on time
6931     allData.clear();
6932     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs, 20));
6933     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket4StartTimeNs);
6934 
6935     // the third pull did close the third bucket with condition duration == bucketSizeNs
6936     assertPastBucketValuesSingleKey(
6937             valueProducer->mPastBuckets, {5, 5}, {bucketSizeNs, bucketSizeNs}, {-pullDelayNs, 0},
6938             {bucket2StartTimeNs, bucket3StartTimeNs}, {bucket3StartTimeNs, bucket4StartTimeNs});
6939 }
6940 
6941 /**
6942  * Tests pulled atoms with no conditions and delayed pull on the bucket boundary
6943  * The threshold is not defined - correction upload should be skipped
6944  * Metric population scenario mimics the
6945  * NumericValueMetricProducerTest_ConditionCorrection.TestAlarmLatePullNoCondition test
6946  * to extent of a single bucket with correction value due to pull delay
6947  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestThresholdNotDefinedNoUpload)6948 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestThresholdNotDefinedNoUpload) {
6949     const int64_t pullDelayNs = 1 * NS_PER_SEC;  // 1 sec
6950 
6951     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
6952     ASSERT_FALSE(metric.has_condition_correction_threshold_nanos());
6953 
6954     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
6955     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
6956             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
6957                                 vector<std::shared_ptr<LogEvent>>* data) {
6958                 data->clear();
6959                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
6960                 return true;
6961             }));
6962 
6963     sp<NumericValueMetricProducer> valueProducer =
6964             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
6965                                                                                   metric);
6966 
6967     ASSERT_FALSE(valueProducer->mConditionCorrectionThresholdNs.has_value());
6968 
6969     vector<shared_ptr<LogEvent>> allData;
6970 
6971     // first delayed pull on the bucket #1 edge
6972     allData.clear();
6973     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + pullDelayNs, 10));
6974     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
6975                                 bucket2StartTimeNs + pullDelayNs);
6976 
6977     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
6978     // and the condition correction == pull delay
6979     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
6980                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
6981 
6982     // generate dump report and validate correction value in the reported buckets
6983     ProtoOutputStream output;
6984     std::set<string> strSet;
6985     valueProducer->onDumpReport(bucket3StartTimeNs, false /* include partial bucket */, true,
6986                                 FAST /* dumpLatency */, &strSet, &output);
6987 
6988     StatsLogReport report = outputStreamToProto(&output);
6989 
6990     EXPECT_TRUE(report.has_value_metrics());
6991     ASSERT_EQ(1, report.value_metrics().data_size());
6992     ASSERT_EQ(0, report.value_metrics().skipped_size());
6993     ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
6994     EXPECT_FALSE(report.value_metrics().data(0).bucket_info(0).has_condition_correction_nanos());
6995 }
6996 
6997 /**
6998  * Tests pulled atoms with no conditions and delayed pull on the bucket boundary
6999  * The threshold set to zero - correction should be performed
7000  * Metric population scenario mimics the
7001  * NumericValueMetricProducerTest_ConditionCorrection.TestAlarmLatePullNoCondition test
7002  * to extent of a single bucket with correction value due to pull delay
7003  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestThresholdDefinedZero)7004 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestThresholdDefinedZero) {
7005     const int64_t pullDelayNs = 1 * NS_PER_SEC;  // 1 sec
7006     const int64_t correctionThresholdNs = 0;     // 0 sec
7007 
7008     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
7009     metric.set_condition_correction_threshold_nanos(correctionThresholdNs);
7010 
7011     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7012     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7013             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7014                                 vector<std::shared_ptr<LogEvent>>* data) {
7015                 data->clear();
7016                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
7017                 return true;
7018             }));
7019 
7020     sp<NumericValueMetricProducer> valueProducer =
7021             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
7022                                                                                   metric);
7023 
7024     ASSERT_EQ(correctionThresholdNs, valueProducer->mConditionCorrectionThresholdNs);
7025 
7026     vector<shared_ptr<LogEvent>> allData;
7027 
7028     // first delayed pull on the bucket #1 edge
7029     allData.clear();
7030     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + pullDelayNs, 10));
7031     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
7032                                 bucket2StartTimeNs + pullDelayNs);
7033 
7034     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
7035     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
7036                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
7037 
7038     // generate dump report and validate correction value in the reported buckets
7039     ProtoOutputStream output;
7040     std::set<string> strSet;
7041     valueProducer->onDumpReport(bucket3StartTimeNs, false /* include partial bucket */, true,
7042                                 FAST /* dumpLatency */, &strSet, &output);
7043 
7044     StatsLogReport report = outputStreamToProto(&output);
7045 
7046     EXPECT_TRUE(report.has_value_metrics());
7047     ASSERT_EQ(1, report.value_metrics().data_size());
7048     ASSERT_EQ(0, report.value_metrics().skipped_size());
7049     ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
7050     EXPECT_EQ(pullDelayNs,
7051               report.value_metrics().data(0).bucket_info(0).condition_correction_nanos());
7052 }
7053 
7054 /**
7055  * Tests pulled atoms with no conditions and delayed pull on the bucket boundary
7056  * The threshold is equal to the pullDelayNs - correction should be performed
7057  * Metric population scenario mimics the
7058  * NumericValueMetricProducerTest_ConditionCorrection.TestAlarmLatePullNoCondition test
7059  * to extent of a 2 bucket with correction value due to pull delay
7060  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestThresholdUploadPassWhenEqual)7061 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestThresholdUploadPassWhenEqual) {
7062     const int64_t pullDelayNs = 1 * NS_PER_SEC;         // 1 sec
7063     const int64_t correctionThresholdNs = pullDelayNs;  // 1 sec
7064 
7065     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
7066     metric.set_condition_correction_threshold_nanos(pullDelayNs);
7067     ASSERT_EQ(pullDelayNs, metric.condition_correction_threshold_nanos());
7068 
7069     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7070     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7071             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7072                                 vector<std::shared_ptr<LogEvent>>* data) {
7073                 data->clear();
7074                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
7075                 return true;
7076             }));
7077 
7078     sp<NumericValueMetricProducer> valueProducer =
7079             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
7080                                                                                   metric);
7081 
7082     ASSERT_EQ(correctionThresholdNs, valueProducer->mConditionCorrectionThresholdNs);
7083 
7084     vector<shared_ptr<LogEvent>> allData;
7085 
7086     // first delayed pull on the bucket #1 edge
7087     allData.clear();
7088     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + pullDelayNs, 10));
7089     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
7090                                 bucket2StartTimeNs + pullDelayNs);
7091 
7092     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
7093     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
7094                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
7095 
7096     // second pull on the bucket #2 boundary on time
7097     allData.clear();
7098     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 15));
7099     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket3StartTimeNs);
7100 
7101     // the second pull did close the second bucket with condition duration == bucketSizeNs
7102     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5, 5},
7103                                     {bucketSizeNs, bucketSizeNs}, {pullDelayNs, -pullDelayNs},
7104                                     {bucketStartTimeNs, bucket2StartTimeNs},
7105                                     {bucket2StartTimeNs, bucket3StartTimeNs});
7106 
7107     // generate dump report and validate correction value in the reported buckets
7108     ProtoOutputStream output;
7109     std::set<string> strSet;
7110     valueProducer->onDumpReport(bucket3StartTimeNs, false /* include partial bucket */, true,
7111                                 FAST /* dumpLatency */, &strSet, &output);
7112 
7113     StatsLogReport report = outputStreamToProto(&output);
7114 
7115     EXPECT_TRUE(report.has_value_metrics());
7116     ASSERT_EQ(1, report.value_metrics().data_size());
7117     ASSERT_EQ(0, report.value_metrics().skipped_size());
7118     ASSERT_EQ(2, report.value_metrics().data(0).bucket_info_size());
7119     EXPECT_EQ(pullDelayNs,
7120               report.value_metrics().data(0).bucket_info(0).condition_correction_nanos());
7121     EXPECT_EQ(-pullDelayNs,
7122               report.value_metrics().data(0).bucket_info(1).condition_correction_nanos());
7123 }
7124 
7125 /**
7126  * Tests pulled atoms with no conditions and delayed pull on the bucket boundary
7127  * The threshold is smaller thant pullDelayNs - correction should be performed
7128  * Metric population scenario mimics the
7129  * NumericValueMetricProducerTest_ConditionCorrection.TestAlarmLatePullNoCondition test
7130  * to extent of a single bucket with correction value due to pull delay
7131  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestThresholdUploadPassWhenGreater)7132 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestThresholdUploadPassWhenGreater) {
7133     const int64_t pullDelayNs = 1 * NS_PER_SEC;            // 1 sec
7134     const int64_t correctionThresholdNs = NS_PER_SEC - 1;  // less than 1 sec
7135 
7136     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
7137     metric.set_condition_correction_threshold_nanos(correctionThresholdNs);
7138     ASSERT_EQ(correctionThresholdNs, metric.condition_correction_threshold_nanos());
7139 
7140     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7141     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7142             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7143                                 vector<std::shared_ptr<LogEvent>>* data) {
7144                 data->clear();
7145                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
7146                 return true;
7147             }));
7148 
7149     sp<NumericValueMetricProducer> valueProducer =
7150             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
7151                                                                                   metric);
7152 
7153     ASSERT_EQ(correctionThresholdNs, valueProducer->mConditionCorrectionThresholdNs);
7154 
7155     vector<shared_ptr<LogEvent>> allData;
7156 
7157     // first delayed pull on the bucket #1 edge
7158     allData.clear();
7159     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + pullDelayNs, 10));
7160     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
7161                                 bucket2StartTimeNs + pullDelayNs);
7162 
7163     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
7164     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
7165                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
7166 
7167     // generate dump report and validate correction value in the reported buckets
7168     ProtoOutputStream output;
7169     std::set<string> strSet;
7170     valueProducer->onDumpReport(bucket3StartTimeNs, false /* include partial bucket */, true,
7171                                 FAST /* dumpLatency */, &strSet, &output);
7172 
7173     StatsLogReport report = outputStreamToProto(&output);
7174 
7175     EXPECT_TRUE(report.has_value_metrics());
7176     ASSERT_EQ(1, report.value_metrics().data_size());
7177     ASSERT_EQ(0, report.value_metrics().skipped_size());
7178     ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
7179     EXPECT_EQ(pullDelayNs,
7180               report.value_metrics().data(0).bucket_info(0).condition_correction_nanos());
7181 }
7182 
7183 /**
7184  * Tests pulled atoms with no conditions and delayed pull on the bucket boundary
7185  * The threshold is greater than pullDelayNs - correction upload should be skipped
7186  * Metric population scenario mimics the
7187  * NumericValueMetricProducerTest_ConditionCorrection.TestAlarmLatePullNoCondition test
7188  * to extent of a single bucket with correction value due to pull delay
7189  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestThresholdUploadSkip)7190 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestThresholdUploadSkip) {
7191     const int64_t pullDelayNs = 1 * NS_PER_SEC;            // 1 sec
7192     const int64_t correctionThresholdNs = NS_PER_SEC + 1;  // greater than 1 sec
7193 
7194     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
7195     metric.set_condition_correction_threshold_nanos(correctionThresholdNs);
7196     ASSERT_EQ(correctionThresholdNs, metric.condition_correction_threshold_nanos());
7197 
7198     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7199     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7200             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7201                                 vector<std::shared_ptr<LogEvent>>* data) {
7202                 data->clear();
7203                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
7204                 return true;
7205             }));
7206 
7207     sp<NumericValueMetricProducer> valueProducer =
7208             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
7209                                                                                   metric);
7210 
7211     ASSERT_EQ(correctionThresholdNs, valueProducer->mConditionCorrectionThresholdNs);
7212 
7213     vector<shared_ptr<LogEvent>> allData;
7214 
7215     // first delayed pull on the bucket #1 edge
7216     allData.clear();
7217     allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + pullDelayNs, 10));
7218     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS,
7219                                 bucket2StartTimeNs + pullDelayNs);
7220 
7221     // the delayed pull did close the first bucket with condition duration == bucketSizeNs
7222     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {5}, {bucketSizeNs}, {pullDelayNs},
7223                                     {bucketStartTimeNs}, {bucket2StartTimeNs});
7224 
7225     // generate dump report and validate correction value in the reported buckets
7226     ProtoOutputStream output;
7227     std::set<string> strSet;
7228     valueProducer->onDumpReport(bucket3StartTimeNs, false /* include partial bucket */, true,
7229                                 FAST /* dumpLatency */, &strSet, &output);
7230 
7231     StatsLogReport report = outputStreamToProto(&output);
7232 
7233     EXPECT_TRUE(report.has_value_metrics());
7234     ASSERT_EQ(1, report.value_metrics().data_size());
7235     ASSERT_EQ(0, report.value_metrics().skipped_size());
7236     ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
7237     EXPECT_FALSE(report.value_metrics().data(0).bucket_info(0).has_condition_correction_nanos());
7238 }
7239 
7240 /**
7241  * Tests pulled atoms with no conditions and delayed pull on the bucket boundary
7242  * for the atoms sliced by state. Delayed pull occures due to delayed onStateChange event
7243  * First bucket ends with delayed OFF -> ON transition, correction is applied only to OFF state
7244  * Second and third buckets pulled ontime
7245  */
TEST(NumericValueMetricProducerTest_ConditionCorrection,TestLateStateChangeSlicedAtoms)7246 TEST(NumericValueMetricProducerTest_ConditionCorrection, TestLateStateChangeSlicedAtoms) {
7247     // Set up NumericValueMetricProducer.
7248     ValueMetric metric =
7249             NumericValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE");
7250     metric.set_condition_correction_threshold_nanos(0);
7251     int increasedValue = 1;
7252     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7253     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7254             .Times(5)
7255             .WillRepeatedly(Invoke([&increasedValue](int tagId, const ConfigKey&,
7256                                                      const int64_t eventTimeNs,
7257                                                      vector<std::shared_ptr<LogEvent>>* data) {
7258                 data->clear();
7259                 data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, increasedValue++));
7260                 return true;
7261             }));
7262 
7263     StateManager::getInstance().clear();
7264     sp<NumericValueMetricProducer> valueProducer =
7265             NumericValueMetricProducerTestHelper::createValueProducerWithState(
7266                     pullerManager, metric, {util::SCREEN_STATE_CHANGED}, {});
7267 
7268     // Set up StateManager and check that StateTrackers are initialized.
7269     StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
7270 
7271     // Bucket status after screen state change kStateUnknown->OFF
7272     auto screenEvent = CreateScreenStateChangedEvent(
7273             bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
7274     StateManager::getInstance().onLogEvent(*screenEvent);
7275     ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
7276 
7277     // Value for dimension, state key {{}, OFF}
7278     auto it = valueProducer->mCurrentSlicedBucket.begin();
7279     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
7280               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
7281     assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
7282 
7283     // Bucket status after screen state change OFF->ON, forces bucket flush and new bucket start
7284     // with 10 seconds delay
7285     screenEvent = CreateScreenStateChangedEvent(bucket2StartTimeNs + 10 * NS_PER_SEC,
7286                                                 android::view::DisplayStateEnum::DISPLAY_STATE_ON);
7287     StateManager::getInstance().onLogEvent(*screenEvent);
7288     // Bucket flush will trim all MetricDimensionKeys besides the current state key.
7289     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
7290     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
7291 
7292     // mCurrentSlicedBucket represents second bucket
7293     // Value for dimension, state key {{}, ON}
7294     it = valueProducer->mCurrentSlicedBucket.begin();
7295     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
7296               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
7297     assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 10 * NS_PER_SEC);
7298 
7299     // Bucket status after screen state change ON->OFF, forces bucket flush and new bucket start
7300     screenEvent = CreateScreenStateChangedEvent(bucket3StartTimeNs,
7301                                                 android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
7302     StateManager::getInstance().onLogEvent(*screenEvent);
7303     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
7304     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
7305 
7306     // mCurrentSlicedBucket represents third bucket
7307     // Value for dimension, state key {{}, OFF}
7308     it = valueProducer->mCurrentSlicedBucket.begin();
7309     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
7310               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
7311     assertConditionTimer(it->second.conditionTimer, true, 0, bucket3StartTimeNs, 0);
7312 
7313     // Bucket status after screen state change OFF->ON, forces bucket flush and new bucket start
7314     screenEvent = CreateScreenStateChangedEvent(bucket4StartTimeNs,
7315                                                 android::view::DisplayStateEnum::DISPLAY_STATE_ON);
7316     StateManager::getInstance().onLogEvent(*screenEvent);
7317     ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
7318     ASSERT_EQ(1UL, valueProducer->mDimInfos.size());
7319 
7320     // Start dump report and check output.
7321     ProtoOutputStream output;
7322     std::set<string> strSet;
7323     valueProducer->onDumpReport(bucket4StartTimeNs + 10, false /* do not include partial buckets */,
7324                                 true, NO_TIME_CONSTRAINTS, &strSet, &output);
7325 
7326     StatsLogReport report = outputStreamToProto(&output);
7327     backfillStartEndTimestamp(&report);
7328     EXPECT_TRUE(report.has_value_metrics());
7329     ASSERT_EQ(3, report.value_metrics().data_size());
7330 
7331     // {{}, ON} - delayed start finish on time - no correction
7332     auto data = report.value_metrics().data(0);
7333     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
7334     ValidateValueBucket(data.bucket_info(0), bucket2StartTimeNs, bucket3StartTimeNs, {1},
7335                         50 * NS_PER_SEC, 0);
7336 
7337     // {{}, Unknown}
7338     data = report.value_metrics().data(1);
7339     EXPECT_EQ(-1, data.slice_by_state(0).value());
7340     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {1},
7341                         5 * NS_PER_SEC, 0);
7342 
7343     // {{}, OFF}
7344     data = report.value_metrics().data(2);
7345     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
7346     ASSERT_EQ(2, data.bucket_info_size());
7347     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {1},
7348                         55 * NS_PER_SEC, 10 * NS_PER_SEC);
7349     ValidateValueBucket(data.bucket_info(1), bucket3StartTimeNs, bucket4StartTimeNs, {1},
7350                         60 * NS_PER_SEC, 0);
7351 }
7352 
TEST(NumericValueMetricProducerTest,TestSubsetDimensions)7353 TEST(NumericValueMetricProducerTest, TestSubsetDimensions) {
7354     // Create metric with subset of dimensions.
7355     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
7356     *metric.mutable_dimensions_in_what() = CreateDimensions(tagId, {1 /*uid*/});
7357 
7358     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7359 
7360     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7361             // First and third fields are dimension fields. Second field is the value field.
7362             // First bucket pull.
7363             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7364                                 vector<std::shared_ptr<LogEvent>>* data) {
7365                 data->clear();
7366                 data->push_back(
7367                         CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 1, 1 /*uid*/, 5, 5));
7368                 data->push_back(
7369                         CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 1, 1 /*uid*/, 5, 7));
7370                 data->push_back(
7371                         CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 1, 2 /*uid*/, 6, 5));
7372                 data->push_back(
7373                         CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 1, 2 /*uid*/, 6, 7));
7374                 return true;
7375             }))
7376             // Dump report.
7377             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7378                                 vector<std::shared_ptr<LogEvent>>* data) {
7379                 data->clear();
7380                 data->push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 10000000000,
7381                                                          1 /*uid*/, 13, 5));
7382                 data->push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 10000000000,
7383                                                          1 /*uid*/, 15, 7));
7384                 data->push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 10000000000,
7385                                                          2 /*uid*/, 21, 5));
7386                 data->push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 10000000000,
7387                                                          2 /*uid*/, 22, 7));
7388                 return true;
7389             }));
7390 
7391     sp<NumericValueMetricProducer> valueProducer =
7392             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
7393                                                                                   metric);
7394 
7395     // Bucket 2 start.
7396     vector<shared_ptr<LogEvent>> allData;
7397     allData.clear();
7398     allData.push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 1, 1 /*uid*/, 10, 5));
7399     allData.push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 1, 1 /*uid*/, 11, 7));
7400     allData.push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 1, 2 /*uid*/, 8, 5));
7401     allData.push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 1, 2 /*uid*/, 9, 7));
7402     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
7403     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
7404     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
7405 
7406     // Check dump report.
7407     ProtoOutputStream output;
7408     std::set<string> strSet;
7409     int64_t dumpReportTimeNs = bucket2StartTimeNs + 10000000000;
7410     valueProducer->onDumpReport(dumpReportTimeNs, true /* include current buckets */, true,
7411                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
7412     ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
7413     ASSERT_EQ(2UL, valueProducer->mDimInfos.size());
7414 
7415     StatsLogReport report = outputStreamToProto(&output);
7416     backfillDimensionPath(&report);
7417     backfillStartEndTimestamp(&report);
7418     EXPECT_TRUE(report.has_value_metrics());
7419     StatsLogReport::ValueMetricDataWrapper valueMetrics;
7420     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
7421     ASSERT_EQ(2, valueMetrics.data_size());
7422     EXPECT_EQ(0, report.value_metrics().skipped_size());
7423 
7424     // Check data keyed to uid 1.
7425     ValueMetricData data = valueMetrics.data(0);
7426     ValidateUidDimension(data.dimensions_in_what(), tagId, 1);
7427     ASSERT_EQ(2, data.bucket_info_size());
7428     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {11}, -1, 0);
7429     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, dumpReportTimeNs, {7}, -1, 0);
7430 
7431     // Check data keyed to uid 2.
7432     data = valueMetrics.data(1);
7433     ValidateUidDimension(data.dimensions_in_what(), tagId, 2);
7434     ASSERT_EQ(2, data.bucket_info_size());
7435     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {5}, -1, 0);
7436     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, dumpReportTimeNs, {26}, -1, 0);
7437 }
7438 
TEST(NumericValueMetricProducerTest,TestRepeatedValueFieldAndDimensions)7439 TEST(NumericValueMetricProducerTest, TestRepeatedValueFieldAndDimensions) {
7440     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithRepeatedValueField();
7441     metric.mutable_dimensions_in_what()->set_field(tagId);
7442     FieldMatcher* valueChild = metric.mutable_dimensions_in_what()->add_child();
7443     valueChild->set_field(1);
7444     valueChild->set_position(Position::FIRST);
7445 
7446     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7447 
7448     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7449             // First field is a dimension field (repeated, position FIRST).
7450             // Third field is the value field (repeated, position FIRST).
7451             // NumericValueMetricProducer initialized.
7452             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7453                                 vector<std::shared_ptr<LogEvent>>* data) {
7454                 data->clear();
7455                 data->push_back(
7456                         makeRepeatedUidLogEvent(tagId, bucketStartTimeNs + 1, {1, 10}, 5, {2, 3}));
7457                 data->push_back(
7458                         makeRepeatedUidLogEvent(tagId, bucketStartTimeNs + 1, {2, 10}, 5, {3, 4}));
7459                 return true;
7460             }))
7461             // Dump report pull.
7462             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7463                                 vector<std::shared_ptr<LogEvent>>* data) {
7464                 data->clear();
7465                 data->push_back(makeRepeatedUidLogEvent(tagId, bucket2StartTimeNs + 10000000000,
7466                                                         {1, 10}, 5, {10, 3}));
7467                 data->push_back(makeRepeatedUidLogEvent(tagId, bucket2StartTimeNs + 10000000000,
7468                                                         {2, 10}, 5, {14, 4}));
7469                 return true;
7470             }));
7471 
7472     sp<NumericValueMetricProducer> valueProducer =
7473             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager,
7474                                                                                   metric);
7475 
7476     // Bucket 2 start.
7477     vector<shared_ptr<LogEvent>> allData;
7478     allData.clear();
7479     allData.push_back(makeRepeatedUidLogEvent(tagId, bucket2StartTimeNs + 1, {1, 10}, 5, {5, 7}));
7480     allData.push_back(makeRepeatedUidLogEvent(tagId, bucket2StartTimeNs + 1, {2, 10}, 5, {7, 5}));
7481     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
7482 
7483     // Check dump report.
7484     ProtoOutputStream output;
7485     std::set<string> strSet;
7486     int64_t dumpReportTimeNs = bucket2StartTimeNs + 10000000000;
7487     valueProducer->onDumpReport(dumpReportTimeNs, true /* include current buckets */, true,
7488                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
7489 
7490     StatsLogReport report = outputStreamToProto(&output);
7491     backfillDimensionPath(&report);
7492     backfillStartEndTimestamp(&report);
7493     EXPECT_TRUE(report.has_value_metrics());
7494     StatsLogReport::ValueMetricDataWrapper valueMetrics;
7495     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
7496     ASSERT_EQ(2, valueMetrics.data_size());
7497     EXPECT_EQ(0, report.value_metrics().skipped_size());
7498 
7499     // Check data keyed to uid 1.
7500     ValueMetricData data = valueMetrics.data(0);
7501     ValidateUidDimension(data.dimensions_in_what(), tagId, 1);
7502     ASSERT_EQ(2, data.bucket_info_size());
7503     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {3}, -1,
7504                         0);  // Summed diffs of 2, 5
7505     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, dumpReportTimeNs, {5}, -1,
7506                         0);  // Summed diffs of 5, 10
7507 
7508     // Check data keyed to uid 2.
7509     data = valueMetrics.data(1);
7510     ValidateUidDimension(data.dimensions_in_what(), tagId, 2);
7511     ASSERT_EQ(2, data.bucket_info_size());
7512     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, {4}, -1,
7513                         0);  // Summed diffs of 3, 7
7514     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, dumpReportTimeNs, {7}, -1,
7515                         0);  // Summed diffs of 7, 14
7516 }
7517 
TEST(NumericValueMetricProducerTest,TestSampleSize)7518 TEST(NumericValueMetricProducerTest, TestSampleSize) {
7519     sp<EventMatcherWizard> eventMatcherWizard =
7520             createEventMatcherWizard(tagId, logEventMatcherIndex);
7521     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
7522     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7523 
7524     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
7525 
7526     /*Sample size is added automatically with ValueMetric::AVG*/
7527     metric.set_aggregation_type(ValueMetric::AVG);
7528     sp<NumericValueMetricProducer> valueProducerAvg =
7529             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
7530                     pullerManager, metric, /*pullAtomId=*/-1);
7531 
7532     /*Sample size is not added automatically with non-ValueMetric::AVG aggregation types*/
7533     metric.set_aggregation_type(ValueMetric::SUM);
7534     sp<NumericValueMetricProducer> valueProducerSum =
7535             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
7536                     pullerManager, metric, /*pullAtomId=*/-1);
7537 
7538     /*Sample size is added when include_sample_size bool is set to true*/
7539     metric.set_include_sample_size(true);
7540     sp<NumericValueMetricProducer> valueProducerSumWithSampleSize =
7541             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
7542                     pullerManager, metric, /*pullAtomId=*/-1);
7543 
7544     LogEvent event1(/*uid=*/0, /*pid=*/0);
7545     LogEvent event2(/*uid=*/0, /*pid=*/0);
7546     LogEvent event3(/*uid=*/0, /*pid=*/0);
7547     CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
7548     CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15);
7549     CreateRepeatedValueLogEvent(&event3, tagId, bucketStartTimeNs + 20, 20);
7550     valueProducerAvg->onMatchedLogEvent(1 /*log matcher index*/, event1);
7551     valueProducerAvg->onMatchedLogEvent(1 /*log matcher index*/, event2);
7552     valueProducerSum->onMatchedLogEvent(1 /*log matcher index*/, event1);
7553     valueProducerSum->onMatchedLogEvent(1 /*log matcher index*/, event2);
7554     valueProducerSum->onMatchedLogEvent(1 /*log matcher index*/, event3);
7555     valueProducerSumWithSampleSize->onMatchedLogEvent(1 /*log matcher index*/, event1);
7556     valueProducerSumWithSampleSize->onMatchedLogEvent(1 /*log matcher index*/, event2);
7557     valueProducerSumWithSampleSize->onMatchedLogEvent(1 /*log matcher index*/, event3);
7558 
7559     NumericValueMetricProducer::Interval curInterval;
7560     ASSERT_EQ(1UL, valueProducerAvg->mCurrentSlicedBucket.size());
7561     curInterval = valueProducerAvg->mCurrentSlicedBucket.begin()->second.intervals[0];
7562     EXPECT_EQ(2, curInterval.sampleSize);
7563     ASSERT_EQ(1UL, valueProducerSum->mCurrentSlicedBucket.size());
7564     curInterval = valueProducerSum->mCurrentSlicedBucket.begin()->second.intervals[0];
7565     EXPECT_EQ(3, curInterval.sampleSize);
7566     ASSERT_EQ(1UL, valueProducerSumWithSampleSize->mCurrentSlicedBucket.size());
7567     curInterval = valueProducerSumWithSampleSize->mCurrentSlicedBucket.begin()->second.intervals[0];
7568     EXPECT_EQ(3, curInterval.sampleSize);
7569 
7570     valueProducerAvg->flushIfNeededLocked(bucket2StartTimeNs);
7571     valueProducerSum->flushIfNeededLocked(bucket2StartTimeNs);
7572     valueProducerSumWithSampleSize->flushIfNeededLocked(bucket2StartTimeNs);
7573 
7574     // Start dump report and check output.
7575     ProtoOutputStream outputAvg;
7576     std::set<string> strSetAvg;
7577     valueProducerAvg->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
7578                                    true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
7579                                    &strSetAvg, &outputAvg);
7580 
7581     StatsLogReport reportAvg = outputStreamToProto(&outputAvg);
7582     ASSERT_EQ(1, reportAvg.value_metrics().data_size());
7583 
7584     ValueMetricData data = reportAvg.value_metrics().data(0);
7585     ASSERT_EQ(1, data.bucket_info_size());
7586     ASSERT_EQ(1, data.bucket_info(0).values_size());
7587     EXPECT_EQ(2, data.bucket_info(0).values(0).sample_size());
7588     EXPECT_TRUE(std::abs(data.bucket_info(0).values(0).value_double() - 12.5) < epsilon);
7589 
7590     // Start dump report and check output.
7591     ProtoOutputStream outputSum;
7592     std::set<string> strSetSum;
7593     valueProducerSum->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
7594                                    true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
7595                                    &strSetSum, &outputSum);
7596 
7597     StatsLogReport reportSum = outputStreamToProto(&outputSum);
7598     ASSERT_EQ(1, reportSum.value_metrics().data_size());
7599 
7600     data = reportSum.value_metrics().data(0);
7601     ASSERT_EQ(1, data.bucket_info_size());
7602     ASSERT_EQ(1, data.bucket_info(0).values_size());
7603     EXPECT_EQ(45, data.bucket_info(0).values(0).value_long());
7604     EXPECT_FALSE(data.bucket_info(0).values(0).has_sample_size());
7605 
7606     // Start dump report and check output.
7607     ProtoOutputStream outputSumWithSampleSize;
7608     std::set<string> strSetSumWithSampleSize;
7609     valueProducerSumWithSampleSize->onDumpReport(
7610             bucket2StartTimeNs + 50 * NS_PER_SEC, true /* include recent buckets */, true,
7611             NO_TIME_CONSTRAINTS, &strSetSumWithSampleSize, &outputSumWithSampleSize);
7612 
7613     StatsLogReport reportSumWithSampleSize = outputStreamToProto(&outputSumWithSampleSize);
7614     ASSERT_EQ(1, reportSumWithSampleSize.value_metrics().data_size());
7615 
7616     data = reportSumWithSampleSize.value_metrics().data(0);
7617     ASSERT_EQ(1, data.bucket_info_size());
7618     ASSERT_EQ(1, data.bucket_info(0).values_size());
7619     EXPECT_EQ(3, data.bucket_info(0).values(0).sample_size());
7620     EXPECT_EQ(45, data.bucket_info(0).values(0).value_long());
7621 }
7622 
TEST(NumericValueMetricProducerTest,TestDimensionalSampling)7623 TEST(NumericValueMetricProducerTest, TestDimensionalSampling) {
7624     ShardOffsetProvider::getInstance().setShardOffset(5);
7625 
7626     int shardCount = 2;
7627     ValueMetric sampledValueMetric = NumericValueMetricProducerTestHelper::createMetric();
7628     *sampledValueMetric.mutable_dimensions_in_what() = CreateDimensions(tagId, {1 /*uid*/});
7629     *sampledValueMetric.mutable_dimensional_sampling_info()->mutable_sampled_what_field() =
7630             CreateDimensions(tagId, {1 /*uid*/});
7631     sampledValueMetric.mutable_dimensional_sampling_info()->set_shard_count(shardCount);
7632 
7633     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7634 
7635     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7636             // First field is a dimension field and sampled what field.
7637             // Second field is the value field.
7638             // NumericValueMetricProducer initialized.
7639             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7640                                 vector<std::shared_ptr<LogEvent>>* data) {
7641                 data->clear();
7642                 data->push_back(makeUidLogEvent(tagId, bucketStartTimeNs + 1, 1001, 5, 10));
7643                 data->push_back(makeUidLogEvent(tagId, bucketStartTimeNs + 1, 1002, 10, 10));
7644                 data->push_back(makeUidLogEvent(tagId, bucketStartTimeNs + 1, 1003, 15, 10));
7645                 return true;
7646             }))
7647             // Dump report pull.
7648             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7649                                 vector<std::shared_ptr<LogEvent>>* data) {
7650                 data->clear();
7651                 data->push_back(
7652                         makeUidLogEvent(tagId, bucketStartTimeNs + 10000000000, 1001, 6, 10));
7653                 data->push_back(
7654                         makeUidLogEvent(tagId, bucketStartTimeNs + 10000000000, 1002, 12, 10));
7655                 data->push_back(
7656                         makeUidLogEvent(tagId, bucketStartTimeNs + 10000000000, 1003, 18, 10));
7657                 return true;
7658             }));
7659 
7660     sp<NumericValueMetricProducer> valueProducer =
7661             NumericValueMetricProducerTestHelper::createValueProducerWithSampling(
7662                     pullerManager, sampledValueMetric);
7663 
7664     // Check dump report.
7665     ProtoOutputStream output;
7666     std::set<string> strSet;
7667     int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000;
7668     valueProducer->onDumpReport(dumpReportTimeNs, true /* include current buckets */, true,
7669                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
7670 
7671     StatsLogReport report = outputStreamToProto(&output);
7672     backfillDimensionPath(&report);
7673     backfillStartEndTimestamp(&report);
7674     EXPECT_TRUE(report.has_value_metrics());
7675     StatsLogReport::ValueMetricDataWrapper valueMetrics;
7676     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
7677     ASSERT_EQ(2, valueMetrics.data_size());
7678     EXPECT_EQ(0, report.value_metrics().skipped_size());
7679 
7680     // Only Uid 1, 3, 4 are logged. (odd hash value) + (offset of 5) % (shard count of 2) = 0
7681     ValueMetricData data = valueMetrics.data(0);
7682     ValidateUidDimension(data.dimensions_in_what(), tagId, 1001);
7683     ASSERT_EQ(1, data.bucket_info_size());
7684     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + 10000000000,
7685                         {1}, -1,
7686                         0);  // Diff of 5 and 6
7687 
7688     data = valueMetrics.data(1);
7689     ValidateUidDimension(data.dimensions_in_what(), tagId, 1003);
7690     ASSERT_EQ(1, data.bucket_info_size());
7691     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + 10000000000,
7692                         {3}, -1,
7693                         0);  // Diff of 15 and 18
7694 }
7695 
TEST(NumericValueMetricProducerTest,TestMultipleAggTypesPulled)7696 TEST(NumericValueMetricProducerTest, TestMultipleAggTypesPulled) {
7697     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetricWithCondition();
7698     // createMetricWithCondition() adds field 2 as first value field.
7699     metric.mutable_value_field()->add_child()->set_field(2);
7700     metric.mutable_value_field()->add_child()->set_field(2);
7701     metric.mutable_value_field()->add_child()->set_field(2);
7702     metric.mutable_value_field()->add_child()->set_field(1);
7703     metric.add_aggregation_types(ValueMetric::MIN);
7704     metric.add_aggregation_types(ValueMetric::MAX);
7705     metric.add_aggregation_types(ValueMetric::SUM);
7706     metric.add_aggregation_types(ValueMetric::AVG);
7707     metric.add_aggregation_types(ValueMetric::SUM);
7708 
7709     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7710 
7711     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
7712             // Screen On Pull 1.
7713             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7714                                 vector<std::shared_ptr<LogEvent>>* data) {
7715                 data->clear();
7716                 data->push_back(
7717                         CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 1, 2));
7718                 data->push_back(
7719                         CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 2, 4));
7720                 return true;
7721             }))
7722             // Screen Off Pull 2.
7723             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7724                                 vector<std::shared_ptr<LogEvent>>* data) {
7725                 data->clear();
7726                 data->push_back(
7727                         CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 3, 5));
7728                 data->push_back(
7729                         CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 4, 9));
7730                 return true;
7731             }))
7732             // Screen On Pull 3.
7733             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7734                                 vector<std::shared_ptr<LogEvent>>* data) {
7735                 data->clear();
7736                 data->push_back(
7737                         CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 5, 10));
7738                 data->push_back(
7739                         CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 6, 20));
7740                 return true;
7741             }))
7742             // Dump report pull.
7743             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
7744                                 vector<std::shared_ptr<LogEvent>>* data) {
7745                 data->clear();
7746                 data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 55 * NS_PER_SEC,
7747                                                        25, 60));
7748                 data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 55 * NS_PER_SEC,
7749                                                        35, 80));
7750 
7751                 return true;
7752             }));
7753 
7754     sp<NumericValueMetricProducer> valueProducer =
7755             NumericValueMetricProducerTestHelper::createValueProducerWithCondition(
7756                     pullerManager, metric, ConditionState::kFalse);
7757 
7758     EXPECT_EQ(5, valueProducer->mFieldMatchers.size());
7759     ASSERT_EQ(5, valueProducer->mAggregationTypes.size());
7760     EXPECT_EQ(ValueMetric::MIN, valueProducer->mAggregationTypes[0]);
7761     EXPECT_EQ(ValueMetric::MAX, valueProducer->mAggregationTypes[1]);
7762     EXPECT_EQ(ValueMetric::SUM, valueProducer->mAggregationTypes[2]);
7763     EXPECT_EQ(ValueMetric::AVG, valueProducer->mAggregationTypes[3]);
7764     EXPECT_EQ(ValueMetric::SUM, valueProducer->mAggregationTypes[4]);
7765     EXPECT_TRUE(valueProducer->mIncludeSampleSize);
7766 
7767     // Screen On. Pull 1.
7768     valueProducer->onConditionChanged(true, bucketStartTimeNs + 30 * NS_PER_SEC);
7769 
7770     // Screen Off.
7771     valueProducer->onConditionChanged(false, bucketStartTimeNs + 40 * NS_PER_SEC);
7772 
7773     // Screen On. Pull 2.
7774     valueProducer->onConditionChanged(true, bucketStartTimeNs + 50 * NS_PER_SEC);
7775 
7776     // Bucket 2 start. Pull 4.
7777     vector<shared_ptr<LogEvent>> allData;
7778     allData.clear();
7779     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs, 15, 30));
7780     allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs, 20, 40));
7781     valueProducer->onDataPulled(allData, PullResult::PULL_RESULT_SUCCESS, bucket2StartTimeNs);
7782 
7783     // Check dump report.
7784     ProtoOutputStream output;
7785     std::set<string> strSet;
7786     int64_t dumpReportTimeNs = bucket2StartTimeNs + 55 * NS_PER_SEC;
7787     valueProducer->onDumpReport(dumpReportTimeNs, true /* include current buckets */, true,
7788                                 NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
7789 
7790     StatsLogReport report = outputStreamToProto(&output);
7791     backfillDimensionPath(&report);
7792     backfillStartEndTimestamp(&report);
7793     EXPECT_TRUE(report.has_value_metrics());
7794     StatsLogReport::ValueMetricDataWrapper valueMetrics;
7795     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
7796     ASSERT_EQ(1, valueMetrics.data_size());
7797     EXPECT_EQ(0, report.value_metrics().skipped_size());
7798 
7799     // Bucket 1.
7800     // Value field 1
7801     // Diff from pulls 1 and 2: (3+4)-(1+2) = 4
7802     // Diff from pulls 3 and 4: (15+20)-(5+6) = 24
7803 
7804     // Value field 2
7805     // Diff from pulls 1 and 2: (5+9)-(2+4) = 8
7806     // Diff from pulls 3 and 4: (30+40)-(10+20) = 40
7807 
7808     // Bucket 2
7809     // Value field 1
7810     // Diff from pulls 4 and 5: (25+35)-(15+20) = 25
7811 
7812     // Value field 2
7813     // Diff from pulls 4 and 5: (60+80)-(30+40) = 70
7814 
7815     // Output values are calculated for these agg type - value field combinations
7816     // MIN-2, MAX-2, SUM-2, AVG-2, SUM-1
7817     ValueMetricData data = valueMetrics.data(0);
7818     ASSERT_EQ(2, data.bucket_info_size());
7819     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs,
7820                         {8, 40, 48, 24, 28}, 20 * NS_PER_SEC, 0);
7821     for (int i = 0; i < data.bucket_info(0).values_size(); ++i) {
7822         EXPECT_EQ(2, data.bucket_info(0).values(i).sample_size());
7823     }
7824     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, dumpReportTimeNs,
7825                         {70, 70, 70, 70, 25}, 55 * NS_PER_SEC, 0);
7826     for (int i = 0; i < data.bucket_info(1).values_size(); ++i) {
7827         EXPECT_EQ(1, data.bucket_info(1).values(i).sample_size());
7828     }
7829 }
7830 
TEST(NumericValueMetricProducerTest,TestMultipleAggTypesPushed)7831 TEST(NumericValueMetricProducerTest, TestMultipleAggTypesPushed) {
7832     ValueMetric metric = NumericValueMetricProducerTestHelper::createMetric();
7833     metric.mutable_dimensions_in_what()->set_field(tagId);
7834     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
7835     // createMetric() adds field 2 as first value field.
7836     metric.mutable_value_field()->add_child()->set_field(2);
7837     metric.mutable_value_field()->add_child()->set_field(2);
7838     metric.mutable_value_field()->add_child()->set_field(2);
7839     metric.mutable_value_field()->add_child()->set_field(3);
7840     metric.add_aggregation_types(ValueMetric::MIN);
7841     metric.add_aggregation_types(ValueMetric::MAX);
7842     metric.add_aggregation_types(ValueMetric::SUM);
7843     metric.add_aggregation_types(ValueMetric::AVG);
7844     metric.add_aggregation_types(ValueMetric::SUM);
7845 
7846     sp<EventMatcherWizard> eventMatcherWizard =
7847             createEventMatcherWizard(tagId, logEventMatcherIndex);
7848     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
7849     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
7850 
7851     sp<NumericValueMetricProducer> valueProducer =
7852             NumericValueMetricProducerTestHelper::createValueProducerNoConditions(
7853                     pullerManager, metric, /*pullAtomId=*/-1);
7854 
7855     EXPECT_EQ(5, valueProducer->mFieldMatchers.size());
7856     ASSERT_EQ(5, valueProducer->mAggregationTypes.size());
7857     EXPECT_EQ(ValueMetric::MIN, valueProducer->mAggregationTypes[0]);
7858     EXPECT_EQ(ValueMetric::MAX, valueProducer->mAggregationTypes[1]);
7859     EXPECT_EQ(ValueMetric::SUM, valueProducer->mAggregationTypes[2]);
7860     EXPECT_EQ(ValueMetric::AVG, valueProducer->mAggregationTypes[3]);
7861     EXPECT_EQ(ValueMetric::SUM, valueProducer->mAggregationTypes[4]);
7862     EXPECT_TRUE(valueProducer->mIncludeSampleSize);
7863 
7864     // Bucket 1 events.
7865     LogEvent event1(/*uid=*/0, /*pid=*/0);
7866     CreateThreeValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 5, 10);
7867 
7868     LogEvent event2(/*uid=*/0, /*pid=*/0);
7869     CreateThreeValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 6, 8);
7870 
7871     LogEvent event3(/*uid=*/0, /*pid=*/0);
7872     CreateThreeValueLogEvent(&event3, tagId, bucketStartTimeNs + 40, 2, 3, 10);
7873 
7874     LogEvent event4(/*uid=*/0, /*pid=*/0);
7875     CreateThreeValueLogEvent(&event4, tagId, bucketStartTimeNs + 50, 2, 4, 6);
7876 
7877     LogEvent event5(/*uid=*/0, /*pid=*/0);
7878     CreateThreeValueLogEvent(&event5, tagId, bucketStartTimeNs + 30, 1, 19, 9);
7879 
7880     LogEvent event6(/*uid=*/0, /*pid=*/0);
7881     CreateThreeValueLogEvent(&event6, tagId, bucketStartTimeNs + 60, 2, 20, 8);
7882 
7883     // Bucket 2 events.
7884     LogEvent event7(/*uid=*/0, /*pid=*/0);
7885     CreateThreeValueLogEvent(&event7, tagId, bucket2StartTimeNs + 10, 2, 7, 41);
7886 
7887     LogEvent event8(/*uid=*/0, /*pid=*/0);
7888     CreateThreeValueLogEvent(&event8, tagId, bucket2StartTimeNs + 20, 1, 21, 40);
7889 
7890     LogEvent event9(/*uid=*/0, /*pid=*/0);
7891     CreateThreeValueLogEvent(&event9, tagId, bucket2StartTimeNs + 30, 1, 10, 4);
7892 
7893     LogEvent event10(/*uid=*/0, /*pid=*/0);
7894     CreateThreeValueLogEvent(&event10, tagId, bucket2StartTimeNs + 40, 2, 3, 50);
7895 
7896     LogEvent event11(/*uid=*/0, /*pid=*/0);
7897     CreateThreeValueLogEvent(&event11, tagId, bucket2StartTimeNs + 50, 1, 20, 7);
7898 
7899     LogEvent event12(/*uid=*/0, /*pid=*/0);
7900     CreateThreeValueLogEvent(&event12, tagId, bucket2StartTimeNs + 60, 2, 20, 2);
7901 
7902     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event1);
7903     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event2);
7904     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event3);
7905     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event4);
7906     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event5);
7907     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event6);
7908     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event7);
7909     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event8);
7910     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event9);
7911     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event10);
7912     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event11);
7913     valueProducer->onMatchedLogEvent(1 /*log matcher index*/, event12);
7914 
7915     // Check dump report.
7916     ProtoOutputStream output;
7917     valueProducer->onDumpReport(bucket3StartTimeNs + 10000, false /* include recent buckets */,
7918                                 true, FAST /* dumpLatency */, nullptr, &output);
7919 
7920     StatsLogReport report = outputStreamToProto(&output);
7921     backfillDimensionPath(&report);
7922     backfillStartEndTimestamp(&report);
7923     EXPECT_TRUE(report.has_value_metrics());
7924     StatsLogReport::ValueMetricDataWrapper valueMetrics;
7925     sortMetricDataByDimensionsValue(report.value_metrics(), &valueMetrics);
7926     ASSERT_EQ(2, valueMetrics.data_size());
7927     EXPECT_EQ(0, report.value_metrics().skipped_size());
7928 
7929     // Bucket 1.
7930     // Value field 2
7931     // dim 1 pushed values: 5, 6, 19
7932     // dim 2 pushed values: 3, 4, 20
7933 
7934     // Value field 3
7935     // dim 1 pushed values: 10, 8, 9
7936     // dim 2 pushed values: 10, 6, 8
7937 
7938     // Bucket 2
7939     // Value field 2
7940     // dim 1 pushed values: 21, 10, 20
7941     // dim 2 pushed values: 7, 3, 20
7942 
7943     // Value field 3
7944     // dim 1 pushed values: 40, 4, 7
7945     // dim 2 pushed values: 41, 50, 2
7946 
7947     // Output values are calculated for these agg type - value field combinations
7948     // MIN-2, MAX-2, SUM-2, AVG-2, SUM-1
7949     ValueMetricData data = valueMetrics.data(0);
7950     ASSERT_EQ(2, data.bucket_info_size());
7951     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs,
7952                         {5, 19, 30, 10, 27}, 0, 0);
7953     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, bucket3StartTimeNs,
7954                         {10, 21, 51, 17, 51}, 0, 0);
7955 
7956     data = valueMetrics.data(1);
7957     ASSERT_EQ(2, data.bucket_info_size());
7958     ValidateValueBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs,
7959                         {3, 20, 27, 9, 24}, 0, 0);
7960     for (int i = 0; i < data.bucket_info(0).values_size(); ++i) {
7961         EXPECT_EQ(3, data.bucket_info(0).values(i).sample_size());
7962     }
7963     ValidateValueBucket(data.bucket_info(1), bucket2StartTimeNs, bucket3StartTimeNs,
7964                         {3, 20, 30, 10, 93}, 0, 0);
7965     for (int i = 0; i < data.bucket_info(1).values_size(); ++i) {
7966         EXPECT_EQ(3, data.bucket_info(1).values(i).sample_size());
7967     }
7968 }
7969 
7970 }  // namespace statsd
7971 }  // namespace os
7972 }  // namespace android
7973 #else
7974 GTEST_LOG_(INFO) << "This test does nothing.\n";
7975 #endif
7976