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