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 "src/metrics/ValueMetricProducer.h" 16#include "src/stats_log_util.h" 17#include "metrics_test_helper.h" 18#include "tests/statsd_test_util.h" 19 20#include <gmock/gmock.h> 21#include <gtest/gtest.h> 22#include <math.h> 23#include <stdio.h> 24#include <vector> 25 26using namespace testing; 27using android::sp; 28using std::make_shared; 29using std::set; 30using std::shared_ptr; 31using std::unordered_map; 32using std::vector; 33 34#ifdef __ANDROID__ 35 36namespace android { 37namespace os { 38namespace statsd { 39 40const ConfigKey kConfigKey(0, 12345); 41const int tagId = 1; 42const int64_t metricId = 123; 43const int64_t bucketStartTimeNs = 10000000000; 44const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; 45const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; 46const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; 47const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs; 48const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs; 49const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs; 50const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; 51 52/* 53 * Tests pulled atoms with no conditions 54 */ 55TEST(ValueMetricProducerTest, TestNonDimensionalEvents) { 56 ValueMetric metric; 57 metric.set_id(metricId); 58 metric.set_bucket(ONE_MINUTE); 59 metric.mutable_value_field()->set_field(tagId); 60 metric.mutable_value_field()->add_child()->set_field(2); 61 62 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 63 // TODO: pending refactor of StatsPullerManager 64 // For now we still need this so that it doesn't do real pulling. 65 shared_ptr<MockStatsPullerManager> pullerManager = 66 make_shared<StrictMock<MockStatsPullerManager>>(); 67 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 68 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); 69 70 ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 71 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); 72 valueProducer.setBucketSize(60 * NS_PER_SEC); 73 74 vector<shared_ptr<LogEvent>> allData; 75 allData.clear(); 76 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); 77 event->write(tagId); 78 event->write(11); 79 event->init(); 80 allData.push_back(event); 81 82 valueProducer.onDataPulled(allData); 83 // has one slice 84 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 85 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 86 valueProducer.setBucketSize(60 * NS_PER_SEC); 87 88 // startUpdated:true tainted:0 sum:0 start:11 89 EXPECT_EQ(true, curInterval.startUpdated); 90 EXPECT_EQ(0, curInterval.tainted); 91 EXPECT_EQ(0, curInterval.sum); 92 EXPECT_EQ(11, curInterval.start); 93 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 94 95 allData.clear(); 96 event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1); 97 event->write(tagId); 98 event->write(23); 99 event->init(); 100 allData.push_back(event); 101 valueProducer.onDataPulled(allData); 102 // has one slice 103 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 104 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 105 // tartUpdated:false tainted:0 sum:12 106 EXPECT_EQ(true, curInterval.startUpdated); 107 EXPECT_EQ(0, curInterval.tainted); 108 EXPECT_EQ(0, curInterval.sum); 109 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 110 EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); 111 EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValue); 112 113 allData.clear(); 114 event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1); 115 event->write(tagId); 116 event->write(36); 117 event->init(); 118 allData.push_back(event); 119 valueProducer.onDataPulled(allData); 120 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 121 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 122 // startUpdated:false tainted:0 sum:12 123 EXPECT_EQ(true, curInterval.startUpdated); 124 EXPECT_EQ(0, curInterval.tainted); 125 EXPECT_EQ(0, curInterval.sum); 126 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 127 EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size()); 128 EXPECT_EQ(13, valueProducer.mPastBuckets.begin()->second.back().mValue); 129} 130 131/* 132 * Tests pulled atoms with no conditions and take absolute value after reset 133 */ 134TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { 135 ValueMetric metric; 136 metric.set_id(metricId); 137 metric.set_bucket(ONE_MINUTE); 138 metric.mutable_value_field()->set_field(tagId); 139 metric.mutable_value_field()->add_child()->set_field(2); 140 metric.set_use_absolute_value_on_reset(true); 141 142 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 143 shared_ptr<MockStatsPullerManager> pullerManager = 144 make_shared<StrictMock<MockStatsPullerManager>>(); 145 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 146 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); 147 148 ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 149 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); 150 valueProducer.setBucketSize(60 * NS_PER_SEC); 151 152 vector<shared_ptr<LogEvent>> allData; 153 allData.clear(); 154 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); 155 event->write(tagId); 156 event->write(11); 157 event->init(); 158 allData.push_back(event); 159 160 valueProducer.onDataPulled(allData); 161 // has one slice 162 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 163 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 164 valueProducer.setBucketSize(60 * NS_PER_SEC); 165 166 EXPECT_EQ(true, curInterval.startUpdated); 167 EXPECT_EQ(0, curInterval.tainted); 168 EXPECT_EQ(0, curInterval.sum); 169 EXPECT_EQ(11, curInterval.start); 170 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 171 172 allData.clear(); 173 event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1); 174 event->write(tagId); 175 event->write(10); 176 event->init(); 177 allData.push_back(event); 178 valueProducer.onDataPulled(allData); 179 // has one slice 180 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 181 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 182 EXPECT_EQ(true, curInterval.startUpdated); 183 EXPECT_EQ(0, curInterval.tainted); 184 EXPECT_EQ(0, curInterval.sum); 185 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 186 EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); 187 EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValue); 188 189 allData.clear(); 190 event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1); 191 event->write(tagId); 192 event->write(36); 193 event->init(); 194 allData.push_back(event); 195 valueProducer.onDataPulled(allData); 196 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 197 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 198 EXPECT_EQ(true, curInterval.startUpdated); 199 EXPECT_EQ(0, curInterval.tainted); 200 EXPECT_EQ(0, curInterval.sum); 201 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 202 EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size()); 203 EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValue); 204} 205 206/* 207 * Tests pulled atoms with no conditions and take zero value after reset 208 */ 209TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { 210 ValueMetric metric; 211 metric.set_id(metricId); 212 metric.set_bucket(ONE_MINUTE); 213 metric.mutable_value_field()->set_field(tagId); 214 metric.mutable_value_field()->add_child()->set_field(2); 215 216 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 217 shared_ptr<MockStatsPullerManager> pullerManager = 218 make_shared<StrictMock<MockStatsPullerManager>>(); 219 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 220 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); 221 222 ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 223 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); 224 valueProducer.setBucketSize(60 * NS_PER_SEC); 225 226 vector<shared_ptr<LogEvent>> allData; 227 allData.clear(); 228 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); 229 event->write(tagId); 230 event->write(11); 231 event->init(); 232 allData.push_back(event); 233 234 valueProducer.onDataPulled(allData); 235 // has one slice 236 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 237 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 238 valueProducer.setBucketSize(60 * NS_PER_SEC); 239 240 EXPECT_EQ(true, curInterval.startUpdated); 241 EXPECT_EQ(0, curInterval.tainted); 242 EXPECT_EQ(0, curInterval.sum); 243 EXPECT_EQ(11, curInterval.start); 244 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 245 246 allData.clear(); 247 event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1); 248 event->write(tagId); 249 event->write(10); 250 event->init(); 251 allData.push_back(event); 252 valueProducer.onDataPulled(allData); 253 // has one slice 254 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 255 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 256 EXPECT_EQ(true, curInterval.startUpdated); 257 EXPECT_EQ(0, curInterval.tainted); 258 EXPECT_EQ(0, curInterval.sum); 259 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 260 261 allData.clear(); 262 event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1); 263 event->write(tagId); 264 event->write(36); 265 event->init(); 266 allData.push_back(event); 267 valueProducer.onDataPulled(allData); 268 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 269 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 270 EXPECT_EQ(true, curInterval.startUpdated); 271 EXPECT_EQ(0, curInterval.tainted); 272 EXPECT_EQ(0, curInterval.sum); 273 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 274 EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); 275 EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValue); 276} 277 278/* 279 * Test pulled event with non sliced condition. 280 */ 281TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { 282 ValueMetric metric; 283 metric.set_id(metricId); 284 metric.set_bucket(ONE_MINUTE); 285 metric.mutable_value_field()->set_field(tagId); 286 metric.mutable_value_field()->add_child()->set_field(2); 287 metric.set_condition(StringToId("SCREEN_ON")); 288 289 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 290 shared_ptr<MockStatsPullerManager> pullerManager = 291 make_shared<StrictMock<MockStatsPullerManager>>(); 292 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 293 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); 294 295 EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) 296 .WillOnce(Invoke([](int tagId, int64_t timeNs, 297 vector<std::shared_ptr<LogEvent>>* data) { 298 data->clear(); 299 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 300 event->write(tagId); 301 event->write(100); 302 event->init(); 303 data->push_back(event); 304 return true; 305 })) 306 .WillOnce(Invoke([](int tagId, int64_t timeNs, 307 vector<std::shared_ptr<LogEvent>>* data) { 308 data->clear(); 309 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10); 310 event->write(tagId); 311 event->write(120); 312 event->init(); 313 data->push_back(event); 314 return true; 315 })); 316 317 ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs, 318 bucketStartTimeNs, pullerManager); 319 valueProducer.setBucketSize(60 * NS_PER_SEC); 320 valueProducer.onConditionChanged(true, bucketStartTimeNs + 8); 321 322 // has one slice 323 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 324 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 325 // startUpdated:false tainted:0 sum:0 start:100 326 EXPECT_EQ(100, curInterval.start); 327 EXPECT_EQ(true, curInterval.startUpdated); 328 EXPECT_EQ(0, curInterval.tainted); 329 EXPECT_EQ(0, curInterval.sum); 330 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 331 332 vector<shared_ptr<LogEvent>> allData; 333 allData.clear(); 334 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); 335 event->write(1); 336 event->write(110); 337 event->init(); 338 allData.push_back(event); 339 valueProducer.onDataPulled(allData); 340 341 // has one slice 342 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 343 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 344 // startUpdated:false tainted:0 sum:0 start:110 345 EXPECT_EQ(110, curInterval.start); 346 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 347 EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); 348 EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValue); 349 350 valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1); 351 352 // has one slice 353 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 354 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 355 // startUpdated:false tainted:0 sum:0 start:110 356 EXPECT_EQ(10, curInterval.sum); 357 EXPECT_EQ(false, curInterval.startUpdated); 358} 359 360TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) { 361 ValueMetric metric; 362 metric.set_id(metricId); 363 metric.set_bucket(ONE_MINUTE); 364 metric.mutable_value_field()->set_field(tagId); 365 metric.mutable_value_field()->add_child()->set_field(2); 366 367 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 368 shared_ptr<MockStatsPullerManager> pullerManager = 369 make_shared<StrictMock<MockStatsPullerManager>>(); 370 ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs, 371 bucketStartTimeNs, pullerManager); 372 valueProducer.setBucketSize(60 * NS_PER_SEC); 373 374 shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 375 event1->write(1); 376 event1->write(10); 377 event1->init(); 378 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1); 379 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 380 381 valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); 382 EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); 383 EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs); 384 385 shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC); 386 event2->write(1); 387 event2->write(10); 388 event2->init(); 389 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2); 390 EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); 391 EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs); 392 393 // Next value should create a new bucket. 394 shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC); 395 event3->write(1); 396 event3->write(10); 397 event3->init(); 398 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3); 399 EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); 400 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, valueProducer.mCurrentBucketStartTimeNs); 401} 402 403TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) { 404 ValueMetric metric; 405 metric.set_id(metricId); 406 metric.set_bucket(ONE_MINUTE); 407 metric.mutable_value_field()->set_field(tagId); 408 metric.mutable_value_field()->add_child()->set_field(2); 409 410 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 411 shared_ptr<MockStatsPullerManager> pullerManager = 412 make_shared<StrictMock<MockStatsPullerManager>>(); 413 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 414 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); 415 EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) 416 .WillOnce(Invoke([](int tagId, int64_t timeNs, 417 vector<std::shared_ptr<LogEvent>>* data) { 418 data->clear(); 419 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 420 event->write(tagId); 421 event->write(120); 422 event->init(); 423 data->push_back(event); 424 return true; 425 })); 426 ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, tagId, bucketStartTimeNs, 427 bucketStartTimeNs, pullerManager); 428 valueProducer.setBucketSize(60 * NS_PER_SEC); 429 430 vector<shared_ptr<LogEvent>> allData; 431 allData.clear(); 432 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1); 433 event->write(tagId); 434 event->write(100); 435 event->init(); 436 allData.push_back(event); 437 438 valueProducer.onDataPulled(allData); 439 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 440 441 valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); 442 EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); 443 EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs); 444 EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValue); 445 446 allData.clear(); 447 event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); 448 event->write(tagId); 449 event->write(150); 450 event->init(); 451 allData.push_back(event); 452 valueProducer.onDataPulled(allData); 453 EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); 454 EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs); 455 EXPECT_EQ(30L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mValue); 456} 457 458TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) { 459 ValueMetric metric; 460 metric.set_id(metricId); 461 metric.set_bucket(ONE_MINUTE); 462 metric.mutable_value_field()->set_field(tagId); 463 metric.mutable_value_field()->add_child()->set_field(2); 464 metric.set_condition(StringToId("SCREEN_ON")); 465 466 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 467 shared_ptr<MockStatsPullerManager> pullerManager = 468 make_shared<StrictMock<MockStatsPullerManager>>(); 469 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 470 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); 471 EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) 472 .WillOnce(Invoke([](int tagId, int64_t timeNs, 473 vector<std::shared_ptr<LogEvent>>* data) { 474 data->clear(); 475 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 476 event->write(tagId); 477 event->write(100); 478 event->init(); 479 data->push_back(event); 480 return true; 481 })) 482 .WillOnce(Invoke([](int tagId, int64_t timeNs, 483 vector<std::shared_ptr<LogEvent>>* data) { 484 data->clear(); 485 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 486 event->write(tagId); 487 event->write(120); 488 event->init(); 489 data->push_back(event); 490 return true; 491 })); 492 ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs, 493 bucketStartTimeNs, pullerManager); 494 valueProducer.setBucketSize(60 * NS_PER_SEC); 495 valueProducer.onConditionChanged(true, bucketStartTimeNs + 1); 496 497 valueProducer.onConditionChanged(false, bucket2StartTimeNs-100); 498 EXPECT_FALSE(valueProducer.mCondition); 499 500 valueProducer.notifyAppUpgrade(bucket2StartTimeNs-50, "ANY.APP", 1, 1); 501 // Expect one full buckets already done and starting a partial bucket. 502 EXPECT_EQ(bucket2StartTimeNs-50, valueProducer.mCurrentBucketStartTimeNs); 503 EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); 504 EXPECT_EQ(bucketStartTimeNs, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs); 505 EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValue); 506 EXPECT_FALSE(valueProducer.mCondition); 507} 508 509TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { 510 ValueMetric metric; 511 metric.set_id(metricId); 512 metric.set_bucket(ONE_MINUTE); 513 metric.mutable_value_field()->set_field(tagId); 514 metric.mutable_value_field()->add_child()->set_field(2); 515 516 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 517 shared_ptr<MockStatsPullerManager> pullerManager = 518 make_shared<StrictMock<MockStatsPullerManager>>(); 519 520 ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs, 521 bucketStartTimeNs, pullerManager); 522 valueProducer.setBucketSize(60 * NS_PER_SEC); 523 524 shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 525 event1->write(1); 526 event1->write(10); 527 event1->init(); 528 shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20); 529 event2->write(1); 530 event2->write(20); 531 event2->init(); 532 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1); 533 // has one slice 534 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 535 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 536 EXPECT_EQ(10, curInterval.sum); 537 538 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2); 539 540 // has one slice 541 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 542 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 543 EXPECT_EQ(30, curInterval.sum); 544 545 valueProducer.flushIfNeededLocked(bucket3StartTimeNs); 546 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 547 EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); 548 EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().mValue); 549} 550 551TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { 552 ValueMetric metric; 553 metric.set_id(metricId); 554 metric.set_bucket(ONE_MINUTE); 555 metric.mutable_value_field()->set_field(tagId); 556 metric.mutable_value_field()->add_child()->set_field(2); 557 558 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 559 shared_ptr<MockStatsPullerManager> pullerManager = 560 make_shared<StrictMock<MockStatsPullerManager>>(); 561 562 ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, -1, bucketStartTimeNs, 563 bucketStartTimeNs, pullerManager); 564 valueProducer.setBucketSize(60 * NS_PER_SEC); 565 566 shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 567 event1->write(1); 568 event1->write(10); 569 event1->init(); 570 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1); 571 // has 1 slice 572 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 573 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 574 EXPECT_EQ(false, curInterval.hasValue); 575 576 valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15); 577 shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20); 578 event2->write(1); 579 event2->write(20); 580 event2->init(); 581 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2); 582 583 // has one slice 584 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 585 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 586 EXPECT_EQ(20, curInterval.sum); 587 588 shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 30); 589 event3->write(1); 590 event3->write(30); 591 event3->init(); 592 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3); 593 594 // has one slice 595 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 596 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 597 EXPECT_EQ(50, curInterval.sum); 598 599 valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35); 600 shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 40); 601 event4->write(1); 602 event4->write(40); 603 event4->init(); 604 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4); 605 606 // has one slice 607 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 608 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 609 EXPECT_EQ(50, curInterval.sum); 610 611 valueProducer.flushIfNeededLocked(bucket3StartTimeNs); 612 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 613 EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); 614 EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().mValue); 615} 616 617TEST(ValueMetricProducerTest, TestAnomalyDetection) { 618 sp<AlarmMonitor> alarmMonitor; 619 Alert alert; 620 alert.set_id(101); 621 alert.set_metric_id(metricId); 622 alert.set_trigger_if_sum_gt(130); 623 alert.set_num_buckets(2); 624 const int32_t refPeriodSec = 3; 625 alert.set_refractory_period_secs(refPeriodSec); 626 627 ValueMetric metric; 628 metric.set_id(metricId); 629 metric.set_bucket(ONE_MINUTE); 630 metric.mutable_value_field()->set_field(tagId); 631 metric.mutable_value_field()->add_child()->set_field(2); 632 633 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 634 ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 635 -1 /*not pulled*/, bucketStartTimeNs, bucketStartTimeNs); 636 valueProducer.setBucketSize(60 * NS_PER_SEC); 637 638 sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor); 639 640 641 shared_ptr<LogEvent> event1 642 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1 * NS_PER_SEC); 643 event1->write(161); 644 event1->write(10); // value of interest 645 event1->init(); 646 shared_ptr<LogEvent> event2 647 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 + NS_PER_SEC); 648 event2->write(162); 649 event2->write(20); // value of interest 650 event2->init(); 651 shared_ptr<LogEvent> event3 652 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC); 653 event3->write(163); 654 event3->write(130); // value of interest 655 event3->init(); 656 shared_ptr<LogEvent> event4 657 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1 * NS_PER_SEC); 658 event4->write(35); 659 event4->write(1); // value of interest 660 event4->init(); 661 shared_ptr<LogEvent> event5 662 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC); 663 event5->write(45); 664 event5->write(150); // value of interest 665 event5->init(); 666 shared_ptr<LogEvent> event6 667 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10 * NS_PER_SEC); 668 event6->write(25); 669 event6->write(160); // value of interest 670 event6->init(); 671 672 // Two events in bucket #0. 673 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1); 674 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2); 675 // Value sum == 30 <= 130. 676 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); 677 678 // One event in bucket #2. No alarm as bucket #0 is trashed out. 679 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3); 680 // Value sum == 130 <= 130. 681 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); 682 683 // Three events in bucket #3. 684 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4); 685 // Anomaly at event 4 since Value sum == 131 > 130! 686 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 687 std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); 688 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5); 689 // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4. 690 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 691 std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); 692 693 valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6); 694 // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period. 695 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 696 std::ceil(1.0 * event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); 697} 698 699// Test value metric no condition, the pull on bucket boundary come in time and too late 700TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { 701 ValueMetric metric; 702 metric.set_id(metricId); 703 metric.set_bucket(ONE_MINUTE); 704 metric.mutable_value_field()->set_field(tagId); 705 metric.mutable_value_field()->add_child()->set_field(2); 706 707 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 708 shared_ptr<MockStatsPullerManager> pullerManager = 709 make_shared<StrictMock<MockStatsPullerManager>>(); 710 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 711 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); 712 713 ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 714 tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); 715 valueProducer.setBucketSize(60 * NS_PER_SEC); 716 717 vector<shared_ptr<LogEvent>> allData; 718 // pull 1 719 allData.clear(); 720 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); 721 event->write(tagId); 722 event->write(11); 723 event->init(); 724 allData.push_back(event); 725 726 valueProducer.onDataPulled(allData); 727 // has one slice 728 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 729 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 730 731 // startUpdated:true tainted:0 sum:0 start:11 732 EXPECT_EQ(true, curInterval.startUpdated); 733 EXPECT_EQ(0, curInterval.tainted); 734 EXPECT_EQ(0, curInterval.sum); 735 EXPECT_EQ(11, curInterval.start); 736 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 737 738 // pull 2 at correct time 739 allData.clear(); 740 event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1); 741 event->write(tagId); 742 event->write(23); 743 event->init(); 744 allData.push_back(event); 745 valueProducer.onDataPulled(allData); 746 // has one slice 747 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 748 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 749 // tartUpdated:false tainted:0 sum:12 750 EXPECT_EQ(true, curInterval.startUpdated); 751 EXPECT_EQ(0, curInterval.tainted); 752 EXPECT_EQ(0, curInterval.sum); 753 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 754 EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); 755 EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValue); 756 757 // pull 3 come late. 758 // The previous bucket gets closed with error. (Has start value 23, no ending) 759 // Another bucket gets closed with error. (No start, but ending with 36) 760 // The new bucket is back to normal. 761 allData.clear(); 762 event = make_shared<LogEvent>(tagId, bucket6StartTimeNs + 1); 763 event->write(tagId); 764 event->write(36); 765 event->init(); 766 allData.push_back(event); 767 valueProducer.onDataPulled(allData); 768 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 769 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 770 // startUpdated:false tainted:0 sum:12 771 EXPECT_EQ(true, curInterval.startUpdated); 772 EXPECT_EQ(0, curInterval.tainted); 773 EXPECT_EQ(36, curInterval.start); 774 EXPECT_EQ(0, curInterval.sum); 775 EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); 776 EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); 777 EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValue); 778} 779 780/* 781 * Test pulled event with non sliced condition. The pull on boundary come late because the alarm 782 * was delivered late. 783 */ 784TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { 785 ValueMetric metric; 786 metric.set_id(metricId); 787 metric.set_bucket(ONE_MINUTE); 788 metric.mutable_value_field()->set_field(tagId); 789 metric.mutable_value_field()->add_child()->set_field(2); 790 metric.set_condition(StringToId("SCREEN_ON")); 791 792 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 793 shared_ptr<MockStatsPullerManager> pullerManager = 794 make_shared<StrictMock<MockStatsPullerManager>>(); 795 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 796 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); 797 798 EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) 799 // condition becomes true 800 .WillOnce(Invoke([](int tagId, int64_t timeNs, 801 vector<std::shared_ptr<LogEvent>>* data) { 802 data->clear(); 803 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 804 event->write(tagId); 805 event->write(100); 806 event->init(); 807 data->push_back(event); 808 return true; 809 })) 810 // condition becomes false 811 .WillOnce(Invoke([](int tagId, int64_t timeNs, 812 vector<std::shared_ptr<LogEvent>>* data) { 813 data->clear(); 814 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20); 815 event->write(tagId); 816 event->write(120); 817 event->init(); 818 data->push_back(event); 819 return true; 820 })); 821 822 ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs, 823 bucketStartTimeNs, pullerManager); 824 valueProducer.setBucketSize(60 * NS_PER_SEC); 825 valueProducer.onConditionChanged(true, bucketStartTimeNs + 8); 826 827 // has one slice 828 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 829 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 830 // startUpdated:false tainted:0 sum:0 start:100 831 EXPECT_EQ(100, curInterval.start); 832 EXPECT_EQ(true, curInterval.startUpdated); 833 EXPECT_EQ(0, curInterval.tainted); 834 EXPECT_EQ(0, curInterval.sum); 835 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 836 837 // pull on bucket boundary come late, condition change happens before it 838 valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1); 839 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 840 EXPECT_EQ(false, curInterval.startUpdated); 841 EXPECT_EQ(1, curInterval.tainted); 842 EXPECT_EQ(0, curInterval.sum); 843 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 844 845 // Now the alarm is delivered. 846 // since the condition turned to off before this pull finish, it has no effect 847 vector<shared_ptr<LogEvent>> allData; 848 allData.clear(); 849 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30); 850 event->write(1); 851 event->write(110); 852 event->init(); 853 allData.push_back(event); 854 valueProducer.onDataPulled(allData); 855 856 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 857 EXPECT_EQ(false, curInterval.startUpdated); 858 EXPECT_EQ(1, curInterval.tainted); 859 EXPECT_EQ(0, curInterval.sum); 860 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 861} 862 863/* 864 * Test pulled event with non sliced condition. The pull on boundary come late, after the condition 865 * change to false, and then true again. This is due to alarm delivered late. 866 */ 867TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { 868 ValueMetric metric; 869 metric.set_id(metricId); 870 metric.set_bucket(ONE_MINUTE); 871 metric.mutable_value_field()->set_field(tagId); 872 metric.mutable_value_field()->add_child()->set_field(2); 873 metric.set_condition(StringToId("SCREEN_ON")); 874 875 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 876 shared_ptr<MockStatsPullerManager> pullerManager = 877 make_shared<StrictMock<MockStatsPullerManager>>(); 878 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillRepeatedly(Return()); 879 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); 880 881 EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) 882 // condition becomes true 883 .WillOnce(Invoke([](int tagId, int64_t timeNs, 884 vector<std::shared_ptr<LogEvent>>* data) { 885 data->clear(); 886 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 887 event->write(tagId); 888 event->write(100); 889 event->init(); 890 data->push_back(event); 891 return true; 892 })) 893 // condition becomes false 894 .WillOnce(Invoke([](int tagId, int64_t timeNs, 895 vector<std::shared_ptr<LogEvent>>* data) { 896 data->clear(); 897 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20); 898 event->write(tagId); 899 event->write(120); 900 event->init(); 901 data->push_back(event); 902 return true; 903 })) 904 // condition becomes true again 905 .WillOnce(Invoke([](int tagId, int64_t timeNs, 906 vector<std::shared_ptr<LogEvent>>* data) { 907 data->clear(); 908 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30); 909 event->write(tagId); 910 event->write(130); 911 event->init(); 912 data->push_back(event); 913 return true; 914 })); 915 916 ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs, 917 bucketStartTimeNs, pullerManager); 918 valueProducer.setBucketSize(60 * NS_PER_SEC); 919 valueProducer.onConditionChanged(true, bucketStartTimeNs + 8); 920 921 // has one slice 922 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 923 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 924 // startUpdated:false tainted:0 sum:0 start:100 925 EXPECT_EQ(100, curInterval.start); 926 EXPECT_EQ(true, curInterval.startUpdated); 927 EXPECT_EQ(0, curInterval.tainted); 928 EXPECT_EQ(0, curInterval.sum); 929 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 930 931 // pull on bucket boundary come late, condition change happens before it 932 valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1); 933 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 934 EXPECT_EQ(false, curInterval.startUpdated); 935 EXPECT_EQ(1, curInterval.tainted); 936 EXPECT_EQ(0, curInterval.sum); 937 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 938 939 // condition changed to true again, before the pull alarm is delivered 940 valueProducer.onConditionChanged(true, bucket2StartTimeNs + 25); 941 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 942 EXPECT_EQ(true, curInterval.startUpdated); 943 EXPECT_EQ(130, curInterval.start); 944 EXPECT_EQ(1, curInterval.tainted); 945 EXPECT_EQ(0, curInterval.sum); 946 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 947 948 // Now the alarm is delivered, but it is considered late, it has no effect 949 vector<shared_ptr<LogEvent>> allData; 950 allData.clear(); 951 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 50); 952 event->write(1); 953 event->write(110); 954 event->init(); 955 allData.push_back(event); 956 valueProducer.onDataPulled(allData); 957 958 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 959 EXPECT_EQ(true, curInterval.startUpdated); 960 EXPECT_EQ(130, curInterval.start); 961 EXPECT_EQ(1, curInterval.tainted); 962 EXPECT_EQ(0, curInterval.sum); 963 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 964} 965 966/* 967 * Test pulled event with non sliced condition. The pull on boundary come late because the puller is 968 * very slow. 969 */ 970TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3) { 971 ValueMetric metric; 972 metric.set_id(metricId); 973 metric.set_bucket(ONE_MINUTE); 974 metric.mutable_value_field()->set_field(tagId); 975 metric.mutable_value_field()->add_child()->set_field(2); 976 metric.set_condition(StringToId("SCREEN_ON")); 977 978 sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); 979 shared_ptr<MockStatsPullerManager> pullerManager = 980 make_shared<StrictMock<MockStatsPullerManager>>(); 981 EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); 982 EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); 983 984 EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) 985 // condition becomes true 986 .WillOnce(Invoke([](int tagId, int64_t timeNs, 987 vector<std::shared_ptr<LogEvent>>* data) { 988 data->clear(); 989 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); 990 event->write(tagId); 991 event->write(100); 992 event->init(); 993 data->push_back(event); 994 return true; 995 })) 996 // condition becomes false 997 .WillOnce(Invoke([](int tagId, int64_t timeNs, 998 vector<std::shared_ptr<LogEvent>>* data) { 999 data->clear(); 1000 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 20); 1001 event->write(tagId); 1002 event->write(120); 1003 event->init(); 1004 data->push_back(event); 1005 return true; 1006 })); 1007 1008 ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs, 1009 bucketStartTimeNs, pullerManager); 1010 valueProducer.setBucketSize(60 * NS_PER_SEC); 1011 valueProducer.onConditionChanged(true, bucketStartTimeNs + 8); 1012 1013 // has one slice 1014 EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); 1015 ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 1016 // startUpdated:false tainted:0 sum:0 start:100 1017 EXPECT_EQ(100, curInterval.start); 1018 EXPECT_EQ(true, curInterval.startUpdated); 1019 EXPECT_EQ(0, curInterval.tainted); 1020 EXPECT_EQ(0, curInterval.sum); 1021 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 1022 1023 // pull on bucket boundary come late, condition change happens before it. 1024 // But puller is very slow in this one, so the data come after bucket finish 1025 valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1); 1026 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 1027 EXPECT_EQ(false, curInterval.startUpdated); 1028 EXPECT_EQ(1, curInterval.tainted); 1029 EXPECT_EQ(0, curInterval.sum); 1030 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 1031 1032 // Alarm is delivered in time, but the pull is very slow, and pullers are called in order, 1033 // so this one comes even later 1034 vector<shared_ptr<LogEvent>> allData; 1035 allData.clear(); 1036 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 30); 1037 event->write(1); 1038 event->write(110); 1039 event->init(); 1040 allData.push_back(event); 1041 valueProducer.onDataPulled(allData); 1042 1043 curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; 1044 EXPECT_EQ(false, curInterval.startUpdated); 1045 EXPECT_EQ(1, curInterval.tainted); 1046 EXPECT_EQ(0, curInterval.sum); 1047 EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); 1048} 1049 1050} // namespace statsd 1051} // namespace os 1052} // namespace android 1053#else 1054GTEST_LOG_(INFO) << "This test does nothing.\n"; 1055#endif 1056