Merge "Add a condition timer to track the duration of condition being true." into qt-dev

am: 32fa3c237d

Change-Id: Iae054510fb5511290fc51c4b2bccd8f99ccc20e4
This commit is contained in:
Yao Chen
2019-04-10 22:22:37 -07:00
committed by android-build-merger
7 changed files with 301 additions and 57 deletions

View File

@@ -235,6 +235,7 @@ cc_test {
"tests/condition/CombinationConditionTracker_test.cpp",
"tests/condition/SimpleConditionTracker_test.cpp",
"tests/condition/StateTracker_test.cpp",
"tests/condition/ConditionTimer_test.cpp",
"tests/metrics/OringDurationTracker_test.cpp",
"tests/metrics/MaxDurationTracker_test.cpp",
"tests/metrics/CountMetricProducer_test.cpp",

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <gtest/gtest_prod.h>
#include <stdint.h>
namespace android {
namespace os {
namespace statsd {
/**
* A simple stopwatch to time the duration of condition being true.
*
* The owner of the stopwatch (MetricProducer) is responsible to notify the stopwatch when condition
* changes (start/pause), and when to start a new bucket (a new lap basically). All timestamps
* should be elapsedRealTime in nano seconds.
*
* Keep the timer simple and inline everything. This class is *NOT* thread safe. Caller is
* responsible for thread safety.
*/
class ConditionTimer {
public:
explicit ConditionTimer(bool initCondition, int64_t bucketStartNs) : mCondition(initCondition) {
if (initCondition) {
mLastConditionTrueTimestampNs = bucketStartNs;
}
};
// Tracks how long the condition has been stayed true in the *current* bucket.
// When a new bucket is created, this value will be reset to 0.
int64_t mTimerNs = 0;
// Last elapsed real timestamp when condition turned to true
// When a new bucket is created and the condition is true, then the timestamp is set
// to be the bucket start timestamp.
int64_t mLastConditionTrueTimestampNs = 0;
bool mCondition = false;
int64_t newBucketStart(int64_t nextBucketStartNs) {
if (mCondition) {
mTimerNs += (nextBucketStartNs - mLastConditionTrueTimestampNs);
mLastConditionTrueTimestampNs = nextBucketStartNs;
}
int64_t temp = mTimerNs;
mTimerNs = 0;
return temp;
}
void onConditionChanged(bool newCondition, int64_t timestampNs) {
if (newCondition == mCondition) {
return;
}
mCondition = newCondition;
if (newCondition) {
mLastConditionTrueTimestampNs = timestampNs;
} else {
mTimerNs += (timestampNs - mLastConditionTrueTimestampNs);
}
}
FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_False);
FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_True);
};
} // namespace statsd
} // namespace os
} // namespace android

View File

@@ -72,6 +72,7 @@ const int FIELD_ID_VALUES = 9;
const int FIELD_ID_BUCKET_NUM = 4;
const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
const int FIELD_ID_CONDITION_TRUE_NS = 10;
const Value ZERO_LONG((int64_t)0);
const Value ZERO_DOUBLE((int64_t)0);
@@ -107,7 +108,8 @@ ValueMetricProducer::ValueMetricProducer(
mCurrentBucketIsInvalid(false),
mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
: StatsdStats::kPullMaxDelayNs),
mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()) {
mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()),
mConditionTimer(mCondition == ConditionState::kTrue, timeBaseNs) {
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
@@ -153,6 +155,7 @@ ValueMetricProducer::ValueMetricProducer(
// flushIfNeeded to adjust start and end to bucket boundaries.
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
mConditionTimer.newBucketStart(mCurrentBucketStartTimeNs);
// Kicks off the puller immediately if condition is true and diff based.
if (mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
pullAndMatchEventsLocked(startTimeNs, mCondition);
@@ -293,6 +296,11 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
(long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
}
// only write the condition timer value if the metric has a condition.
if (mConditionTrackerIndex >= 0) {
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_TRUE_NS,
(long long)bucket.mConditionTrueNs);
}
for (int i = 0; i < (int)bucket.valueIndex.size(); i ++) {
int index = bucket.valueIndex[i];
const Value& value = bucket.values[i];
@@ -386,19 +394,19 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition,
resetBase();
}
mCondition = newCondition;
} else {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
invalidateCurrentBucket();
// Something weird happened. If we received another event if the future, the condition might
// Something weird happened. If we received another event in the future, the condition might
// be wrong.
mCondition = initialCondition(mConditionTrackerIndex);
}
// This part should alway be called.
flushIfNeededLocked(eventTimeNs);
mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
}
void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition) {
@@ -799,12 +807,14 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
(int)mCurrentSlicedBucket.size());
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
int64_t bucketEndTime = eventTimeNs < fullBucketEndTimeNs ? eventTimeNs : fullBucketEndTimeNs;
// Close the current bucket.
int64_t conditionTrueDuration = mConditionTimer.newBucketStart(bucketEndTime);
bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
if (isBucketLargeEnough && !mCurrentBucketIsInvalid) {
// The current bucket is large enough to keep.
for (const auto& slice : mCurrentSlicedBucket) {
ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second);
bucket.mConditionTrueNs = conditionTrueDuration;
// it will auto create new vector of ValuebucketInfo if the key is not found.
if (bucket.valueIndex.size() > 0) {
auto& bucketList = mPastBuckets[slice.first];
@@ -817,6 +827,8 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
initCurrentSlicedBucket(nextBucketStartTimeNs);
// Update the condition timer again, in case we skipped buckets.
mConditionTimer.newBucketStart(nextBucketStartTimeNs);
mCurrentBucketNum += numBucketsForward;
}

View File

@@ -19,12 +19,13 @@
#include <gtest/gtest_prod.h>
#include <utils/threads.h>
#include <list>
#include "../anomaly/AnomalyTracker.h"
#include "../condition/ConditionTracker.h"
#include "../external/PullDataReceiver.h"
#include "../external/StatsPullerManager.h"
#include "../matchers/EventMatcherWizard.h"
#include "../stats_log_util.h"
#include "anomaly/AnomalyTracker.h"
#include "condition/ConditionTimer.h"
#include "condition/ConditionTracker.h"
#include "external/PullDataReceiver.h"
#include "external/StatsPullerManager.h"
#include "matchers/EventMatcherWizard.h"
#include "stats_log_util.h"
#include "MetricProducer.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -37,6 +38,9 @@ struct ValueBucket {
int64_t mBucketEndNs;
std::vector<int> valueIndex;
std::vector<Value> values;
// If the metric has no condition, then this field is just wasted.
// When we tune statsd memory usage in the future, this is a candidate to optimize.
int64_t mConditionTrueNs;
};
@@ -228,6 +232,8 @@ private:
const bool mSplitBucketForAppUpgrade;
ConditionTimer mConditionTimer;
FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade);

View File

@@ -129,6 +129,8 @@ message ValueBucketInfo {
optional int64 start_bucket_elapsed_millis = 5;
optional int64 end_bucket_elapsed_millis = 6;
optional int64 condition_true_nanos = 10;
}
message ValueMetricData {

View File

@@ -0,0 +1,68 @@
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/condition/ConditionTimer.h"
#include <gtest/gtest.h>
#include <stdio.h>
#ifdef __ANDROID__
namespace android {
namespace os {
namespace statsd {
static int64_t time_base = 10;
static int64_t ct_start_time = 200;
TEST(ConditionTimerTest, TestTimer_Inital_False) {
ConditionTimer timer(false, time_base);
EXPECT_EQ(false, timer.mCondition);
EXPECT_EQ(0, timer.mTimerNs);
EXPECT_EQ(0, timer.newBucketStart(ct_start_time));
EXPECT_EQ(0, timer.mTimerNs);
timer.onConditionChanged(true, ct_start_time + 5);
EXPECT_EQ(ct_start_time + 5, timer.mLastConditionTrueTimestampNs);
EXPECT_EQ(true, timer.mCondition);
EXPECT_EQ(95, timer.newBucketStart(ct_start_time + 100));
EXPECT_EQ(ct_start_time + 100, timer.mLastConditionTrueTimestampNs);
EXPECT_EQ(true, timer.mCondition);
}
TEST(ConditionTimerTest, TestTimer_Inital_True) {
ConditionTimer timer(true, time_base);
EXPECT_EQ(true, timer.mCondition);
EXPECT_EQ(0, timer.mTimerNs);
EXPECT_EQ(ct_start_time - time_base, timer.newBucketStart(ct_start_time));
EXPECT_EQ(true, timer.mCondition);
EXPECT_EQ(0, timer.mTimerNs);
EXPECT_EQ(ct_start_time, timer.mLastConditionTrueTimestampNs);
timer.onConditionChanged(false, ct_start_time + 5);
EXPECT_EQ(5, timer.mTimerNs);
EXPECT_EQ(5, timer.newBucketStart(ct_start_time + 100));
EXPECT_EQ(0, timer.mTimerNs);
}
} // namespace statsd
} // namespace os
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif

View File

@@ -55,8 +55,11 @@ double epsilon = 0.001;
static void assertPastBucketValuesSingleKey(
const std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>>& mPastBuckets,
const std::initializer_list<int>& expectedValuesList) {
const std::initializer_list<int>& expectedValuesList,
const std::initializer_list<int64_t>& expectedDurationNsList) {
std::vector<int> expectedValues(expectedValuesList);
std::vector<int64_t> expectedDurationNs(expectedDurationNsList);
ASSERT_EQ(expectedValues.size(), expectedDurationNs.size());
if (expectedValues.size() == 0) {
ASSERT_EQ(0, mPastBuckets.size());
return;
@@ -69,10 +72,11 @@ static void assertPastBucketValuesSingleKey(
for (int i = 0; i < expectedValues.size(); i++) {
EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value)
<< "Values differ at index " << i;
EXPECT_EQ(expectedDurationNs[i], buckets[i].mConditionTrueNs)
<< "Condition duration value differ at index " << i;
}
}
class ValueMetricProducerTestHelper {
public:
@@ -237,6 +241,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -256,7 +261,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -275,8 +282,11 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(3UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
EXPECT_EQ(13, valueProducer->mPastBuckets.begin()->second[2].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[2].mConditionTrueNs);
}
TEST(ValueMetricProducerTest, TestPartialBucketCreated) {
@@ -326,8 +336,11 @@ TEST(ValueMetricProducerTest, TestPartialBucketCreated) {
EXPECT_EQ(2UL, buckets.size());
// Full bucket (2 - 1)
EXPECT_EQ(1, buckets[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, buckets[0].mConditionTrueNs);
// Full bucket (5 - 3)
EXPECT_EQ(3, buckets[1].values[0].long_value);
// partial bucket [bucket2StartTimeNs, bucket2StartTimeNs + 2]
EXPECT_EQ(2, buckets[1].mConditionTrueNs);
}
/*
@@ -385,6 +398,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -402,6 +416,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -420,6 +435,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
}
/*
@@ -468,6 +484,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -485,14 +502,16 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
}
/*
* Tests pulled atoms with no conditions and take zero value after reset
*/
TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
sp<ValueMetricProducer> valueProducer =
@@ -546,6 +565,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
EXPECT_EQ(26, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
}
/*
@@ -574,6 +594,15 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
event->init();
data->push_back(event);
return true;
}))
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
event->write(tagId);
event->write(180);
event->init();
data->push_back(event);
return true;
}));
sp<ValueMetricProducer> valueProducer =
@@ -598,7 +627,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
event->init();
allData.push_back(event);
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -609,7 +638,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
EXPECT_EQ(10, curInterval.value.long_value);
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -617,6 +646,9 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(false, curInterval.hasBase);
valueProducer->onConditionChanged(true, bucket3StartTimeNs + 1);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10, 20}, {bucketSizeNs - 8, 1});
}
TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
@@ -705,8 +737,7 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(20L,
valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20}, {150});
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -719,10 +750,12 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
EXPECT_EQ(bucket3StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(20L,
valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20, 30},
{150, bucketSizeNs - 150});
}
TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_split_bucket_for_app_upgrade(false);
UidMap uidMap;
@@ -791,8 +824,10 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
// Expect one full buckets already done and starting a partial bucket.
EXPECT_EQ(bucket2StartTimeNs-50, valueProducer->mCurrentBucketStartTimeNs);
EXPECT_EQ(1UL, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucketStartTimeNs, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
EXPECT_EQ(20L, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
EXPECT_EQ(bucketStartTimeNs,
valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20},
{(bucket2StartTimeNs - 100) - (bucketStartTimeNs + 1)});
EXPECT_FALSE(valueProducer->mCondition);
}
@@ -835,7 +870,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
EXPECT_EQ(30, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30});
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
@@ -872,7 +907,8 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(20, curInterval.value.long_value);
@@ -900,7 +936,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
EXPECT_EQ(50, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50});
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50}, {20});
}
TEST(ValueMetricProducerTest, TestAnomalyDetection) {
@@ -1008,7 +1044,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
// startUpdated:true sum:0 start:11
EXPECT_EQ(true, curInterval.hasBase);
@@ -1031,7 +1068,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(23, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
// pull 3 come late.
// The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -1050,7 +1087,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
}
/*
@@ -1089,7 +1126,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(100, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1098,7 +1136,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
EXPECT_EQ(false, curInterval.hasBase);
// Now the alarm is delivered.
@@ -1107,7 +1145,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(false, curInterval.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1160,7 +1198,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
// startUpdated:false sum:0 start:100
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(100, curInterval.base.long_value);
@@ -1169,7 +1208,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(false, curInterval.hasBase);
@@ -1177,7 +1216,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
// condition changed to true again, before the pull alarm is delivered
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(130, curInterval.base.long_value);
@@ -1194,12 +1233,13 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
EXPECT_EQ(140, curInterval.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
allData.clear();
allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs, 160));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30},
{bucketSizeNs - 8, bucketSizeNs - 24});
}
TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
@@ -1230,7 +1270,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1242,7 +1283,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
EXPECT_EQ(10, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10});
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
@@ -1273,7 +1314,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1335,7 +1377,9 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value - 12.5) < epsilon);
EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value -
12.5) < epsilon);
}
TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
@@ -1366,7 +1410,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1378,7 +1423,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
EXPECT_EQ(25, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25});
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
@@ -1410,7 +1455,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(10, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1449,7 +1495,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {5}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
@@ -1546,11 +1592,13 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[1].mConditionTrueNs);
EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
}
@@ -1625,8 +1673,10 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
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);
}
@@ -1795,7 +1845,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
EXPECT_FALSE(interval1.seenNewData);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
auto it = valueProducer->mCurrentSlicedBucket.begin();
for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
@@ -1810,7 +1860,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
EXPECT_EQ(4, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
// next pull somehow did not happen, skip to end of bucket 3
allData.clear();
@@ -1828,7 +1878,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
EXPECT_EQ(5, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
allData.clear();
event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
@@ -1846,8 +1896,10 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
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) {
@@ -1930,6 +1982,15 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
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);
@@ -1943,10 +2004,11 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
valueProducer->mCondition = ConditionState::kTrue;
// 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);
vector<shared_ptr<LogEvent>> allData;
valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
@@ -2406,7 +2468,7 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(1, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {1}, {bucketSizeNs - 12 + 1});
}
TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
@@ -2539,13 +2601,15 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
// Second onConditionChanged.
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 10, 5));
data->push_back(
ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 10, 5));
return true;
}))
// Third onConditionChanged.
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
data->push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 10, 7));
data->push_back(
ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 10, 7));
return true;
}));
@@ -2572,7 +2636,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
valueProducer->onConditionChanged(false, bucket3StartTimeNs + 10);
// Bucket should have been completed.
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {bucketSizeNs - 10});
}
TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff) {
@@ -2592,7 +2656,7 @@ TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// Bucket should have been completed.
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff) {
@@ -2619,7 +2683,7 @@ TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// Bucket should have been completed.
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade) {
@@ -2636,7 +2700,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade) {
// notifyAppUpgrade.
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 2, 10));
data->push_back(
ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 2, 10));
return true;
}));
@@ -2646,7 +2711,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade) {
valueProducer->notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
// Bucket should have been completed.
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
@@ -2678,6 +2743,12 @@ TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(2, curInterval.value.long_value);
vector<shared_ptr<LogEvent>> allData;
allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 1, 10));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 1);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {2});
}
TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
@@ -2724,7 +2795,7 @@ TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// There was not global base available so all buckets are invalid.
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {});
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {});
}
static StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
@@ -2890,6 +2961,7 @@ TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
EXPECT_EQ(1, report.value_metrics().data_size());
EXPECT_EQ(1, report.value_metrics().data(0).bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
EXPECT_EQ(10, report.value_metrics().data(0).bucket_info(0).condition_true_nanos());
}