Merge "Update unit tests to use new socket schema" into rvc-dev
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 0f39efd5..e58bbb7 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -13,14 +13,17 @@
 // limitations under the License.
 
 #include "src/metrics/EventMetricProducer.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <stdio.h>
+
 #include <vector>
 
+#include "metrics_test_helper.h"
+#include "stats_event.h"
+#include "tests/statsd_test_util.h"
+
 using namespace testing;
 using android::sp;
 using std::set;
@@ -35,6 +38,22 @@
 
 const ConfigKey kConfigKey(0, 12345);
 
+namespace {
+void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, string str) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeString(statsEvent, str.c_str());
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+}
+}  // anonymous namespace
+
 TEST(EventMetricProducerTest, TestNoCondition) {
     int64_t bucketStartTimeNs = 10000000000;
     int64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -43,8 +62,11 @@
     EventMetric metric;
     metric.set_id(1);
 
-    LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1);
-    LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2);
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 2);
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
@@ -54,8 +76,17 @@
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
 
-    // TODO(b/110561136): get the report and check the content after the ProtoOutputStream change
-    // is done eventProducer.onDumpReport();
+    // Check dump report content.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+                               true /*erase data*/, FAST, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_event_metrics());
+    EXPECT_EQ(2, report.event_metrics().data_size());
+    EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 2, report.event_metrics().data(1).elapsed_timestamp_nanos());
 }
 
 TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
@@ -67,8 +98,11 @@
     metric.set_id(1);
     metric.set_condition(StringToId("SCREEN_ON"));
 
-    LogEvent event1(1, bucketStartTimeNs + 1);
-    LogEvent event2(1, bucketStartTimeNs + 10);
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10);
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
@@ -81,51 +115,67 @@
 
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
 
-    // TODO: get the report and check the content after the ProtoOutputStream change is done.
-    // eventProducer.onDumpReport();
+    // Check dump report content.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+                               true /*erase data*/, FAST, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_event_metrics());
+    EXPECT_EQ(1, report.event_metrics().data_size());
+    EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
 }
 
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-//
-//    int tagId = 1;
-//    int conditionTagId = 2;
-//
-//    EventMetric metric;
-//    metric.set_id(1);
-//    metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
-//    MetricConditionLink* link = metric.add_links();
-//    link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
-//    buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
-//    buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
-//
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    EXPECT_TRUE(event1.write("111"));
-//    event1.init();
-//    ConditionKey key1;
-//    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "111")};
-//
-//    LogEvent event2(tagId, bucketStartTimeNs + 10);
-//    EXPECT_TRUE(event2.write("222"));
-//    event2.init();
-//    ConditionKey key2;
-//    key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")};
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
-//
-//    EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
-//
-//    EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
-//
-//    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-//    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-//
-//    // TODO: get the report and check the content after the ProtoOutputStream change is done.
-//    // eventProducer.onDumpReport();
-//}
+TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+    int tagId = 1;
+    int conditionTagId = 2;
+
+    EventMetric metric;
+    metric.set_id(1);
+    metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
+    MetricConditionLink* link = metric.add_links();
+    link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
+    buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
+    buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1, "111");
+    ConditionKey key1;
+    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+            getMockedDimensionKey(conditionTagId, 2, "111")};
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10, "222");
+    ConditionKey key2;
+    key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+            getMockedDimensionKey(conditionTagId, 2, "222")};
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    // Condition is false for first event.
+    EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
+    // Condition is true for second event.
+    EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
+
+    EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
+
+    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
+
+    // Check dump report content.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+                               true /*erase data*/, FAST, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_event_metrics());
+    EXPECT_EQ(1, report.event_metrics().data_size());
+    EXPECT_EQ(bucketStartTimeNs + 10, report.event_metrics().data(0).elapsed_timestamp_nanos());
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 609324e..d372ffd 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -26,6 +26,7 @@
 #include "src/matchers/SimpleLogMatchingTracker.h"
 #include "src/metrics/MetricProducer.h"
 #include "src/stats_log_util.h"
+#include "stats_event.h"
 #include "tests/statsd_test_util.h"
 
 using namespace testing;
@@ -53,6 +54,28 @@
 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
 const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
 
+namespace {
+shared_ptr<LogEvent> makeLogEvent(int32_t atomId, int64_t timestampNs, int32_t value1, string str1,
+                                  int32_t value2) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, value1);
+    AStatsEvent_writeString(statsEvent, str1.c_str());
+    AStatsEvent_writeInt32(statsEvent, value2);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+
+    return logEvent;
+}
+}  // anonymous namespace
+
 /*
  * Tests that the first bucket works correctly
  */
@@ -88,769 +111,685 @@
     EXPECT_EQ(660000000005, gaugeProducer.getCurrentBucketEndTimeNs());
 }
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.mutable_gauge_fields_filter()->set_include_all(false);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(1);
-//    gaugeFieldMatcher->add_child()->set_field(3);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    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 + 10);
-//                event->write(3);
-//                event->write("some value");
-//                event->write(11);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write(10);
-//    event->write("some value");
-//    event->write(11);
-//    event->init();
-//    allData.push_back(event);
-//
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(10, it->mValue.int_value);
-//    it++;
-//    EXPECT_EQ(11, it->mValue.int_value);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms
-//        .front().mFields->begin()->mValue.int_value);
-//
-//    allData.clear();
-//    std::shared_ptr<LogEvent> event2 = std::make_shared<LogEvent>(tagId, bucket3StartTimeNs + 10);
-//    event2->write(24);
-//    event2->write("some value");
-//    event2->write(25);
-//    event2->init();
-//    allData.push_back(event2);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(24, it->mValue.int_value);
-//    it++;
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(25, it->mValue.int_value);
-//    // One dimension.
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
-//    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(10L, it->mValue.int_value);
-//    it++;
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(11L, it->mValue.int_value);
-//
-//    gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
-//    EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    // One dimension.
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
-//    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(24L, it->mValue.int_value);
-//    it++;
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(25L, it->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
-//    sp<AlarmMonitor> alarmMonitor;
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.mutable_gauge_fields_filter()->set_include_all(true);
-//
-//    Alert alert;
-//    alert.set_id(101);
-//    alert.set_metric_id(metricId);
-//    alert.set_trigger_if_sum_gt(25);
-//    alert.set_num_buckets(100);
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
-//    EXPECT_TRUE(anomalyTracker != nullptr);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    // Partial buckets are not sent to anomaly tracker.
-//    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    // Create an event in the same partial bucket.
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
-//    event2->write(1);
-//    event2->write(10);
-//    event2->init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    // Partial buckets are not sent to anomaly tracker.
-//    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    // Next event should trigger creation of new bucket and send previous full bucket to anomaly
-//    // tracker.
-//    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
-//    event3->write(1);
-//    event3->write(10);
-//    event3->init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-//    EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    // Next event should trigger creation of new bucket.
-//    shared_ptr<LogEvent> event4 =
-//            make_shared<LogEvent>(tagId, bucketStartTimeNs + 125 * NS_PER_SEC);
-//    event4->write(1);
-//    event4->write(10);
-//    event4->init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-//    EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(2);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard =
-//            new EventMatcherWizard({new SimpleLogMatchingTracker(
-//                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Return(false))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs);
-//                event->write("some value");
-//                event->write(2);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-//                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-//    event->write("some value");
-//    event->write(1);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//
-//    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-//    event->write("some value");
-//    event->write(3);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    metric.set_split_bucket_for_app_upgrade(false);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(2);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-//    event->write("some value");
-//    event->write(1);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//
-//    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(2);
-//    metric.set_condition(StringToId("SCREEN_ON"));
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    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 + 10);
-//                event->write("some value");
-//                event->write(100);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-//                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-//    gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write("some value");
-//    event->write(110);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
-//                           ->second.back()
-//                           .mGaugeAtoms.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//
-//    gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
-//    gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
-//    EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
-//                            ->second.back()
-//                            .mGaugeAtoms.front()
-//                            .mFields->begin()
-//                            ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
-//    const int conditionTag = 65;
-//    GaugeMetric metric;
-//    metric.set_id(1111111);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.mutable_gauge_fields_filter()->set_include_all(true);
-//    metric.set_condition(StringToId("APP_DIED"));
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto dim = metric.mutable_dimensions_in_what();
-//    dim->set_field(tagId);
-//    dim->add_child()->set_field(1);
-//
-//    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>();
-//    EXPECT_CALL(*wizard, query(_, _, _))
-//            .WillRepeatedly(
-//                    Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
-//                              const bool isPartialLink) {
-//                        int pos[] = {1, 0, 0};
-//                        Field f(conditionTag, pos, 0);
-//                        HashableDimensionKey key;
-//                        key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
-//
-//                        return ConditionState::kTrue;
-//                    }));
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    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 + 10);
-//                event->write(1000);
-//                event->write(100);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-//                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-//    gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
-//
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
-//    EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
-//    EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-//
-//    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write(1000);
-//    event->write(110);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
-//    sp<AlarmMonitor> alarmMonitor;
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-//
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(2);
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    Alert alert;
-//    alert.set_id(101);
-//    alert.set_metric_id(metricId);
-//    alert.set_trigger_if_sum_gt(25);
-//    alert.set_num_buckets(2);
-//    const int32_t refPeriodSec = 60;
-//    alert.set_refractory_period_secs(refPeriodSec);
-//    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
-//
-//    int tagId = 1;
-//    std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-//    event1->write("some value");
-//    event1->write(13);
-//    event1->init();
-//
-//    gaugeProducer.onDataPulled({event1}, /** succeed */ true, bucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-//    std::shared_ptr<LogEvent> event2 =
-//            std::make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 20);
-//    event2->write("some value");
-//    event2->write(15);
-//    event2->init();
-//
-//    gaugeProducer.onDataPulled({event2}, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
-//
-//    std::shared_ptr<LogEvent> event3 =
-//            std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
-//    event3->write("some value");
-//    event3->write(26);
-//    event3->init();
-//
-//    gaugeProducer.onDataPulled({event3}, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//
-//    // The event4 does not have the gauge field. Thus the current bucket value is 0.
-//    std::shared_ptr<LogEvent> event4 =
-//            std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10);
-//    event4->write("some value");
-//    event4->init();
-//    gaugeProducer.onDataPulled({event4}, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-//    metric.mutable_gauge_fields_filter()->set_include_all(false);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(1);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    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 + 10);
-//                event->write(4);
-//                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, bucketStartTimeNs + 20);
-//                event->write(5);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            .WillOnce(Return(true));
-//
-//    int triggerId = 5;
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//
-//    EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    LogEvent trigger(triggerId, bucketStartTimeNs + 10);
-//    trigger.init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-//    trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-//    trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
-//    EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
-//                         ->second.back()
-//                         .mGaugeAtoms[0]
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//    EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
-//                         ->second.back()
-//                         .mGaugeAtoms[1]
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-//    metric.mutable_gauge_fields_filter()->set_include_all(true);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto dimensionMatcher = metric.mutable_dimensions_in_what();
-//    // use field 1 as dimension.
-//    dimensionMatcher->set_field(tagId);
-//    dimensionMatcher->add_child()->set_field(1);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    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 + 3);
-//                event->write(3);
-//                event->write(4);
-//                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, bucketStartTimeNs + 10);
-//                event->write(4);
-//                event->write(5);
-//                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, bucketStartTimeNs + 20);
-//                event->write(4);
-//                event->write(6);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            .WillOnce(Return(true));
-//
-//    int triggerId = 5;
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//
-//    LogEvent trigger(triggerId, bucketStartTimeNs + 3);
-//    trigger.init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    trigger.setElapsedTimestampNs(bucketStartTimeNs + 10);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-//    trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-//    trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
-//    auto bucketIt = gaugeProducer.mPastBuckets.begin();
-//    EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
-//    EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
-//    EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
-//    bucketIt++;
-//    EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
-//    EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
-//    EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
-//    EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
-//}
-//
-///*
-// * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
-// * is smaller than the "min_bucket_size_nanos" specified in the metric config.
-// */
-//TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(FIVE_MINUTES);
-//    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-//    metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            // Bucket start.
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-//                event->write("field1");
-//                event->write(10);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    int triggerId = 5;
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    LogEvent trigger(triggerId, bucketStartTimeNs + 3);
-//    trigger.init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-//    // Check dump report.
-//    ProtoOutputStream output;
-//    std::set<string> strSet;
-//    gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */,
-//                                true, FAST /* dump_latency */, &strSet, &output);
-//
-//    StatsLogReport report = outputStreamToProto(&output);
-//    EXPECT_TRUE(report.has_gauge_metrics());
-//    EXPECT_EQ(0, report.gauge_metrics().data_size());
-//    EXPECT_EQ(1, report.gauge_metrics().skipped_size());
-//
-//    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-//              report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
-//    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
-//              report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
-//    EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
-//
-//    auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
-//    EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
-//    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
-//}
+TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_gauge_fields_filter()->set_include_all(false);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(1);
+    gaugeFieldMatcher->add_child()->set_field(3);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(makeLogEvent(tagId, bucketStartTimeNs + 10, 3, "some value", 11));
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(makeLogEvent(tagId, bucket2StartTimeNs + 1, 10, "some value", 11));
+
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(10, it->mValue.int_value);
+    it++;
+    EXPECT_EQ(11, it->mValue.int_value);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()
+                         ->second.back()
+                         .mGaugeAtoms.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    allData.clear();
+    allData.push_back(makeLogEvent(tagId, bucket3StartTimeNs + 10, 24, "some value", 25));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(24, it->mValue.int_value);
+    it++;
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(25, it->mValue.int_value);
+    // One dimension.
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
+    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(10L, it->mValue.int_value);
+    it++;
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(11L, it->mValue.int_value);
+
+    gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
+    EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
+    // One dimension.
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
+    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(24L, it->mValue.int_value);
+    it++;
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(25L, it->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
+    sp<AlarmMonitor> alarmMonitor;
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_gauge_fields_filter()->set_include_all(true);
+
+    Alert alert;
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
+    alert.set_trigger_if_sum_gt(25);
+    alert.set_num_buckets(100);
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard,
+                                      -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
+    EXPECT_TRUE(anomalyTracker != nullptr);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    // Partial buckets are not sent to anomaly tracker.
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Create an event in the same partial bucket.
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    // Partial buckets are not sent to anomaly tracker.
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Next event should trigger creation of new bucket and send previous full bucket to anomaly
+    // tracker.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Next event should trigger creation of new bucket.
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 125 * NS_PER_SEC, 1, 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+    EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Return(false))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, eventUpgradeTimeNs, 2));
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 1, 3));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    metric.set_split_bucket_for_app_upgrade(false);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 100));
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
+                           ->second.back()
+                           .mGaugeAtoms.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+
+    gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
+    gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
+                            ->second.back()
+                            .mGaugeAtoms.front()
+                            .mFields->begin()
+                            ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
+    const int conditionTag = 65;
+    GaugeMetric metric;
+    metric.set_id(1111111);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_gauge_fields_filter()->set_include_all(true);
+    metric.set_condition(StringToId("APP_DIED"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto dim = metric.mutable_dimensions_in_what();
+    dim->set_field(tagId);
+    dim->add_child()->set_field(1);
+
+    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>();
+    EXPECT_CALL(*wizard, query(_, _, _))
+            .WillRepeatedly(
+                    Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
+                              const bool isPartialLink) {
+                        int pos[] = {1, 0, 0};
+                        Field f(conditionTag, pos, 0);
+                        HashableDimensionKey key;
+                        key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
+
+                        return ConditionState::kTrue;
+                    }));
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 1000, 100));
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
+
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
+    EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+
+    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1000, 110));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
+    sp<AlarmMonitor> alarmMonitor;
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
+
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    Alert alert;
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
+    alert.set_trigger_if_sum_gt(25);
+    alert.set_num_buckets(2);
+    const int32_t refPeriodSec = 60;
+    alert.set_refractory_period_secs(refPeriodSec);
+    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
+
+    int tagId = 1;
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 13));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+    std::shared_ptr<LogEvent> event2 =
+            CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 20, 15);
+
+    allData.clear();
+    allData.push_back(event2);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
+
+    allData.clear();
+    allData.push_back(
+            CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10, 26));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+
+    // This event does not have the gauge field. Thus the current bucket value is 0.
+    allData.clear();
+    allData.push_back(CreateNoValuesLogEvent(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
+}
+
+TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+    metric.mutable_gauge_fields_filter()->set_include_all(false);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(1);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    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 + 10, 4));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 5));
+                return true;
+            }))
+            .WillOnce(Return(true));
+
+    int triggerId = 5;
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
+
+    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+    triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
+    EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
+                         ->second.back()
+                         .mGaugeAtoms[0]
+                         .mFields->begin()
+                         ->mValue.int_value);
+    EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
+                         ->second.back()
+                         .mGaugeAtoms[1]
+                         .mFields->begin()
+                         ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+    metric.mutable_gauge_fields_filter()->set_include_all(true);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto dimensionMatcher = metric.mutable_dimensions_in_what();
+    // use field 1 as dimension.
+    dimensionMatcher->set_field(tagId);
+    dimensionMatcher->add_child()->set_field(1);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    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 + 3, 3, 4));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 4, 5));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 4, 6));
+                return true;
+            }))
+            .WillOnce(Return(true));
+
+    int triggerId = 5;
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+    triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
+    auto bucketIt = gaugeProducer.mPastBuckets.begin();
+    EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
+    EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
+    EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
+    bucketIt++;
+    EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
+    EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
+    EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
+    EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
+}
+
+/*
+ * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
+ * is smaller than the "min_bucket_size_nanos" specified in the metric config.
+ */
+TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(FIVE_MINUTES);
+    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+    metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Bucket start.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 10));
+                return true;
+            }));
+
+    int triggerId = 5;
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */, true,
+                               FAST /* dump_latency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_gauge_metrics());
+    EXPECT_EQ(0, report.gauge_metrics().data_size());
+    EXPECT_EQ(1, report.gauge_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
+              report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index c7838fc..8c8836b 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -428,7 +428,7 @@
 
     return logEvent;
 }
-//
+
 void CreateTwoValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1,
                             int32_t value2) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
@@ -531,6 +531,18 @@
     return logEvent;
 }
 
+void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+}
+
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
         uint64_t timestampNs, const android::view::DisplayStateEnum state) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 05e1572..7c01755 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -187,6 +187,8 @@
 
 std::shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs);
 
+void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs);
+
 // Create log event for screen state changed.
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
         uint64_t timestampNs, const android::view::DisplayStateEnum state);