(Part 2.4) Use new socket schema in ValueMetricProducer_test
First CL at ag/10697747. Sending ValueMetricProducer_test as multiple CLs to retain diff and make
it easier to review.
Updates from TestUseZeroDefaultBase to TestEmptyDataResetsBase_onDataPulled
Test: bit statsd_test:*
Bug: 149590301
Change-Id: I91601123e8aaeb92aa6e6618dbd12467949a94e4
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index fab8e68..14b191e 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -1486,936 +1486,783 @@
EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
}
-///*
-// * Tests zero default base.
-// */
-// TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.mutable_dimensions_in_what()->set_field(tagId);
-// metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-// metric.set_use_zero_default_base(true);
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-// event->write(1);
-// event->write(3);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-//
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// auto iter = valueProducer->mCurrentSlicedBucket.begin();
-// auto& interval1 = iter->second[0];
-// auto iterBase = valueProducer->mCurrentBaseInfo.begin();
-// auto& baseInfo1 = iterBase->second[0];
-// EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-// EXPECT_EQ(true, baseInfo1.hasBase);
-// EXPECT_EQ(3, baseInfo1.base.long_value);
-// EXPECT_EQ(false, interval1.hasValue);
-// EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-// vector<shared_ptr<LogEvent>> allData;
-//
-// allData.clear();
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event1->write(2);
-// event1->write(4);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event2->write(1);
-// event2->write(11);
-// event2->init();
-// allData.push_back(event1);
-// allData.push_back(event2);
-//
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-// EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(true, baseInfo1.hasBase);
-// EXPECT_EQ(11, baseInfo1.base.long_value);
-// EXPECT_EQ(false, interval1.hasValue);
-// EXPECT_EQ(8, interval1.value.long_value);
-//
-// auto it = valueProducer->mCurrentSlicedBucket.begin();
-// for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
-// if (it != iter) {
-// break;
-// }
-// }
-// auto itBase = valueProducer->mCurrentBaseInfo.begin();
-// for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
-// if (itBase != iterBase) {
-// break;
-// }
-// }
-// EXPECT_TRUE(it != iter);
-// EXPECT_TRUE(itBase != iterBase);
-// auto& interval2 = it->second[0];
-// auto& baseInfo2 = itBase->second[0];
-// EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-// EXPECT_EQ(true, baseInfo2.hasBase);
-// EXPECT_EQ(4, baseInfo2.base.long_value);
-// EXPECT_EQ(false, interval2.hasValue);
-// EXPECT_EQ(4, interval2.value.long_value);
-//
-// EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
-// auto iterator = valueProducer->mPastBuckets.begin();
-// EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
-// EXPECT_EQ(8, iterator->second[0].values[0].long_value);
-// iterator++;
-// EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
-// EXPECT_EQ(4, iterator->second[0].values[0].long_value);
-//}
-//
-///*
-// * Tests using zero default base with failed pull.
-// */
-// TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.mutable_dimensions_in_what()->set_field(tagId);
-// metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-// metric.set_use_zero_default_base(true);
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-// event->write(1);
-// event->write(3);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-//
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// auto it = valueProducer->mCurrentSlicedBucket.begin();
-// auto& interval1 = it->second[0];
-// auto& baseInfo1 =
-// valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
-// EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-// EXPECT_EQ(true, baseInfo1.hasBase);
-// EXPECT_EQ(3, baseInfo1.base.long_value);
-// EXPECT_EQ(false, interval1.hasValue);
-// EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-// vector<shared_ptr<LogEvent>> allData;
-//
-// allData.clear();
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event1->write(2);
-// event1->write(4);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event2->write(1);
-// event2->write(11);
-// event2->init();
-// allData.push_back(event1);
-// allData.push_back(event2);
-//
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-// EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(true, baseInfo1.hasBase);
-// EXPECT_EQ(11, baseInfo1.base.long_value);
-// EXPECT_EQ(false, interval1.hasValue);
-// EXPECT_EQ(8, interval1.value.long_value);
-//
-// auto it2 = valueProducer->mCurrentSlicedBucket.begin();
-// for (; it2 != valueProducer->mCurrentSlicedBucket.end(); it2++) {
-// if (it2 != it) {
-// break;
-// }
-// }
-// // auto itBase = valueProducer->mCurrentBaseInfo.begin();
-// // for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
-// // if (itBase != iterBase) {
-// // break;
-// // }
-// // }
-// EXPECT_TRUE(it2 != it);
-// // EXPECT_TRUE(itBase != iterBase);
-// auto& interval2 = it2->second[0];
-// auto& baseInfo2 =
-// valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
-// EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-// EXPECT_EQ(true, baseInfo2.hasBase);
-// EXPECT_EQ(4, baseInfo2.base.long_value);
-// EXPECT_EQ(false, interval2.hasValue);
-// EXPECT_EQ(4, interval2.value.long_value);
-// EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
-//
-// // next pull somehow did not happen, skip to end of bucket 3
-// allData.clear();
-// event1 = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
-// event1->write(2);
-// event1->write(5);
-// event1->init();
-// allData.push_back(event1);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-//
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(true, baseInfo2.hasBase);
-// EXPECT_EQ(5, baseInfo2.base.long_value);
-// EXPECT_EQ(false, interval2.hasValue);
-// EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-// EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
-//
-// allData.clear();
-// event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
-// event1->write(2);
-// event1->write(13);
-// event1->init();
-// allData.push_back(event1);
-// event2 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
-// event2->write(1);
-// event2->write(5);
-// event2->init();
-// allData.push_back(event2);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
-//
-// EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-// it = valueProducer->mCurrentSlicedBucket.begin();
-// it2 = std::next(valueProducer->mCurrentSlicedBucket.begin());
-// interval1 = it->second[0];
-// interval2 = it2->second[0];
-// baseInfo1 =
-// valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0]; baseInfo2
-// = valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
-//
-// EXPECT_EQ(true, baseInfo1.hasBase);
-// EXPECT_EQ(5, baseInfo1.base.long_value);
-// EXPECT_EQ(false, interval1.hasValue);
-// EXPECT_EQ(5, interval1.value.long_value);
-// EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-//
-// EXPECT_EQ(true, baseInfo2.hasBase);
-// EXPECT_EQ(13, baseInfo2.base.long_value);
-// EXPECT_EQ(false, interval2.hasValue);
-// EXPECT_EQ(8, interval2.value.long_value);
-//
-// EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
-//}
-//
-///*
-// * Tests trim unused dimension key if no new data is seen in an entire bucket.
-// */
-// TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.mutable_dimensions_in_what()->set_field(tagId);
-// metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-// event->write(1);
-// event->write(3);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-//
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// auto iter = valueProducer->mCurrentSlicedBucket.begin();
-// auto& interval1 = iter->second[0];
-// auto iterBase = valueProducer->mCurrentBaseInfo.begin();
-// auto& baseInfo1 = iterBase->second[0];
-// EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-// EXPECT_EQ(true, baseInfo1.hasBase);
-// EXPECT_EQ(3, baseInfo1.base.long_value);
-// EXPECT_EQ(false, interval1.hasValue);
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-// vector<shared_ptr<LogEvent>> allData;
-//
-// allData.clear();
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event1->write(2);
-// event1->write(4);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event2->write(1);
-// event2->write(11);
-// event2->init();
-// allData.push_back(event1);
-// allData.push_back(event2);
-//
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-// EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(true, baseInfo1.hasBase);
-// EXPECT_EQ(11, baseInfo1.base.long_value);
-// EXPECT_EQ(false, interval1.hasValue);
-// EXPECT_EQ(8, interval1.value.long_value);
-// EXPECT_FALSE(interval1.seenNewData);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
-//
-// auto it = valueProducer->mCurrentSlicedBucket.begin();
-// for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
-// if (it != iter) {
-// break;
-// }
-// }
-// auto itBase = valueProducer->mCurrentBaseInfo.begin();
-// for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
-// if (itBase != iterBase) {
-// break;
-// }
-// }
-// EXPECT_TRUE(it != iter);
-// EXPECT_TRUE(itBase != iterBase);
-// auto& interval2 = it->second[0];
-// auto& baseInfo2 = itBase->second[0];
-// EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-// EXPECT_EQ(true, baseInfo2.hasBase);
-// EXPECT_EQ(4, baseInfo2.base.long_value);
-// EXPECT_EQ(false, interval2.hasValue);
-// EXPECT_FALSE(interval2.seenNewData);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
-//
-// // next pull somehow did not happen, skip to end of bucket 3
-// allData.clear();
-// event1 = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
-// event1->write(2);
-// event1->write(5);
-// event1->init();
-// allData.push_back(event1);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-// // Only one interval left. One was trimmed.
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-// EXPECT_EQ(true, baseInfo2.hasBase);
-// EXPECT_EQ(5, baseInfo2.base.long_value);
-// EXPECT_EQ(false, interval2.hasValue);
-// EXPECT_FALSE(interval2.seenNewData);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
-//
-// allData.clear();
-// event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
-// event1->write(2);
-// event1->write(14);
-// event1->init();
-// allData.push_back(event1);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
-//
-// interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, baseInfo2.hasBase);
-// EXPECT_EQ(14, baseInfo2.base.long_value);
-// EXPECT_EQ(false, interval2.hasValue);
-// EXPECT_FALSE(interval2.seenNewData);
-// ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
-// auto iterator = valueProducer->mPastBuckets.begin();
-// EXPECT_EQ(9, iterator->second[0].values[0].long_value);
-// EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
-// iterator++;
-// EXPECT_EQ(8, iterator->second[0].values[0].long_value);
-// EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
-//}
-//
-// TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// // Used by onConditionChanged.
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(100);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval& curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo& curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(100, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-//
-// vector<shared_ptr<LogEvent>> allData;
-// valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(false, curBaseInfo.hasBase);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-//}
-//
-// TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(100);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// .WillOnce(Return(false));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval& curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo& curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(100, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-// valueProducer->onConditionChanged(false, bucketStartTimeNs + 20);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(false, curBaseInfo.hasBase);
-// EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-//}
-//
-// TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-// event->write(tagId);
-// event->write(50);
-// event->init();
-// data->push_back(event);
-// return false;
-// }))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(100);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// // Don't directly set mCondition; the real code never does that. Go through regular code path
-// // to avoid unexpected behaviors.
-// // valueProducer->mCondition = ConditionState::kTrue;
-// valueProducer->onConditionChanged(true, bucketStartTimeNs);
-//
-// EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-//
-// valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval& curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-//}
-//
-// TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.set_condition(StringToId("SCREEN_ON"));
-// metric.set_max_pull_delay_sec(0);
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event->write(tagId);
-// event->write(120);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->mCondition = ConditionState::kFalse;
-//
-// // Max delay is set to 0 so pull will exceed max delay.
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
-// EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-//}
-//
-// TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, tagId, bucket2StartTimeNs,
-// bucket2StartTimeNs, pullerManager);
-// valueProducer.mCondition = ConditionState::kFalse;
-//
-// // Event should be skipped since it is from previous bucket.
-// // Pull should not be called.
-// valueProducer.onConditionChanged(true, bucketStartTimeNs);
-// EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
-//}
-//
-// TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event->write(tagId);
-// event->write(100);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->mCondition = ConditionState::kFalse;
-// valueProducer->mHasGlobalBase = false;
-//
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
-// valueProducer->mHasGlobalBase = true;
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval& curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(100, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-//}
-//
-///*
-// * Tests that a bucket is marked invalid when a condition change pull fails.
-// */
-// TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// // First onConditionChanged
-// .WillOnce(Return(false))
-// // Second onConditionChanged
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(130);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->mCondition = ConditionState::kTrue;
-//
-// // Bucket start.
-// vector<shared_ptr<LogEvent>> allData;
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event->write(1);
-// event->write(110);
-// event->init();
-// allData.push_back(event);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-//
-// // This will fail and should invalidate the whole bucket since we do not have all the data
-// // needed to compute the metric value when the screen was on.
-// valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
-//
-// // Bucket end.
-// allData.clear();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event2->write(1);
-// event2->write(140);
-// event2->init();
-// allData.push_back(event2);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-// valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
-//
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-// // Contains base from last pull which was successful.
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval& curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(140, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-//
-// // Check dump report.
-// ProtoOutputStream output;
-// std::set<string> strSet;
-// valueProducer->onDumpReport(bucket2StartTimeNs + 10, false /* include partial bucket */, true,
-// FAST /* dumpLatency */, &strSet, &output);
-//
-// StatsLogReport report = outputStreamToProto(&output);
-// EXPECT_TRUE(report.has_value_metrics());
-// EXPECT_EQ(0, report.value_metrics().data_size());
-// EXPECT_EQ(1, report.value_metrics().skipped_size());
-//
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-// report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-// EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-// report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-// EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-//
-// auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-// EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
-//}
-//
-///*
-// * Tests that a bucket is marked invalid when the guardrail is hit.
-// */
-// TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.mutable_dimensions_in_what()->set_field(tagId);
-// metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-// metric.set_condition(StringToId("SCREEN_ON"));
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// // First onConditionChanged
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// for (int i = 0; i < 2000; i++) {
-// shared_ptr<LogEvent> event =
-// make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event->write(i);
-// event->write(i);
-// event->init();
-// data->push_back(event);
-// }
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-// valueProducer->mCondition = ConditionState::kFalse;
-//
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
-// EXPECT_EQ(true, valueProducer->mCurrentBucketIsInvalid);
-// EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(0UL, valueProducer->mSkippedBuckets.size());
-//
-// // Bucket 2 start.
-// vector<shared_ptr<LogEvent>> allData;
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event->write(1);
-// event->write(10);
-// event->init();
-// allData.push_back(event);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-// // First bucket added to mSkippedBuckets after flush.
-// EXPECT_EQ(1UL, valueProducer->mSkippedBuckets.size());
-//
-// // Check dump report.
-// ProtoOutputStream output;
-// std::set<string> strSet;
-// valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
-// true, FAST /* dumpLatency */, &strSet, &output);
-//
-// StatsLogReport report = outputStreamToProto(&output);
-// EXPECT_TRUE(report.has_value_metrics());
-// EXPECT_EQ(0, report.value_metrics().data_size());
-// EXPECT_EQ(1, report.value_metrics().skipped_size());
-//
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-// report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-// EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-// report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-// EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-//
-// auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-// EXPECT_EQ(BucketDropReason::DIMENSION_GUARDRAIL_REACHED, dropEvent.drop_reason());
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
-//}
-//
-///*
-// * Tests that a bucket is marked invalid when the bucket's initial pull fails.
-// */
-// TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// // First onConditionChanged
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(120);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// // Second onConditionChanged
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(130);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->mCondition = ConditionState::kTrue;
-//
-// // Bucket start.
-// vector<shared_ptr<LogEvent>> allData;
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event->write(1);
-// event->write(110);
-// event->init();
-// allData.push_back(event);
-// valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
-//
-// valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
-//
-// // Bucket end.
-// allData.clear();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event2->write(1);
-// event2->write(140);
-// event2->init();
-// allData.push_back(event2);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-// valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
-//
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-// // Contains base from last pull which was successful.
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval& curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(140, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-//
-// // Check dump report.
-// ProtoOutputStream output;
-// std::set<string> strSet;
-// valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
-// true, FAST /* dumpLatency */, &strSet, &output);
-//
-// StatsLogReport report = outputStreamToProto(&output);
-// EXPECT_TRUE(report.has_value_metrics());
-// EXPECT_EQ(0, report.value_metrics().data_size());
-// EXPECT_EQ(1, report.value_metrics().skipped_size());
-//
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-// report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-// EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-// report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-// EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-//
-// auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-// EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
-//}
-//
-///*
-// * Tests that a bucket is marked invalid when the bucket's final pull fails
-// * (i.e. failed pull on bucket boundary).
-// */
-// TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// // First onConditionChanged
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(120);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// // Second onConditionChanged
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(130);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->mCondition = ConditionState::kTrue;
-//
-// // Bucket start.
-// vector<shared_ptr<LogEvent>> allData;
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event->write(1);
-// event->write(110);
-// event->init();
-// allData.push_back(event);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-//
-// valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
-//
-// // Bucket end.
-// allData.clear();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event2->write(1);
-// event2->write(140);
-// event2->init();
-// allData.push_back(event2);
-// valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
-//
-// valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
-//
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-// // Last pull failed so base has been reset.
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval& curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-//
-// // Check dump report.
-// ProtoOutputStream output;
-// std::set<string> strSet;
-// valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
-// true, FAST /* dumpLatency */, &strSet, &output);
-//
-// StatsLogReport report = outputStreamToProto(&output);
-// EXPECT_TRUE(report.has_value_metrics());
-// EXPECT_EQ(0, report.value_metrics().data_size());
-// EXPECT_EQ(1, report.value_metrics().skipped_size());
-//
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-// report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-// EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-// report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-// EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-//
-// auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-// EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-// EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis());
-//}
-//
-// TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// // Start bucket.
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-// event->write(tagId);
-// event->write(3);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-//
-// // Bucket 2 start.
-// vector<shared_ptr<LogEvent>> allData;
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event->write(tagId);
-// event->write(110);
-// event->init();
-// allData.push_back(event);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
-//
-// // Bucket 3 empty.
-// allData.clear();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
-// event2->init();
-// allData.push_back(event2);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-// // Data has been trimmed.
-// EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-// EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
-//}
+/*
+ * Tests zero default base.
+ */
+TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ metric.set_use_zero_default_base(true);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ auto iter = valueProducer->mCurrentSlicedBucket.begin();
+ auto& interval1 = iter->second[0];
+ auto iterBase = valueProducer->mCurrentBaseInfo.begin();
+ auto& baseInfo1 = iterBase->second[0];
+ EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(3, baseInfo1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ vector<shared_ptr<LogEvent>> allData;
+
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
+
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(11, baseInfo1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(8, interval1.value.long_value);
+
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
+ if (it != iter) {
+ break;
+ }
+ }
+ auto itBase = valueProducer->mCurrentBaseInfo.begin();
+ for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
+ if (itBase != iterBase) {
+ break;
+ }
+ }
+ EXPECT_TRUE(it != iter);
+ EXPECT_TRUE(itBase != iterBase);
+ auto& interval2 = it->second[0];
+ auto& baseInfo2 = itBase->second[0];
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(4, baseInfo2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_EQ(4, interval2.value.long_value);
+
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ auto iterator = valueProducer->mPastBuckets.begin();
+ EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
+ EXPECT_EQ(8, iterator->second[0].values[0].long_value);
+ iterator++;
+ EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
+ EXPECT_EQ(4, iterator->second[0].values[0].long_value);
+}
+
+/*
+ * Tests using zero default base with failed pull.
+ */
+TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ metric.set_use_zero_default_base(true);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ auto& interval1 = it->second[0];
+ auto& baseInfo1 =
+ valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(3, baseInfo1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ vector<shared_ptr<LogEvent>> allData;
+
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
+
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(11, baseInfo1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(8, interval1.value.long_value);
+
+ auto it2 = valueProducer->mCurrentSlicedBucket.begin();
+ for (; it2 != valueProducer->mCurrentSlicedBucket.end(); it2++) {
+ if (it2 != it) {
+ break;
+ }
+ }
+ // auto itBase = valueProducer->mCurrentBaseInfo.begin();
+ // for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
+ // if (itBase != iterBase) {
+ // break;
+ // }
+ // }
+ EXPECT_TRUE(it2 != it);
+ // EXPECT_TRUE(itBase != iterBase);
+ auto& interval2 = it2->second[0];
+ auto& baseInfo2 =
+ valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
+ EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(4, baseInfo2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_EQ(4, interval2.value.long_value);
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+
+ // next pull somehow did not happen, skip to end of bucket 3
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 2, 5));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(5, baseInfo2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 13));
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 1, 5));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
+
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ it2 = std::next(valueProducer->mCurrentSlicedBucket.begin());
+ interval1 = it->second[0];
+ interval2 = it2->second[0];
+ baseInfo1 = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
+
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(5, baseInfo1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(5, interval1.value.long_value);
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(13, baseInfo2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_EQ(8, interval2.value.long_value);
+
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+}
+
+/*
+ * Tests trim unused dimension key if no new data is seen in an entire bucket.
+ */
+TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ auto iter = valueProducer->mCurrentSlicedBucket.begin();
+ auto& interval1 = iter->second[0];
+ auto iterBase = valueProducer->mCurrentBaseInfo.begin();
+ auto& baseInfo1 = iterBase->second[0];
+ EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(3, baseInfo1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ vector<shared_ptr<LogEvent>> allData;
+
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(11, baseInfo1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(8, interval1.value.long_value);
+ EXPECT_FALSE(interval1.seenNewData);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
+
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
+ if (it != iter) {
+ break;
+ }
+ }
+ auto itBase = valueProducer->mCurrentBaseInfo.begin();
+ for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
+ if (itBase != iterBase) {
+ break;
+ }
+ }
+ EXPECT_TRUE(it != iter);
+ EXPECT_TRUE(itBase != iterBase);
+ auto& interval2 = it->second[0];
+ auto& baseInfo2 = itBase->second[0];
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(4, baseInfo2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_FALSE(interval2.seenNewData);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
+
+ // next pull somehow did not happen, skip to end of bucket 3
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 2, 5));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+ // Only one interval left. One was trimmed.
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(5, baseInfo2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_FALSE(interval2.seenNewData);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
+
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 14));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
+
+ interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(14, baseInfo2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_FALSE(interval2.seenNewData);
+ ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
+ auto iterator = valueProducer->mPastBuckets.begin();
+ EXPECT_EQ(9, iterator->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
+ iterator++;
+ EXPECT_EQ(8, iterator->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ // Used by onConditionChanged.
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+
+ vector<shared_ptr<LogEvent>> allData;
+ valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(false, curBaseInfo.hasBase);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, valueProducer->mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
+ return true;
+ }))
+ .WillOnce(Return(false));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 20);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, curBaseInfo.hasBase);
+ EXPECT_EQ(false, valueProducer->mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 50));
+ return false;
+ }))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ // Don't directly set mCondition; the real code never does that. Go through regular code path
+ // to avoid unexpected behaviors.
+ // valueProducer->mCondition = ConditionState::kTrue;
+ valueProducer->onConditionChanged(true, bucketStartTimeNs);
+
+ EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, valueProducer->mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_condition(StringToId("SCREEN_ON"));
+ metric.set_max_pull_delay_sec(0);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 120));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->mCondition = ConditionState::kFalse;
+
+ // Max delay is set to 0 so pull will exceed max delay.
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
+ EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucket2StartTimeNs,
+ bucket2StartTimeNs, pullerManager);
+ valueProducer.mCondition = ConditionState::kFalse;
+
+ // Event should be skipped since it is from previous bucket.
+ // Pull should not be called.
+ valueProducer.onConditionChanged(true, bucketStartTimeNs);
+ EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+}
+
+TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->mCondition = ConditionState::kFalse;
+ valueProducer->mHasGlobalBase = false;
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
+ valueProducer->mHasGlobalBase = true;
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+}
+
+/*
+ * Tests that a bucket is marked invalid when a condition change pull fails.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // First onConditionChanged
+ .WillOnce(Return(false))
+ // Second onConditionChanged
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->mCondition = ConditionState::kTrue;
+
+ // Bucket start.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+
+ // This will fail and should invalidate the whole bucket since we do not have all the data
+ // needed to compute the metric value when the screen was on.
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
+
+ // Bucket end.
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
+
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ // Contains base from last pull which was successful.
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(140, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucket2StartTimeNs + 10, false /* include partial bucket */, true,
+ FAST /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ EXPECT_EQ(0, report.value_metrics().data_size());
+ EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+ EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
+}
+
+/*
+ * Tests that a bucket is marked invalid when the guardrail is hit.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ metric.set_condition(StringToId("SCREEN_ON"));
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // First onConditionChanged
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ for (int i = 0; i < 2000; i++) {
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i));
+ }
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ valueProducer->mCondition = ConditionState::kFalse;
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
+ EXPECT_EQ(true, valueProducer->mCurrentBucketIsInvalid);
+ EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(0UL, valueProducer->mSkippedBuckets.size());
+
+ // Bucket 2 start.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 10));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ // First bucket added to mSkippedBuckets after flush.
+ EXPECT_EQ(1UL, valueProducer->mSkippedBuckets.size());
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
+ true, FAST /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ EXPECT_EQ(0, report.value_metrics().data_size());
+ EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+ EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::DIMENSION_GUARDRAIL_REACHED, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
+}
+
+/*
+ * Tests that a bucket is marked invalid when the bucket's initial pull fails.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // First onConditionChanged
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120));
+ return true;
+ }))
+ // Second onConditionChanged
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->mCondition = ConditionState::kTrue;
+
+ // Bucket start.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 1, 1, 110));
+ valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
+
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
+
+ // Bucket end.
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 140));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
+
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ // Contains base from last pull which was successful.
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(140, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
+ true, FAST /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ EXPECT_EQ(0, report.value_metrics().data_size());
+ EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+ EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
+}
+
+/*
+ * Tests that a bucket is marked invalid when the bucket's final pull fails
+ * (i.e. failed pull on bucket boundary).
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // First onConditionChanged
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120));
+ return true;
+ }))
+ // Second onConditionChanged
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->mCondition = ConditionState::kTrue;
+
+ // Bucket start.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
+
+ // Bucket end.
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140));
+ valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
+
+ valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
+
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ // Last pull failed so base has been reset.
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, valueProducer->mHasGlobalBase);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
+ true, FAST /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ EXPECT_EQ(0, report.value_metrics().data_size());
+ EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+ EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis());
+}
+
+TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Start bucket.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ // Bucket 2 start.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+
+ // Bucket 3 empty.
+ allData.clear();
+ allData.push_back(CreateNoValuesLogEvent(tagId, bucket3StartTimeNs + 1));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ // Data has been trimmed.
+ EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+}
TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();