Yangster-mac | 2087716 | 2017-12-22 17:19:39 -0800 | [diff] [blame] | 1 | // Copyright (C) 2017 The Android Open Source Project |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include <gtest/gtest.h> |
| 16 | |
| 17 | #include "src/StatsLogProcessor.h" |
| 18 | #include "tests/statsd_test_util.h" |
| 19 | |
| 20 | #include <vector> |
| 21 | |
| 22 | namespace android { |
| 23 | namespace os { |
| 24 | namespace statsd { |
| 25 | |
| 26 | #ifdef __ANDROID__ |
| 27 | |
| 28 | StatsdConfig CreateStatsdConfig(DurationMetric::AggregationType aggregationType) { |
| 29 | StatsdConfig config; |
| 30 | *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); |
| 31 | *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher(); |
| 32 | *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher(); |
| 33 | *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher(); |
| 34 | |
| 35 | auto screenIsOffPredicate = CreateScreenIsOffPredicate(); |
| 36 | *config.add_predicate() = screenIsOffPredicate; |
| 37 | |
| 38 | auto holdingWakelockPredicate = CreateHoldingWakelockPredicate(); |
| 39 | // The predicate is dimensioning by any attribution node and both by uid and tag. |
| 40 | *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = |
| 41 | CreateAttributionUidAndTagDimensions( |
| 42 | android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST, Position::LAST}); |
| 43 | *config.add_predicate() = holdingWakelockPredicate; |
| 44 | |
| 45 | auto durationMetric = config.add_duration_metric(); |
| 46 | durationMetric->set_name("WakelockDuration"); |
| 47 | durationMetric->set_what(holdingWakelockPredicate.name()); |
| 48 | durationMetric->set_condition(screenIsOffPredicate.name()); |
| 49 | durationMetric->set_aggregation_type(aggregationType); |
| 50 | // The metric is dimensioning by first attribution node and only by uid. |
| 51 | *durationMetric->mutable_dimensions() = |
| 52 | CreateAttributionUidDimensions( |
| 53 | android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); |
| 54 | durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000LL); |
| 55 | return config; |
| 56 | } |
| 57 | |
| 58 | TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions) { |
| 59 | ConfigKey cfgKey; |
| 60 | for (auto aggregationType : { DurationMetric::SUM, DurationMetric::MAX_SPARSE }) { |
| 61 | auto config = CreateStatsdConfig(aggregationType); |
| 62 | uint64_t bucketStartTimeNs = 10000000000; |
| 63 | uint64_t bucketSizeNs = |
| 64 | config.duration_metric(0).bucket().bucket_size_millis() * 1000 * 1000; |
| 65 | |
| 66 | auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey); |
| 67 | EXPECT_EQ(processor->mMetricsManagers.size(), 1u); |
| 68 | EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); |
| 69 | |
| 70 | auto screenTurnedOnEvent = |
| 71 | CreateScreenStateChangedEvent(ScreenStateChanged::STATE_ON, bucketStartTimeNs + 1); |
| 72 | auto screenTurnedOffEvent = |
| 73 | CreateScreenStateChangedEvent(ScreenStateChanged::STATE_OFF, bucketStartTimeNs + 200); |
| 74 | auto screenTurnedOnEvent2 = |
| 75 | CreateScreenStateChangedEvent(ScreenStateChanged::STATE_ON, |
| 76 | bucketStartTimeNs + bucketSizeNs + 500); |
| 77 | |
| 78 | std::vector<AttributionNode> attributions1 = |
| 79 | {CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"), |
| 80 | CreateAttribution(222, "GMSCoreModule2")}; |
| 81 | |
| 82 | std::vector<AttributionNode> attributions2 = |
| 83 | {CreateAttribution(111, "App2"), CreateAttribution(222, "GMSCoreModule1"), |
| 84 | CreateAttribution(222, "GMSCoreModule2")}; |
| 85 | |
| 86 | auto acquireEvent1 = CreateAcquireWakelockEvent( |
| 87 | attributions1, "wl1", bucketStartTimeNs + 2); |
| 88 | auto acquireEvent2 = CreateAcquireWakelockEvent( |
| 89 | attributions2, "wl2", bucketStartTimeNs + bucketSizeNs - 10); |
| 90 | |
| 91 | auto releaseEvent1 = CreateReleaseWakelockEvent( |
| 92 | attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2); |
| 93 | auto releaseEvent2 = CreateReleaseWakelockEvent( |
| 94 | attributions2, "wl2", bucketStartTimeNs + 2 * bucketSizeNs - 15); |
| 95 | |
| 96 | std::vector<std::unique_ptr<LogEvent>> events; |
| 97 | |
| 98 | events.push_back(std::move(screenTurnedOnEvent)); |
| 99 | events.push_back(std::move(screenTurnedOffEvent)); |
| 100 | events.push_back(std::move(screenTurnedOnEvent2)); |
| 101 | events.push_back(std::move(acquireEvent1)); |
| 102 | events.push_back(std::move(acquireEvent2)); |
| 103 | events.push_back(std::move(releaseEvent1)); |
| 104 | events.push_back(std::move(releaseEvent2)); |
| 105 | |
| 106 | sortLogEventsByTimestamp(&events); |
| 107 | |
| 108 | for (const auto& event : events) { |
| 109 | processor->OnLogEvent(*event); |
| 110 | } |
| 111 | |
| 112 | ConfigMetricsReportList reports; |
| 113 | processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports); |
| 114 | EXPECT_EQ(reports.reports_size(), 1); |
| 115 | EXPECT_EQ(reports.reports(0).metrics_size(), 1); |
| 116 | // Only 1 dimension output. The tag dimension in the predicate has been aggregated. |
| 117 | EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); |
| 118 | |
| 119 | auto data = reports.reports(0).metrics(0).duration_metrics().data(0); |
| 120 | // Validate dimension value. |
| 121 | EXPECT_EQ(data.dimension().field(), |
| 122 | android::util::WAKELOCK_STATE_CHANGED); |
| 123 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value_size(), 1); |
| 124 | // Attribution field. |
| 125 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0).field(), 1); |
| 126 | // Uid only. |
| 127 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0) |
| 128 | .value_tuple().dimensions_value_size(), 1); |
| 129 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0) |
| 130 | .value_tuple().dimensions_value(0).field(), 1); |
| 131 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0) |
| 132 | .value_tuple().dimensions_value(0).value_int(), 111); |
| 133 | // Validate bucket info. |
| 134 | EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1); |
| 135 | data = reports.reports(0).metrics(0).duration_metrics().data(0); |
| 136 | // The wakelock holding interval starts from the screen off event and to the end of the 1st |
| 137 | // bucket. |
| 138 | EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200); |
| 139 | |
| 140 | reports.Clear(); |
| 141 | processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports); |
| 142 | EXPECT_EQ(reports.reports_size(), 1); |
| 143 | EXPECT_EQ(reports.reports(0).metrics_size(), 1); |
| 144 | EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); |
| 145 | // Dump the report after the end of 2nd bucket. |
| 146 | EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2); |
| 147 | data = reports.reports(0).metrics(0).duration_metrics().data(0); |
| 148 | // Validate dimension value. |
| 149 | EXPECT_EQ(data.dimension().field(), |
| 150 | android::util::WAKELOCK_STATE_CHANGED); |
| 151 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value_size(), 1); |
| 152 | // Attribution field. |
| 153 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0).field(), 1); |
| 154 | // Uid only. |
| 155 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0) |
| 156 | .value_tuple().dimensions_value_size(), 1); |
| 157 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0) |
| 158 | .value_tuple().dimensions_value(0).field(), 1); |
| 159 | EXPECT_EQ(data.dimension().value_tuple().dimensions_value(0) |
| 160 | .value_tuple().dimensions_value(0).value_int(), 111); |
| 161 | // Two output buckets. |
| 162 | // The wakelock holding interval in the 1st bucket starts from the screen off event and to |
| 163 | // the end of the 1st bucket. |
| 164 | EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), |
| 165 | bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200)); |
| 166 | // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and |
| 167 | // ends at the second screen on event. |
| 168 | EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | #else |
| 173 | GTEST_LOG_(INFO) << "This test does nothing.\n"; |
| 174 | #endif |
| 175 | |
| 176 | } // namespace statsd |
| 177 | } // namespace os |
| 178 | } // namespace android |