Add unit tests for CountMetricProducer, EventMetricProducer
And other miscellaneous fixes.
+ clang-format
+ 2 bug fixes, one in dump-report command, one in ResourcePowerManagerPuller
Test: statsd_test
Change-Id: Ibd164d948ad62adcc529d813df1210781e38be47
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index fdfe8ef..d0898b0 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -42,7 +42,7 @@
auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
simpleMatcher->set_tag(TAG_ID);
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
// Convert to a LogEvent
event.init();
@@ -62,7 +62,7 @@
keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << true;
*list << false;
@@ -98,7 +98,7 @@
keyValue->set_eq_string("some value");
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << "some value";
@@ -119,7 +119,7 @@
keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << 11;
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
new file mode 100644
index 0000000..5a4ee73
--- /dev/null
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -0,0 +1,183 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "metrics_test_helper.h"
+#include "src/metrics/CountMetricProducer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+ int tagId = 1;
+
+ CountMetric metric;
+ metric.set_metric_id(1);
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+
+ LogEvent event1(tagId, bucketStartTimeNs + 1);
+ LogEvent event2(tagId, bucketStartTimeNs + 2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs);
+
+ // 2 events in bucket 1.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2, false);
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(2LL, bucketInfo.mCount);
+
+ // 1 matched event happens in bucket 2.
+ LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3, false);
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY].size());
+ const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY][1];
+ EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
+ EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo2.mCount);
+
+ // nothing happens in bucket 3. we should not record anything for bucket 3.
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(2UL, buckets3.size());
+}
+
+TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ CountMetric metric;
+ metric.set_metric_id(1);
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_condition("SCREEN_ON");
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ LogEvent event2(1, bucketStartTimeNs + 10);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(metric, 1, wizard, bucketStartTimeNs);
+
+ countProducer.onConditionChanged(true, bucketStartTimeNs);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ CountMetric metric;
+ metric.set_metric_id(1);
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+ EventConditionLink* link = metric.add_links();
+ link->set_condition("APP_IN_BACKGROUND_PER_UID");
+ link->add_key_in_main()->set_key(1);
+ link->add_key_in_condition()->set_key(2);
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ auto list = event1.GetAndroidLogEventList();
+ *list << "111"; // uid
+ event1.init();
+ ConditionKey key1;
+ key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
+
+ LogEvent event2(1, bucketStartTimeNs + 10);
+ auto list2 = event2.GetAndroidLogEventList();
+ *list2 << "222"; // uid
+ event2.init();
+ ConditionKey key2;
+ key2["APP_IN_BACKGROUND_PER_UID"] = "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));
+
+ CountMetricProducer countProducer(metric, 1 /*condition tracker index*/, wizard,
+ bucketStartTimeNs);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2, false);
+
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
new file mode 100644
index 0000000..76dbc73
--- /dev/null
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -0,0 +1,130 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "metrics_test_helper.h"
+#include "src/metrics/EventMetricProducer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(EventMetricProducerTest, TestNoCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_metric_id(1);
+
+ LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1);
+ LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ EventMetricProducer eventProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_metric_id(1);
+ metric.set_condition("SCREEN_ON");
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ LogEvent event2(1, bucketStartTimeNs + 10);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs);
+
+ eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+
+ eventProducer.onConditionChanged(false /*condition*/, bucketStartTimeNs + 2);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_metric_id(1);
+ metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+ EventConditionLink* link = metric.add_links();
+ link->set_condition("APP_IN_BACKGROUND_PER_UID");
+ link->add_key_in_main()->set_key(1);
+ link->add_key_in_condition()->set_key(2);
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ auto list = event1.GetAndroidLogEventList();
+ *list << "111"; // uid
+ event1.init();
+ ConditionKey key1;
+ key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
+
+ LogEvent event2(1, bucketStartTimeNs + 10);
+ auto list2 = event2.GetAndroidLogEventList();
+ *list2 << "222"; // uid
+ event2.init();
+ ConditionKey key2;
+ key2["APP_IN_BACKGROUND_PER_UID"] = "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(metric, 1, wizard, bucketStartTimeNs);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
similarity index 92%
rename from cmds/statsd/tests/MaxDurationTracker_test.cpp
rename to cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index ae8bf42..f2abe7b 100644
--- a/cmds/statsd/tests/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
+#include "metrics_test_helper.h"
#include "src/condition/ConditionWizard.h"
#include "src/metrics/duration_helper/MaxDurationTracker.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include <stdio.h>
#include <set>
#include <unordered_map>
@@ -32,13 +32,9 @@
#ifdef __ANDROID__
-class MockConditionWizard : public ConditionWizard {
-public:
- MOCK_METHOD2(
- query,
- ConditionState(const int conditionIndex,
- const std::map<std::string, HashableDimensionKey>& conditionParameters));
-};
+namespace android {
+namespace os {
+namespace statsd {
TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -110,6 +106,9 @@
EXPECT_EQ(5, buckets[0].duration_nanos());
}
+} // namespace statsd
+} // namespace os
+} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
similarity index 90%
rename from cmds/statsd/tests/OringDurationTracker_test.cpp
rename to cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 0b79819..338d55d 100644
--- a/cmds/statsd/tests/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -12,18 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
+#include "metrics_test_helper.h"
#include "src/condition/ConditionWizard.h"
#include "src/metrics/duration_helper/OringDurationTracker.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include <stdio.h>
#include <set>
#include <unordered_map>
#include <vector>
-using namespace android::os::statsd;
using namespace testing;
using android::sp;
using std::set;
@@ -31,14 +30,9 @@
using std::vector;
#ifdef __ANDROID__
-
-class MockConditionWizard : public ConditionWizard {
-public:
- MOCK_METHOD2(
- query,
- ConditionState(const int conditionIndex,
- const std::map<std::string, HashableDimensionKey>& conditionParameters));
-};
+namespace android {
+namespace os {
+namespace statsd {
TEST(OringDurationTrackerTest, TestDurationOverlap) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -93,7 +87,9 @@
EXPECT_EQ(1u, buckets.size());
EXPECT_EQ(5, buckets[0].duration_nanos());
}
-
+} // namespace statsd
+} // namespace os
+} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
new file mode 100644
index 0000000..5fd7d62
--- /dev/null
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include "src/condition/ConditionWizard.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class MockConditionWizard : public ConditionWizard {
+public:
+ MOCK_METHOD2(
+ query,
+ ConditionState(const int conditionIndex,
+ const std::map<std::string, HashableDimensionKey>& conditionParameters));
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android