Home | History | Annotate | Download | only in metrics
      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/DurationMetricProducer.h"
     16 #include "src/stats_log_util.h"
     17 #include "metrics_test_helper.h"
     18 #include "src/condition/ConditionWizard.h"
     19 
     20 #include <gmock/gmock.h>
     21 #include <gtest/gtest.h>
     22 #include <stdio.h>
     23 #include <set>
     24 #include <unordered_map>
     25 #include <vector>
     26 
     27 using namespace android::os::statsd;
     28 using namespace testing;
     29 using android::sp;
     30 using std::set;
     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 
     42 TEST(DurationMetricTrackerTest, TestFirstBucket) {
     43     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     44     DurationMetric metric;
     45     metric.set_id(1);
     46     metric.set_bucket(ONE_MINUTE);
     47     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
     48 
     49     FieldMatcher dimensions;
     50     DurationMetricProducer durationProducer(
     51             kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
     52             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC/2);
     53 
     54     EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs);
     55     EXPECT_EQ(10, durationProducer.mCurrentBucketNum);
     56     EXPECT_EQ(660000000005, durationProducer.getCurrentBucketEndTimeNs());
     57 }
     58 
     59 TEST(DurationMetricTrackerTest, TestNoCondition) {
     60     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     61     int64_t bucketStartTimeNs = 10000000000;
     62     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
     63 
     64     DurationMetric metric;
     65     metric.set_id(1);
     66     metric.set_bucket(ONE_MINUTE);
     67     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
     68 
     69     int tagId = 1;
     70     LogEvent event1(tagId, bucketStartTimeNs + 1);
     71     event1.init();
     72     LogEvent event2(tagId, bucketStartTimeNs + bucketSizeNs + 2);
     73     event2.init();
     74 
     75     FieldMatcher dimensions;
     76     DurationMetricProducer durationProducer(
     77             kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
     78             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
     79 
     80     durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
     81     durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
     82     durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
     83     EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
     84     EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
     85                 durationProducer.mPastBuckets.end());
     86     const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
     87     EXPECT_EQ(2UL, buckets.size());
     88     EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
     89     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
     90     EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
     91     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
     92     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
     93     EXPECT_EQ(2LL, buckets[1].mDuration);
     94 }
     95 
     96 TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
     97     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     98     int64_t bucketStartTimeNs = 10000000000;
     99     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    100 
    101     DurationMetric metric;
    102     metric.set_id(1);
    103     metric.set_bucket(ONE_MINUTE);
    104     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
    105 
    106     int tagId = 1;
    107     LogEvent event1(tagId, bucketStartTimeNs + 1);
    108     event1.init();
    109     LogEvent event2(tagId, bucketStartTimeNs + 2);
    110     event2.init();
    111     LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
    112     event3.init();
    113     LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
    114     event4.init();
    115 
    116     FieldMatcher dimensions;
    117     DurationMetricProducer durationProducer(
    118             kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
    119             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
    120     durationProducer.mCondition = ConditionState::kFalse;
    121 
    122     EXPECT_FALSE(durationProducer.mCondition);
    123     EXPECT_FALSE(durationProducer.isConditionSliced());
    124 
    125     durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
    126     durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
    127     durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
    128     EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
    129 
    130     durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
    131     durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
    132     durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
    133     durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
    134     EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
    135     EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
    136                 durationProducer.mPastBuckets.end());
    137     const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    138     EXPECT_EQ(1UL, buckets2.size());
    139     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
    140     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
    141     EXPECT_EQ(1LL, buckets2[0].mDuration);
    142 }
    143 
    144 TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
    145     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    146     int64_t bucketStartTimeNs = 10000000000;
    147     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    148 
    149     DurationMetric metric;
    150     metric.set_id(1);
    151     metric.set_bucket(ONE_MINUTE);
    152     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
    153 
    154     int tagId = 1;
    155     LogEvent event1(tagId, bucketStartTimeNs + 1);
    156     event1.init();
    157     LogEvent event2(tagId, bucketStartTimeNs + 2);
    158     event2.init();
    159     LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
    160     event3.init();
    161     LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
    162     event4.init();
    163 
    164     FieldMatcher dimensions;
    165     DurationMetricProducer durationProducer(
    166             kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
    167             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
    168 
    169     EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
    170     EXPECT_FALSE(durationProducer.isConditionSliced());
    171 
    172     durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
    173     durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
    174     durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
    175     EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
    176 
    177     durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
    178     durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
    179     durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
    180     durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
    181     EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
    182     const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    183     EXPECT_EQ(1UL, buckets2.size());
    184     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
    185     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
    186     EXPECT_EQ(1LL, buckets2[0].mDuration);
    187 }
    188 
    189 TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
    190     /**
    191      * The duration starts from the first bucket, through the two partial buckets (10-70sec),
    192      * another bucket, and ends at the beginning of the next full bucket.
    193      * Expected buckets:
    194      *  - [10,25]: 14 secs
    195      *  - [25,70]: All 45 secs
    196      *  - [70,130]: All 60 secs
    197      *  - [130, 210]: Only 5 secs (event ended at 135sec)
    198      */
    199     int64_t bucketStartTimeNs = 10000000000;
    200     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    201     int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
    202     int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
    203     int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
    204 
    205     int tagId = 1;
    206 
    207     DurationMetric metric;
    208     metric.set_id(1);
    209     metric.set_bucket(ONE_MINUTE);
    210     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
    211     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    212     FieldMatcher dimensions;
    213     DurationMetricProducer durationProducer(
    214             kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
    215             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
    216 
    217     LogEvent start_event(tagId, startTimeNs);
    218     start_event.init();
    219     durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
    220     EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
    221     EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    222 
    223     durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
    224     EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    225     std::vector<DurationBucket> buckets =
    226             durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    227     EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
    228     EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs);
    229     EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration);
    230     EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    231 
    232     // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
    233     LogEvent end_event(tagId, endTimeNs);
    234     end_event.init();
    235     durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
    236     buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    237     EXPECT_EQ(3UL, buckets.size());
    238     EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
    239     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
    240     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration);
    241     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
    242     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
    243     EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
    244 }
    245 
    246 TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
    247     /**
    248      * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
    249      *  - [10,70]: 59 secs
    250      *  - [70,75]: 5 sec
    251      *  - [75,130]: 55 secs
    252      */
    253     int64_t bucketStartTimeNs = 10000000000;
    254     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    255     int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
    256     int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
    257     int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
    258 
    259     int tagId = 1;
    260 
    261     DurationMetric metric;
    262     metric.set_id(1);
    263     metric.set_bucket(ONE_MINUTE);
    264     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
    265     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    266     FieldMatcher dimensions;
    267     DurationMetricProducer durationProducer(
    268             kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
    269             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
    270 
    271     LogEvent start_event(tagId, startTimeNs);
    272     start_event.init();
    273     durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
    274     EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
    275     EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    276 
    277     durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
    278     EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    279     std::vector<DurationBucket> buckets =
    280             durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    281     EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
    282     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
    283     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
    284     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
    285     EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs);
    286     EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
    287     EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    288 
    289     // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
    290     LogEvent end_event(tagId, endTimeNs);
    291     end_event.init();
    292     durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
    293     buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    294     EXPECT_EQ(3UL, buckets.size());
    295     EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
    296     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
    297     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration);
    298 }
    299 
    300 TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
    301     sp<AlarmMonitor> alarmMonitor;
    302     int64_t bucketStartTimeNs = 10000000000;
    303     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    304     int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
    305     int64_t startTimeNs = bucketStartTimeNs + 1;
    306     int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
    307 
    308     int tagId = 1;
    309 
    310     // Setup metric with alert.
    311     DurationMetric metric;
    312     metric.set_id(1);
    313     metric.set_bucket(ONE_MINUTE);
    314     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
    315     Alert alert;
    316     alert.set_num_buckets(3);
    317     alert.set_trigger_if_sum_gt(2);
    318 
    319     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    320     FieldMatcher dimensions;
    321     DurationMetricProducer durationProducer(
    322             kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
    323             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
    324 
    325     sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
    326     EXPECT_TRUE(anomalyTracker != nullptr);
    327 
    328     LogEvent start_event(tagId, startTimeNs);
    329     start_event.init();
    330     durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
    331     durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
    332     // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
    333     LogEvent end_event(tagId, endTimeNs);
    334     end_event.init();
    335     durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
    336 
    337     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
    338               anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
    339 }
    340 
    341 TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
    342     int64_t bucketStartTimeNs = 10000000000;
    343     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    344     int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
    345     int64_t startTimeNs = bucketStartTimeNs + 1;
    346     int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
    347 
    348     int tagId = 1;
    349 
    350     DurationMetric metric;
    351     metric.set_id(1);
    352     metric.set_bucket(ONE_MINUTE);
    353     metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
    354     LogEvent event1(tagId, startTimeNs);
    355     event1.write("111");  // uid
    356     event1.init();
    357     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    358     FieldMatcher dimensions;
    359     DurationMetricProducer durationProducer(
    360             kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
    361             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
    362 
    363     LogEvent start_event(tagId, startTimeNs);
    364     start_event.init();
    365     durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
    366     EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
    367     EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    368 
    369     durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
    370     EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    371     EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    372 
    373     // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
    374     LogEvent end_event(tagId, endTimeNs);
    375     end_event.init();
    376     durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
    377     EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    378 
    379     durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
    380     std::vector<DurationBucket> buckets =
    381             durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    382     EXPECT_EQ(1UL, buckets.size());
    383     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
    384     EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
    385     EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
    386 }
    387 
    388 TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
    389     int64_t bucketStartTimeNs = 10000000000;
    390     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    391     int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
    392     int64_t startTimeNs = bucketStartTimeNs + 1;
    393     int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
    394 
    395     int tagId = 1;
    396 
    397     DurationMetric metric;
    398     metric.set_id(1);
    399     metric.set_bucket(ONE_MINUTE);
    400     metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
    401     LogEvent event1(tagId, startTimeNs);
    402     event1.write("111");  // uid
    403     event1.init();
    404     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    405     FieldMatcher dimensions;
    406     DurationMetricProducer durationProducer(
    407             kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
    408             3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
    409 
    410     LogEvent start_event(tagId, startTimeNs);
    411     start_event.init();
    412     durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
    413     EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
    414     EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    415 
    416     durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
    417     EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    418     EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    419 
    420     // Stop occurs in the same partial bucket as created for the app upgrade.
    421     LogEvent end_event(tagId, endTimeNs);
    422     end_event.init();
    423     durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
    424     EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    425     EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
    426 
    427     durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
    428     std::vector<DurationBucket> buckets =
    429             durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    430     EXPECT_EQ(1UL, buckets.size());
    431     EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs);
    432     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
    433     EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
    434 }
    435 
    436 }  // namespace statsd
    437 }  // namespace os
    438 }  // namespace android
    439 #else
    440 GTEST_LOG_(INFO) << "This test does nothing.\n";
    441 #endif
    442