From d5800b208e4ce8ca154811a6b106b7fc624c9e35 Mon Sep 17 00:00:00 2001 From: tsaichristine Date: Wed, 25 Mar 2020 10:31:50 -0700 Subject: [PATCH] Update unit tests to use new socket schema I forgot to update Gauge and EventMetricProducer unit test files to use the new socket schema. The EventMetric tests were also incomplete so I added test code to output the dump report and check its contents. Test: bit statsd_test:* Bug: 149590301 && 110561136 Change-Id: I685688285d9890cf7c5bd3ffc43f13cbbb8f93de --- .../metrics/EventMetricProducer_test.cpp | 152 +- .../metrics/GaugeMetricProducer_test.cpp | 1465 ++++++++--------- cmds/statsd/tests/statsd_test_util.cpp | 14 +- cmds/statsd/tests/statsd_test_util.h | 2 + 4 files changed, 818 insertions(+), 815 deletions(-) diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp index 0f39efd51b580..e58bbb7893d75 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 #include #include + #include +#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 @@ namespace statsd { 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 @@ TEST(EventMetricProducerTest, TestNoCondition) { 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 wizard = new NaggyMock(); @@ -54,8 +76,17 @@ TEST(EventMetricProducerTest, TestNoCondition) { 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 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 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) { 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 wizard = new NaggyMock(); @@ -81,51 +115,67 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) { 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 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 wizard = new NaggyMock(); -// 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 wizard = new NaggyMock(); + // 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 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 609324e91daa2..d372ffd7e6896 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 bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs; const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; +namespace { +shared_ptr 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 = std::make_shared(/*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 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) { 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 wizard = new NaggyMock(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp pullerManager = new StrictMock(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(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> allData; -// allData.clear(); -// shared_ptr event = make_shared(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 event2 = std::make_shared(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; -// 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 wizard = new NaggyMock(); -// sp pullerManager = new StrictMock(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp 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 = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); -// EXPECT_TRUE(anomalyTracker != nullptr); -// -// shared_ptr event1 = make_shared(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 event2 = make_shared(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 event3 = make_shared(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 event4 = -// make_shared(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 wizard = new NaggyMock(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp eventMatcherWizard = -// new EventMatcherWizard({new SimpleLogMatchingTracker( -// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp pullerManager = new StrictMock(); -// 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>* data) { -// data->clear(); -// shared_ptr event = make_shared(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> allData; -// shared_ptr event = make_shared(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(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 wizard = new NaggyMock(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp pullerManager = new StrictMock(); -// 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> allData; -// shared_ptr event = make_shared(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 wizard = new NaggyMock(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp pullerManager = new StrictMock(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(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> allData; -// allData.clear(); -// shared_ptr event = make_shared(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 = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp wizard = new NaggyMock(); -// 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 pullerManager = new StrictMock(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(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> allData; -// allData.clear(); -// shared_ptr event = make_shared(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; -// sp wizard = new NaggyMock(); -// -// sp pullerManager = new StrictMock(); -// 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 = 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 = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); -// -// int tagId = 1; -// std::shared_ptr event1 = std::make_shared(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 event2 = -// std::make_shared(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 event3 = -// std::make_shared(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 event4 = -// std::make_shared(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 wizard = new NaggyMock(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp pullerManager = new StrictMock(); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(tagId, bucketStartTimeNs + 10); -// event->write(4); -// event->init(); -// data->push_back(event); -// return true; -// })) -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(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> 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 wizard = new NaggyMock(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp pullerManager = new StrictMock(); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(tagId, bucketStartTimeNs + 3); -// event->write(3); -// event->write(4); -// event->init(); -// data->push_back(event); -// return true; -// })) -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(tagId, bucketStartTimeNs + 10); -// event->write(4); -// event->write(5); -// event->init(); -// data->push_back(event); -// return true; -// })) -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(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> 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 wizard = new NaggyMock(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp pullerManager = new StrictMock(); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// // Bucket start. -// .WillOnce(Invoke([](int tagId, vector>* data) { -// data->clear(); -// shared_ptr event = make_shared(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 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 wizard = new NaggyMock(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp pullerManager = new StrictMock(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector>* 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> 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; + 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 wizard = new NaggyMock(); + sp pullerManager = new StrictMock(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp 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 = 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 wizard = new NaggyMock(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp pullerManager = new StrictMock(); + 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>* 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> 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 wizard = new NaggyMock(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp pullerManager = new StrictMock(); + 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> 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 wizard = new NaggyMock(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp pullerManager = new StrictMock(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector>* 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> 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 = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp wizard = new NaggyMock(); + 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 pullerManager = new StrictMock(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector>* 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> 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; + sp wizard = new NaggyMock(); + + sp pullerManager = new StrictMock(); + 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 = + 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 = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); + + int tagId = 1; + vector> 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 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 wizard = new NaggyMock(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp pullerManager = new StrictMock(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector>* data) { + data->clear(); + data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 4)); + return true; + })) + .WillOnce(Invoke([](int tagId, vector>* 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 wizard = new NaggyMock(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp pullerManager = new StrictMock(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector>* data) { + data->clear(); + data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 3, 3, 4)); + return true; + })) + .WillOnce(Invoke([](int tagId, vector>* data) { + data->clear(); + data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 4, 5)); + return true; + })) + .WillOnce(Invoke([](int tagId, vector>* 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 wizard = new NaggyMock(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp pullerManager = new StrictMock(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // Bucket start. + .WillOnce(Invoke([](int tagId, vector>* 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 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 c7838fcddb532..8c8836b94f568 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -428,7 +428,7 @@ shared_ptr CreateTwoValueLogEvent(int atomId, int64_t eventTimeNs, int 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 @@ shared_ptr CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs) { 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 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 05e1572e3aa9e..7c017554d511e 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -187,6 +187,8 @@ void CreateRepeatedValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTi std::shared_ptr 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 CreateScreenStateChangedEvent( uint64_t timestampNs, const android::view::DisplayStateEnum state);