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
26 using namespace testing;
27 using android::sp;
28 using std::make_shared;
29 using std::set;
30 using std::shared_ptr;
31 using std::unordered_map;
32 using std::vector;
33
34 #ifdef __ANDROID__
35
36 namespace android {
37 namespace os {
38 namespace statsd {
39
40 const ConfigKey kConfigKey(0, 12345);
41 const int tagId = 1;
42 const int64_t metricId = 123;
43 const int64_t bucketStartTimeNs = 10000000000;
44 const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
45 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
46 const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
47 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
48 const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs;
49 const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
50 const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
51
52 /*
53 * Tests pulled atoms with no conditions
54 */
TEST(ValueMetricProducerTest,TestNonDimensionalEvents)55 TEST(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 */
TEST(ValueMetricProducerTest,TestPulledEventsTakeAbsoluteValueOnReset)134 TEST(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 */
TEST(ValueMetricProducerTest,TestPulledEventsTakeZeroOnReset)209 TEST(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 */
TEST(ValueMetricProducerTest,TestEventsWithNonSlicedCondition)281 TEST(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
TEST(ValueMetricProducerTest,TestPushedEventsWithUpgrade)360 TEST(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
TEST(ValueMetricProducerTest,TestPulledValueWithUpgrade)403 TEST(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
TEST(ValueMetricProducerTest,TestPulledValueWithUpgradeWhileConditionFalse)458 TEST(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
TEST(ValueMetricProducerTest,TestPushedEventsWithoutCondition)509 TEST(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
TEST(ValueMetricProducerTest,TestPushedEventsWithCondition)551 TEST(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
TEST(ValueMetricProducerTest,TestAnomalyDetection)617 TEST(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
TEST(ValueMetricProducerTest,TestBucketBoundaryNoCondition)700 TEST(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 */
TEST(ValueMetricProducerTest,TestBucketBoundaryWithCondition)784 TEST(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 */
TEST(ValueMetricProducerTest,TestBucketBoundaryWithCondition2)867 TEST(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 */
TEST(ValueMetricProducerTest,TestBucketBoundaryWithCondition3)970 TEST(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
1054 GTEST_LOG_(INFO) << "This test does nothing.\n";
1055 #endif
1056