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