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