1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.cts.statsd.metric; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import android.cts.statsd.atom.DeviceAtomTestCase; 21 22 import com.android.internal.os.StatsdConfigProto; 23 import com.android.internal.os.StatsdConfigProto.AtomMatcher; 24 import com.android.internal.os.StatsdConfigProto.FieldMatcher; 25 import com.android.internal.os.StatsdConfigProto.FieldValueMatcher; 26 import com.android.internal.os.StatsdConfigProto.Position; 27 import com.android.internal.os.StatsdConfigProto.Predicate; 28 import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher; 29 import com.android.internal.os.StatsdConfigProto.SimplePredicate; 30 import com.android.os.AtomsProto.AppBreadcrumbReported; 31 import com.android.os.AtomsProto.Atom; 32 import com.android.os.StatsLog.ConfigMetricsReport; 33 import com.android.os.StatsLog.ConfigMetricsReportList; 34 import com.android.os.StatsLog.DurationBucketInfo; 35 import com.android.os.StatsLog.StatsLogReport; 36 import com.android.tradefed.device.DeviceNotAvailableException; 37 import com.android.tradefed.log.LogUtil; 38 39 import com.google.common.collect.Range; 40 41 import java.util.List; 42 43 public class DurationMetricsTests extends DeviceAtomTestCase { 44 45 private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0; 46 private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1; 47 private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2; 48 private static final int APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID = 3; 49 50 public void testDurationMetric() throws Exception { 51 final int label = 1; 52 // Add AtomMatchers. 53 AtomMatcher startAtomMatcher = 54 MetricsUtils.startAtomMatcherWithLabel(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID, label); 55 AtomMatcher stopAtomMatcher = 56 MetricsUtils.stopAtomMatcherWithLabel(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID, label); 57 58 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder(); 59 builder.addAtomMatcher(startAtomMatcher); 60 builder.addAtomMatcher(stopAtomMatcher); 61 62 // Add Predicates. 63 SimplePredicate simplePredicate = SimplePredicate.newBuilder() 64 .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID) 65 .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID) 66 .build(); 67 Predicate predicate = Predicate.newBuilder() 68 .setId(MetricsUtils.StringToId("Predicate")) 69 .setSimplePredicate(simplePredicate) 70 .build(); 71 builder.addPredicate(predicate); 72 73 // Add DurationMetric. 74 builder.addDurationMetric( 75 StatsdConfigProto.DurationMetric.newBuilder() 76 .setId(MetricsUtils.DURATION_METRIC_ID) 77 .setWhat(predicate.getId()) 78 .setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM) 79 .setBucket(StatsdConfigProto.TimeUnit.CTS)); 80 81 // Upload config. 82 uploadConfig(builder); 83 84 // Create AppBreadcrumbReported Start/Stop events. 85 doAppBreadcrumbReportedStart(label); 86 Thread.sleep(2000); 87 doAppBreadcrumbReportedStop(label); 88 89 // Wait for the metrics to propagate to statsd. 90 Thread.sleep(2000); 91 92 StatsLogReport metricReport = getStatsLogReport(); 93 assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID); 94 LogUtil.CLog.d("Received the following data: " + metricReport.toString()); 95 assertThat(metricReport.hasDurationMetrics()).isTrue(); 96 StatsLogReport.DurationMetricDataWrapper durationData 97 = metricReport.getDurationMetrics(); 98 assertThat(durationData.getDataCount()).isEqualTo(1); 99 assertThat(durationData.getData(0).getBucketInfo(0).getDurationNanos()) 100 .isIn(Range.open(0L, (long)1e9)); 101 } 102 103 public void testDurationMetricWithCondition() throws Exception { 104 final int durationLabel = 1; 105 final int conditionLabel = 2; 106 107 // Add AtomMatchers. 108 AtomMatcher startAtomMatcher = MetricsUtils.startAtomMatcherWithLabel( 109 APP_BREADCRUMB_REPORTED_A_MATCH_START_ID, durationLabel); 110 AtomMatcher stopAtomMatcher = MetricsUtils.stopAtomMatcherWithLabel( 111 APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID, durationLabel); 112 AtomMatcher conditionStartAtomMatcher = MetricsUtils.startAtomMatcherWithLabel( 113 APP_BREADCRUMB_REPORTED_B_MATCH_START_ID, conditionLabel); 114 AtomMatcher conditionStopAtomMatcher = MetricsUtils.stopAtomMatcherWithLabel( 115 APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID, conditionLabel); 116 117 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder() 118 .addAtomMatcher(startAtomMatcher) 119 .addAtomMatcher(stopAtomMatcher) 120 .addAtomMatcher(conditionStartAtomMatcher) 121 .addAtomMatcher(conditionStopAtomMatcher); 122 123 // Add Predicates. 124 SimplePredicate simplePredicate = SimplePredicate.newBuilder() 125 .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID) 126 .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID) 127 .build(); 128 Predicate predicate = Predicate.newBuilder() 129 .setId(MetricsUtils.StringToId("Predicate")) 130 .setSimplePredicate(simplePredicate) 131 .build(); 132 133 SimplePredicate conditionSimplePredicate = SimplePredicate.newBuilder() 134 .setStart(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID) 135 .setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID) 136 .build(); 137 Predicate conditionPredicate = Predicate.newBuilder() 138 .setId(MetricsUtils.StringToId("ConditionPredicate")) 139 .setSimplePredicate(conditionSimplePredicate) 140 .build(); 141 142 builder 143 .addPredicate(predicate) 144 .addPredicate(conditionPredicate); 145 146 // Add DurationMetric. 147 builder 148 .addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder() 149 .setId(MetricsUtils.DURATION_METRIC_ID) 150 .setWhat(predicate.getId()) 151 .setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM) 152 .setBucket(StatsdConfigProto.TimeUnit.CTS) 153 .setCondition(conditionPredicate.getId()) 154 ); 155 156 // Upload config. 157 uploadConfig(builder); 158 159 // Start uncounted duration. 160 doAppBreadcrumbReportedStart(durationLabel); 161 Thread.sleep(10); 162 163 Thread.sleep(2_000); 164 165 // Stop uncounted duration. 166 doAppBreadcrumbReportedStop(durationLabel); 167 Thread.sleep(10); 168 169 // Set the condition to true. 170 doAppBreadcrumbReportedStart(conditionLabel); 171 Thread.sleep(10); 172 173 // Start counted duration. 174 doAppBreadcrumbReportedStart(durationLabel); 175 Thread.sleep(10); 176 177 Thread.sleep(2_000); 178 179 // Stop counted duration. 180 doAppBreadcrumbReportedStop(durationLabel); 181 Thread.sleep(10); 182 183 // Set the condition to false. 184 doAppBreadcrumbReportedStop(conditionLabel); 185 Thread.sleep(10); 186 187 // Start uncounted duration. 188 doAppBreadcrumbReportedStart(durationLabel); 189 Thread.sleep(10); 190 191 Thread.sleep(2_000); 192 193 // Stop uncounted duration. 194 doAppBreadcrumbReportedStop(durationLabel); 195 Thread.sleep(10); 196 197 Thread.sleep(2_000); 198 StatsLogReport metricReport = getStatsLogReport(); 199 assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID); 200 LogUtil.CLog.d("Received the following data: " + metricReport.toString()); 201 assertThat(metricReport.hasDurationMetrics()).isTrue(); 202 StatsLogReport.DurationMetricDataWrapper durationData 203 = metricReport.getDurationMetrics(); 204 assertThat(durationData.getDataCount()).isEqualTo(1); 205 long totalDuration = durationData.getData(0).getBucketInfoList().stream() 206 .mapToLong(bucketInfo -> bucketInfo.getDurationNanos()) 207 .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long)1e9))) 208 .sum(); 209 assertThat(totalDuration).isIn(Range.open((long)2e9, (long)3e9)); 210 } 211 212 public void testDurationMetricWithActivation() throws Exception { 213 final int activationMatcherId = 5; 214 final int activationMatcherLabel = 5; 215 final int ttlSec = 5; 216 final int durationLabel = 1; 217 218 // Add AtomMatchers. 219 AtomMatcher startAtomMatcher = MetricsUtils.startAtomMatcherWithLabel( 220 APP_BREADCRUMB_REPORTED_A_MATCH_START_ID, durationLabel); 221 AtomMatcher stopAtomMatcher = MetricsUtils.stopAtomMatcherWithLabel( 222 APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID, durationLabel); 223 StatsdConfigProto.AtomMatcher activationMatcher = 224 MetricsUtils.appBreadcrumbMatcherWithLabel(activationMatcherId, 225 activationMatcherLabel); 226 227 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder() 228 .addAtomMatcher(startAtomMatcher) 229 .addAtomMatcher(stopAtomMatcher) 230 .addAtomMatcher(activationMatcher); 231 232 // Add Predicates. 233 SimplePredicate simplePredicate = SimplePredicate.newBuilder() 234 .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID) 235 .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID) 236 .build(); 237 Predicate predicate = Predicate.newBuilder() 238 .setId(MetricsUtils.StringToId("Predicate")) 239 .setSimplePredicate(simplePredicate) 240 .build(); 241 builder.addPredicate(predicate); 242 243 // Add DurationMetric. 244 builder 245 .addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder() 246 .setId(MetricsUtils.DURATION_METRIC_ID) 247 .setWhat(predicate.getId()) 248 .setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM) 249 .setBucket(StatsdConfigProto.TimeUnit.CTS) 250 ) 251 .addMetricActivation(StatsdConfigProto.MetricActivation.newBuilder() 252 .setMetricId(MetricsUtils.DURATION_METRIC_ID) 253 .addEventActivation(StatsdConfigProto.EventActivation.newBuilder() 254 .setAtomMatcherId(activationMatcherId) 255 .setActivationType( 256 StatsdConfigProto.ActivationType.ACTIVATE_IMMEDIATELY) 257 .setTtlSeconds(ttlSec))); 258 259 // Upload config. 260 uploadConfig(builder); 261 262 // Start uncounted duration. 263 doAppBreadcrumbReportedStart(durationLabel); 264 Thread.sleep(10); 265 266 Thread.sleep(2_000); 267 268 // Stop uncounted duration. 269 doAppBreadcrumbReportedStop(durationLabel); 270 Thread.sleep(10); 271 272 // Activate the metric. 273 doAppBreadcrumbReported(activationMatcherLabel); 274 Thread.sleep(10); 275 276 // Start counted duration. 277 doAppBreadcrumbReportedStart(durationLabel); 278 Thread.sleep(10); 279 280 Thread.sleep(2_000); 281 282 // Stop counted duration. 283 doAppBreadcrumbReportedStop(durationLabel); 284 Thread.sleep(10); 285 286 Thread.sleep(2_000); 287 StatsLogReport metricReport = getStatsLogReport(); 288 assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID); 289 LogUtil.CLog.d("Received the following data: " + metricReport.toString()); 290 assertThat(metricReport.hasDurationMetrics()).isTrue(); 291 StatsLogReport.DurationMetricDataWrapper durationData 292 = metricReport.getDurationMetrics(); 293 assertThat(durationData.getDataCount()).isEqualTo(1); 294 long totalDuration = durationData.getData(0).getBucketInfoList().stream() 295 .mapToLong(bucketInfo -> bucketInfo.getDurationNanos()) 296 .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long)1e9))) 297 .sum(); 298 assertThat(totalDuration).isIn(Range.open((long)2e9, (long)3e9)); 299 } 300 301 public void testDurationMetricWithConditionAndActivation() throws Exception { 302 final int durationLabel = 1; 303 final int conditionLabel = 2; 304 final int activationMatcherId = 5; 305 final int activationMatcherLabel = 5; 306 final int ttlSec = 5; 307 308 // Add AtomMatchers. 309 AtomMatcher startAtomMatcher = MetricsUtils.startAtomMatcherWithLabel( 310 APP_BREADCRUMB_REPORTED_A_MATCH_START_ID, durationLabel); 311 AtomMatcher stopAtomMatcher = MetricsUtils.stopAtomMatcherWithLabel( 312 APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID, durationLabel); 313 AtomMatcher conditionStartAtomMatcher = MetricsUtils.startAtomMatcherWithLabel( 314 APP_BREADCRUMB_REPORTED_B_MATCH_START_ID, conditionLabel); 315 AtomMatcher conditionStopAtomMatcher = MetricsUtils.stopAtomMatcherWithLabel( 316 APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID, conditionLabel); 317 StatsdConfigProto.AtomMatcher activationMatcher = 318 MetricsUtils.appBreadcrumbMatcherWithLabel(activationMatcherId, 319 activationMatcherLabel); 320 321 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder() 322 .addAtomMatcher(startAtomMatcher) 323 .addAtomMatcher(stopAtomMatcher) 324 .addAtomMatcher(conditionStartAtomMatcher) 325 .addAtomMatcher(conditionStopAtomMatcher) 326 .addAtomMatcher(activationMatcher); 327 328 // Add Predicates. 329 SimplePredicate simplePredicate = SimplePredicate.newBuilder() 330 .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID) 331 .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID) 332 .build(); 333 Predicate predicate = Predicate.newBuilder() 334 .setId(MetricsUtils.StringToId("Predicate")) 335 .setSimplePredicate(simplePredicate) 336 .build(); 337 builder.addPredicate(predicate); 338 339 SimplePredicate conditionSimplePredicate = SimplePredicate.newBuilder() 340 .setStart(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID) 341 .setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID) 342 .build(); 343 Predicate conditionPredicate = Predicate.newBuilder() 344 .setId(MetricsUtils.StringToId("ConditionPredicate")) 345 .setSimplePredicate(conditionSimplePredicate) 346 .build(); 347 builder.addPredicate(conditionPredicate); 348 349 // Add DurationMetric. 350 builder 351 .addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder() 352 .setId(MetricsUtils.DURATION_METRIC_ID) 353 .setWhat(predicate.getId()) 354 .setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM) 355 .setBucket(StatsdConfigProto.TimeUnit.CTS) 356 .setCondition(conditionPredicate.getId()) 357 ) 358 .addMetricActivation(StatsdConfigProto.MetricActivation.newBuilder() 359 .setMetricId(MetricsUtils.DURATION_METRIC_ID) 360 .addEventActivation(StatsdConfigProto.EventActivation.newBuilder() 361 .setAtomMatcherId(activationMatcherId) 362 .setActivationType( 363 StatsdConfigProto.ActivationType.ACTIVATE_IMMEDIATELY) 364 .setTtlSeconds(ttlSec))); 365 366 // Upload config. 367 uploadConfig(builder); 368 369 // Activate the metric. 370 doAppBreadcrumbReported(activationMatcherLabel); 371 Thread.sleep(10); 372 373 // Set the condition to true. 374 doAppBreadcrumbReportedStart(conditionLabel); 375 Thread.sleep(10); 376 377 // Start counted duration. 378 doAppBreadcrumbReportedStart(durationLabel); 379 Thread.sleep(10); 380 381 Thread.sleep(2_000); 382 383 // Stop counted duration. 384 doAppBreadcrumbReportedStop(durationLabel); 385 Thread.sleep(10); 386 387 // Set the condition to false. 388 doAppBreadcrumbReportedStop(conditionLabel); 389 Thread.sleep(10); 390 391 // Start uncounted duration. 392 doAppBreadcrumbReportedStart(durationLabel); 393 Thread.sleep(10); 394 395 Thread.sleep(2_000); 396 397 // Stop uncounted duration. 398 doAppBreadcrumbReportedStop(durationLabel); 399 Thread.sleep(10); 400 401 // Let the metric deactivate. 402 Thread.sleep(ttlSec * 1000); 403 //doAppBreadcrumbReported(99); // TODO: maybe remove? 404 //Thread.sleep(10); 405 406 // Start uncounted duration. 407 doAppBreadcrumbReportedStart(durationLabel); 408 Thread.sleep(10); 409 410 Thread.sleep(2_000); 411 412 // Stop uncounted duration. 413 doAppBreadcrumbReportedStop(durationLabel); 414 Thread.sleep(10); 415 416 // Set condition to true again. 417 doAppBreadcrumbReportedStart(conditionLabel); 418 Thread.sleep(10); 419 420 // Start uncounted duration. 421 doAppBreadcrumbReportedStart(durationLabel); 422 Thread.sleep(10); 423 424 Thread.sleep(2_000); 425 426 // Stop uncounted duration. 427 doAppBreadcrumbReportedStop(durationLabel); 428 Thread.sleep(10); 429 430 // Activate the metric. 431 doAppBreadcrumbReported(activationMatcherLabel); 432 Thread.sleep(10); 433 434 // Start counted duration. 435 doAppBreadcrumbReportedStart(durationLabel); 436 Thread.sleep(10); 437 438 Thread.sleep(2_000); 439 440 // Stop counted duration. 441 doAppBreadcrumbReportedStop(durationLabel); 442 Thread.sleep(10); 443 444 // Let the metric deactivate. 445 Thread.sleep(ttlSec * 1000); 446 447 // Start uncounted duration. 448 doAppBreadcrumbReportedStart(durationLabel); 449 Thread.sleep(10); 450 451 Thread.sleep(2_000); 452 453 // Stop uncounted duration. 454 doAppBreadcrumbReportedStop(durationLabel); 455 Thread.sleep(10); 456 457 // Wait for the metrics to propagate to statsd. 458 Thread.sleep(2000); 459 460 StatsLogReport metricReport = getStatsLogReport(); 461 LogUtil.CLog.d("Received the following data: " + metricReport.toString()); 462 assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID); 463 assertThat(metricReport.hasDurationMetrics()).isTrue(); 464 StatsLogReport.DurationMetricDataWrapper durationData 465 = metricReport.getDurationMetrics(); 466 assertThat(durationData.getDataCount()).isEqualTo(1); 467 long totalDuration = durationData.getData(0).getBucketInfoList().stream() 468 .mapToLong(bucketInfo -> bucketInfo.getDurationNanos()) 469 .peek(durationNs -> assertThat(durationNs).isIn(Range.openClosed(0L, (long)1e9))) 470 .sum(); 471 assertThat(totalDuration).isIn(Range.open((long)4e9, (long)5e9)); 472 } 473 474 public void testDurationMetricWithDimension() throws Exception { 475 // Add AtomMatchers. 476 AtomMatcher startAtomMatcherA = 477 MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID); 478 AtomMatcher stopAtomMatcherA = 479 MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID); 480 AtomMatcher startAtomMatcherB = 481 MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID); 482 AtomMatcher stopAtomMatcherB = 483 MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID); 484 485 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder(); 486 builder.addAtomMatcher(startAtomMatcherA); 487 builder.addAtomMatcher(stopAtomMatcherA); 488 builder.addAtomMatcher(startAtomMatcherB); 489 builder.addAtomMatcher(stopAtomMatcherB); 490 491 // Add Predicates. 492 SimplePredicate simplePredicateA = SimplePredicate.newBuilder() 493 .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID) 494 .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID) 495 .build(); 496 Predicate predicateA = Predicate.newBuilder() 497 .setId(MetricsUtils.StringToId("Predicate_A")) 498 .setSimplePredicate(simplePredicateA) 499 .build(); 500 builder.addPredicate(predicateA); 501 502 FieldMatcher.Builder dimensionsBuilder = FieldMatcher.newBuilder() 503 .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER); 504 dimensionsBuilder 505 .addChild(FieldMatcher.newBuilder().setField( 506 AppBreadcrumbReported.LABEL_FIELD_NUMBER)); 507 Predicate predicateB = 508 Predicate.newBuilder() 509 .setId(MetricsUtils.StringToId("Predicate_B")) 510 .setSimplePredicate(SimplePredicate.newBuilder() 511 .setStart(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID) 512 .setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID) 513 .setDimensions(dimensionsBuilder.build()) 514 .build()) 515 .build(); 516 builder.addPredicate(predicateB); 517 518 // Add DurationMetric. 519 builder.addDurationMetric( 520 StatsdConfigProto.DurationMetric.newBuilder() 521 .setId(MetricsUtils.DURATION_METRIC_ID) 522 .setWhat(predicateB.getId()) 523 .setCondition(predicateA.getId()) 524 .setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM) 525 .setBucket(StatsdConfigProto.TimeUnit.CTS) 526 .setDimensionsInWhat( 527 FieldMatcher.newBuilder() 528 .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER) 529 .addChild(FieldMatcher.newBuilder().setField( 530 AppBreadcrumbReported.LABEL_FIELD_NUMBER)))); 531 532 // Upload config. 533 uploadConfig(builder); 534 535 // Trigger events. 536 doAppBreadcrumbReportedStart(1); 537 Thread.sleep(2000); 538 doAppBreadcrumbReportedStart(2); 539 Thread.sleep(2000); 540 doAppBreadcrumbReportedStop(1); 541 Thread.sleep(2000); 542 doAppBreadcrumbReportedStop(2); 543 544 // Wait for the metrics to propagate to statsd. 545 Thread.sleep(2000); 546 547 StatsLogReport metricReport = getStatsLogReport(); 548 assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.DURATION_METRIC_ID); 549 assertThat(metricReport.hasDurationMetrics()).isTrue(); 550 StatsLogReport.DurationMetricDataWrapper durationData 551 = metricReport.getDurationMetrics(); 552 assertThat(durationData.getDataCount()).isEqualTo(2); 553 assertThat(durationData.getData(0).getBucketInfoCount()).isGreaterThan(3); 554 assertThat(durationData.getData(1).getBucketInfoCount()).isGreaterThan(3); 555 long totalDuration = 0; 556 for (DurationBucketInfo bucketInfo : durationData.getData(0).getBucketInfoList()) { 557 assertThat(bucketInfo.getDurationNanos()).isIn(Range.openClosed(0L, (long) 1e9)); 558 totalDuration += bucketInfo.getDurationNanos(); 559 } 560 // Duration for both labels is expected to be 4s. 561 assertThat(totalDuration).isIn(Range.open((long) 3e9, (long) 8e9)); 562 totalDuration = 0; 563 for (DurationBucketInfo bucketInfo : durationData.getData(1).getBucketInfoList()) { 564 assertThat(bucketInfo.getDurationNanos()).isIn(Range.openClosed(0L, (long) 1e9)); 565 totalDuration += bucketInfo.getDurationNanos(); 566 } 567 assertThat(totalDuration).isIn(Range.open((long) 3e9, (long) 8e9)); 568 } 569 } 570