Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -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 | |
Yao Chen | d5aa01b3 | 2017-12-19 16:46:36 -0800 | [diff] [blame] | 15 | #include "src/metrics/GaugeMetricProducer.h" |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 16 | #include "logd/LogEvent.h" |
| 17 | #include "metrics_test_helper.h" |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 18 | |
| 19 | #include <gmock/gmock.h> |
| 20 | #include <gtest/gtest.h> |
| 21 | #include <stdio.h> |
| 22 | #include <vector> |
| 23 | |
| 24 | using namespace testing; |
| 25 | using android::sp; |
| 26 | using std::set; |
| 27 | using std::unordered_map; |
| 28 | using std::vector; |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 29 | using std::make_shared; |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 30 | |
| 31 | #ifdef __ANDROID__ |
| 32 | |
| 33 | namespace android { |
| 34 | namespace os { |
| 35 | namespace statsd { |
| 36 | |
Bookatz | 8f2f3d8 | 2017-12-07 13:53:21 -0800 | [diff] [blame] | 37 | const ConfigKey kConfigKey(0, "test"); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 38 | const int tagId = 1; |
| 39 | const string metricName = "test_metric"; |
| 40 | const int64_t bucketStartTimeNs = 10000000000; |
| 41 | const int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL; |
| 42 | const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; |
| 43 | const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; |
| 44 | const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs; |
Bookatz | 8f2f3d8 | 2017-12-07 13:53:21 -0800 | [diff] [blame] | 45 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 46 | TEST(GaugeMetricProducerTest, TestNoCondition) { |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 47 | GaugeMetric metric; |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 48 | metric.set_name(metricName); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 49 | metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 50 | metric.mutable_gauge_fields()->add_field_num(2); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 51 | |
| 52 | sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); |
| 53 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 54 | // TODO: pending refactor of StatsPullerManager |
| 55 | // For now we still need this so that it doesn't do real pulling. |
| 56 | shared_ptr<MockStatsPullerManager> pullerManager = |
| 57 | make_shared<StrictMock<MockStatsPullerManager>>(); |
| 58 | EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); |
| 59 | EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 60 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 61 | GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, |
| 62 | tagId, tagId, bucketStartTimeNs, pullerManager); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 63 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 64 | vector<shared_ptr<LogEvent>> allData; |
| 65 | allData.clear(); |
| 66 | shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); |
| 67 | event->write(tagId); |
| 68 | event->write(11); |
| 69 | event->init(); |
| 70 | allData.push_back(event); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 71 | |
| 72 | gaugeProducer.onDataPulled(allData); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 73 | EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); |
| 74 | EXPECT_EQ(11, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int()); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 75 | EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size()); |
| 76 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 77 | allData.clear(); |
| 78 | std::shared_ptr<LogEvent> event2 = |
| 79 | std::make_shared<LogEvent>(tagId, bucket3StartTimeNs + 10); |
| 80 | event2->write(tagId); |
| 81 | event2->write(25); |
| 82 | event2->init(); |
| 83 | allData.push_back(event2); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 84 | gaugeProducer.onDataPulled(allData); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 85 | EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 86 | EXPECT_EQ(25, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int()); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 87 | // One dimension. |
| 88 | EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); |
| 89 | EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.size()); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 90 | EXPECT_EQ(11L, gaugeProducer.mPastBuckets.begin()->second.back().mEvent->kv[0].value_int()); |
| 91 | EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum); |
| 92 | |
| 93 | gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs); |
| 94 | EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size()); |
| 95 | // One dimension. |
| 96 | EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); |
| 97 | EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size()); |
| 98 | EXPECT_EQ(25L, gaugeProducer.mPastBuckets.begin()->second.back().mEvent->kv[0].value_int()); |
| 99 | EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 100 | } |
| 101 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 102 | TEST(GaugeMetricProducerTest, TestWithCondition) { |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 103 | GaugeMetric metric; |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 104 | metric.set_name(metricName); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 105 | metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 106 | metric.mutable_gauge_fields()->add_field_num(2); |
| 107 | metric.set_condition("SCREEN_ON"); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 108 | |
| 109 | sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); |
| 110 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 111 | shared_ptr<MockStatsPullerManager> pullerManager = |
| 112 | make_shared<StrictMock<MockStatsPullerManager>>(); |
| 113 | EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); |
| 114 | EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); |
| 115 | EXPECT_CALL(*pullerManager, Pull(tagId, _)) |
| 116 | .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { |
| 117 | data->clear(); |
| 118 | shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); |
| 119 | event->write(tagId); |
| 120 | event->write(100); |
| 121 | event->init(); |
| 122 | data->push_back(event); |
| 123 | return true; |
| 124 | })); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 125 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 126 | GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId, tagId, |
| 127 | bucketStartTimeNs, pullerManager); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 128 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 129 | gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 130 | EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 131 | EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int()); |
| 132 | EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size()); |
| 133 | |
| 134 | vector<shared_ptr<LogEvent>> allData; |
| 135 | allData.clear(); |
| 136 | shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); |
| 137 | event->write(1); |
| 138 | event->write(110); |
| 139 | event->init(); |
| 140 | allData.push_back(event); |
| 141 | gaugeProducer.onDataPulled(allData); |
| 142 | |
| 143 | EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); |
| 144 | EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int()); |
| 145 | EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); |
| 146 | EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()->second.back().mEvent->kv[0].value_int()); |
| 147 | |
| 148 | gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10); |
| 149 | gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10); |
| 150 | EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 151 | EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size()); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 152 | EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()->second.back().mEvent->kv[0].value_int()); |
| 153 | EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 154 | } |
| 155 | |
| 156 | TEST(GaugeMetricProducerTest, TestAnomalyDetection) { |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 157 | sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); |
| 158 | |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 159 | shared_ptr<MockStatsPullerManager> pullerManager = |
| 160 | make_shared<StrictMock<MockStatsPullerManager>>(); |
| 161 | EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); |
| 162 | EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); |
| 163 | |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 164 | GaugeMetric metric; |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 165 | metric.set_name(metricName); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 166 | metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 167 | metric.mutable_gauge_fields()->add_field_num(2); |
| 168 | GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, |
| 169 | tagId, tagId, bucketStartTimeNs, pullerManager); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 170 | |
| 171 | Alert alert; |
| 172 | alert.set_name("alert"); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 173 | alert.set_metric_name(metricName); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 174 | alert.set_trigger_if_sum_gt(25); |
| 175 | alert.set_number_of_buckets(2); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame^] | 176 | sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 177 | |
| 178 | std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(1, bucketStartTimeNs + 1); |
| 179 | event1->write(1); |
| 180 | event1->write(13); |
| 181 | event1->init(); |
| 182 | |
| 183 | gaugeProducer.onDataPulled({event1}); |
| 184 | EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 185 | EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int()); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame^] | 186 | EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), -1LL); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 187 | |
| 188 | std::shared_ptr<LogEvent> event2 = |
| 189 | std::make_shared<LogEvent>(1, bucketStartTimeNs + bucketSizeNs + 10); |
| 190 | event2->write(1); |
| 191 | event2->write(15); |
| 192 | event2->init(); |
| 193 | |
| 194 | gaugeProducer.onDataPulled({event2}); |
| 195 | EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 196 | EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int()); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame^] | 197 | EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event2->GetTimestampNs()); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 198 | |
| 199 | std::shared_ptr<LogEvent> event3 = |
| 200 | std::make_shared<LogEvent>(1, bucketStartTimeNs + 2 * bucketSizeNs + 10); |
| 201 | event3->write(1); |
| 202 | event3->write(24); |
| 203 | event3->init(); |
| 204 | |
| 205 | gaugeProducer.onDataPulled({event3}); |
| 206 | EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 207 | EXPECT_EQ(24L, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int()); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame^] | 208 | EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event3->GetTimestampNs()); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 209 | |
| 210 | // The event4 does not have the gauge field. Thus the current bucket value is 0. |
| 211 | std::shared_ptr<LogEvent> event4 = |
| 212 | std::make_shared<LogEvent>(1, bucketStartTimeNs + 3 * bucketSizeNs + 10); |
| 213 | event4->write(1); |
| 214 | event4->init(); |
| 215 | gaugeProducer.onDataPulled({event4}); |
Chenjie Yu | d9dfda7 | 2017-12-11 17:41:20 -0800 | [diff] [blame] | 216 | EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); |
| 217 | EXPECT_EQ(0, gaugeProducer.mCurrentSlicedBucket->begin()->second->kv[0].value_int()); |
Bookatz | 857aaa5 | 2017-12-19 15:29:06 -0800 | [diff] [blame^] | 218 | EXPECT_EQ(anomalyTracker->getLastAnomalyTimestampNs(), (long long)event3->GetTimestampNs()); |
Yangster-mac | e2cd6d5 | 2017-11-09 20:38:30 -0800 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | } // namespace statsd |
| 222 | } // namespace os |
| 223 | } // namespace android |
| 224 | #else |
| 225 | GTEST_LOG_(INFO) << "This test does nothing.\n"; |
| 226 | #endif |