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