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