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 android.cts.statsd.atom.DeviceAtomTestCase; 19 20 import com.android.internal.os.StatsdConfigProto; 21 import com.android.os.AtomsProto.Atom; 22 import com.android.os.AtomsProto.AppBreadcrumbReported; 23 import com.android.os.StatsLog; 24 import com.android.os.StatsLog.ConfigMetricsReport; 25 import com.android.os.StatsLog.ConfigMetricsReportList; 26 import com.android.os.StatsLog.CountBucketInfo; 27 import com.android.os.StatsLog.CountMetricData; 28 import com.android.os.StatsLog.StatsLogReport; 29 import com.android.tradefed.device.DeviceNotAvailableException; 30 import com.android.tradefed.log.LogUtil; 31 32 import java.util.Arrays; 33 import java.util.List; 34 35 public class CountMetricsTests extends DeviceAtomTestCase { 36 37 public void testSimpleEventCountMetric() throws Exception { 38 if (statsdDisabled()) { 39 return; 40 } 41 int matcherId = 1; 42 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder(); 43 builder.addCountMetric(StatsdConfigProto.CountMetric.newBuilder() 44 .setId(MetricsUtils.COUNT_METRIC_ID) 45 .setBucket(StatsdConfigProto.TimeUnit.CTS) 46 .setWhat(matcherId)) 47 .addAtomMatcher(MetricsUtils.simpleAtomMatcher(matcherId)); 48 uploadConfig(builder); 49 50 doAppBreadcrumbReportedStart(0); 51 doAppBreadcrumbReportedStop(0); 52 Thread.sleep(2000); // Wait for the metrics to propagate to statsd. 53 54 StatsLogReport metricReport = getStatsLogReport(); 55 LogUtil.CLog.d("Got the following stats log report: \n" + metricReport.toString()); 56 assertEquals(MetricsUtils.COUNT_METRIC_ID, metricReport.getMetricId()); 57 assertTrue(metricReport.hasCountMetrics()); 58 59 StatsLogReport.CountMetricDataWrapper countData = metricReport.getCountMetrics(); 60 61 assertTrue(countData.getDataCount() > 0); 62 assertEquals(2, countData.getData(0).getBucketInfo(0).getCount()); 63 } 64 public void testEventCountWithCondition() throws Exception { 65 if (statsdDisabled()) { 66 return; 67 } 68 int startMatcherId = 1; 69 int endMatcherId = 2; 70 int whatMatcherId = 3; 71 int conditionId = 4; 72 73 StatsdConfigProto.AtomMatcher whatMatcher = 74 MetricsUtils.unspecifiedAtomMatcher(whatMatcherId); 75 76 StatsdConfigProto.AtomMatcher predicateStartMatcher = 77 MetricsUtils.startAtomMatcher(startMatcherId); 78 79 StatsdConfigProto.AtomMatcher predicateEndMatcher = 80 MetricsUtils.stopAtomMatcher(endMatcherId); 81 82 StatsdConfigProto.Predicate p = StatsdConfigProto.Predicate.newBuilder() 83 .setSimplePredicate(StatsdConfigProto.SimplePredicate.newBuilder() 84 .setStart(startMatcherId) 85 .setStop(endMatcherId) 86 .setCountNesting(false)) 87 .setId(conditionId) 88 .build(); 89 90 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder() 91 .addCountMetric(StatsdConfigProto.CountMetric.newBuilder() 92 .setId(MetricsUtils.COUNT_METRIC_ID) 93 .setBucket(StatsdConfigProto.TimeUnit.CTS) 94 .setWhat(whatMatcherId) 95 .setCondition(conditionId)) 96 .addAtomMatcher(whatMatcher) 97 .addAtomMatcher(predicateStartMatcher) 98 .addAtomMatcher(predicateEndMatcher) 99 .addPredicate(p); 100 101 uploadConfig(builder); 102 103 doAppBreadcrumbReported(0, AppBreadcrumbReported.State.UNSPECIFIED.ordinal()); 104 Thread.sleep(10); 105 doAppBreadcrumbReportedStart(0); 106 Thread.sleep(10); 107 doAppBreadcrumbReported(0, AppBreadcrumbReported.State.UNSPECIFIED.ordinal()); 108 Thread.sleep(10); 109 doAppBreadcrumbReportedStop(0); 110 Thread.sleep(10); 111 doAppBreadcrumbReported(0, AppBreadcrumbReported.State.UNSPECIFIED.ordinal()); 112 Thread.sleep(2000); // Wait for the metrics to propagate to statsd. 113 114 StatsLogReport metricReport = getStatsLogReport(); 115 assertEquals(MetricsUtils.COUNT_METRIC_ID, metricReport.getMetricId()); 116 assertTrue(metricReport.hasCountMetrics()); 117 118 StatsLogReport.CountMetricDataWrapper countData = metricReport.getCountMetrics(); 119 120 assertTrue(countData.getDataCount() > 0); 121 assertEquals(1, countData.getData(0).getBucketInfo(0).getCount()); 122 } 123 124 public void testEventCountWithConditionAndActivation() throws Exception { 125 if (statsdDisabled()) { 126 return; 127 } 128 int startMatcherId = 1; 129 int startMatcherLabel = 1; 130 int endMatcherId = 2; 131 int endMatcherLabel = 2; 132 int whatMatcherId = 3; 133 int whatMatcherLabel = 3; 134 int conditionId = 4; 135 int activationMatcherId = 5; 136 int activationMatcherLabel = 5; 137 int ttlSec = 5; 138 139 StatsdConfigProto.AtomMatcher whatMatcher = 140 MetricsUtils.appBreadcrumbMatcherWithLabel(whatMatcherId, whatMatcherLabel); 141 142 StatsdConfigProto.AtomMatcher predicateStartMatcher = 143 MetricsUtils.startAtomMatcherWithLabel(startMatcherId, startMatcherLabel); 144 145 StatsdConfigProto.AtomMatcher predicateEndMatcher = 146 MetricsUtils.stopAtomMatcherWithLabel(endMatcherId, endMatcherLabel); 147 148 StatsdConfigProto.AtomMatcher activationMatcher = 149 MetricsUtils.appBreadcrumbMatcherWithLabel(activationMatcherId, 150 activationMatcherLabel); 151 152 StatsdConfigProto.Predicate p = StatsdConfigProto.Predicate.newBuilder() 153 .setSimplePredicate(StatsdConfigProto.SimplePredicate.newBuilder() 154 .setStart(startMatcherId) 155 .setStop(endMatcherId) 156 .setCountNesting(false)) 157 .setId(conditionId) 158 .build(); 159 160 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder() 161 .addCountMetric(StatsdConfigProto.CountMetric.newBuilder() 162 .setId(MetricsUtils.COUNT_METRIC_ID) 163 .setBucket(StatsdConfigProto.TimeUnit.CTS) 164 .setWhat(whatMatcherId) 165 .setCondition(conditionId) 166 ) 167 .addAtomMatcher(whatMatcher) 168 .addAtomMatcher(predicateStartMatcher) 169 .addAtomMatcher(predicateEndMatcher) 170 .addAtomMatcher(activationMatcher) 171 .addPredicate(p) 172 .addMetricActivation(StatsdConfigProto.MetricActivation.newBuilder() 173 .setMetricId(MetricsUtils.COUNT_METRIC_ID) 174 .setActivationType(StatsdConfigProto.ActivationType.ACTIVATE_IMMEDIATELY) 175 .addEventActivation(StatsdConfigProto.EventActivation.newBuilder() 176 .setAtomMatcherId(activationMatcherId) 177 .setTtlSeconds(ttlSec))); 178 179 uploadConfig(builder); 180 181 // Activate the metric. 182 doAppBreadcrumbReported(activationMatcherLabel); 183 Thread.sleep(10); 184 185 // Set the condition to true. 186 doAppBreadcrumbReportedStart(startMatcherLabel); 187 Thread.sleep(10); 188 189 // Log an event that should be counted. Bucket 1 Count 1. 190 doAppBreadcrumbReported(whatMatcherLabel); 191 Thread.sleep(10); 192 193 // Log an event that should be counted. Bucket 1 Count 2. 194 doAppBreadcrumbReported(whatMatcherLabel); 195 Thread.sleep(10); 196 197 // Set the condition to false. 198 doAppBreadcrumbReportedStop(endMatcherLabel); 199 Thread.sleep(10); 200 201 // Log an event that should not be counted because condition is false. 202 doAppBreadcrumbReported(whatMatcherLabel); 203 Thread.sleep(10); 204 205 // Let the metric deactivate. 206 Thread.sleep(ttlSec * 1000); 207 208 // Log an event that should not be counted. 209 doAppBreadcrumbReported(whatMatcherLabel); 210 Thread.sleep(10); 211 212 // Condition to true again. 213 doAppBreadcrumbReportedStart(startMatcherLabel); 214 Thread.sleep(10); 215 216 // Event should not be counted, metric is still not active. 217 doAppBreadcrumbReported(whatMatcherLabel); 218 Thread.sleep(10); 219 220 // Activate the metric. 221 doAppBreadcrumbReported(activationMatcherLabel); 222 Thread.sleep(10); 223 224 // Log an event that should be counted. 225 doAppBreadcrumbReported(whatMatcherLabel); 226 Thread.sleep(10); 227 228 // Let the metric deactivate. 229 Thread.sleep(ttlSec * 1000); 230 231 // Log an event that should not be counted. 232 doAppBreadcrumbReported(whatMatcherLabel); 233 Thread.sleep(10); 234 235 // Wait for the metrics to propagate to statsd. 236 Thread.sleep(2000); 237 238 StatsLogReport metricReport = getStatsLogReport(); 239 assertEquals(MetricsUtils.COUNT_METRIC_ID, metricReport.getMetricId()); 240 LogUtil.CLog.d("Received the following data: " + metricReport.toString()); 241 assertTrue(metricReport.hasCountMetrics()); 242 assertFalse(metricReport.getIsActive()); 243 244 StatsLogReport.CountMetricDataWrapper countData = metricReport.getCountMetrics(); 245 assertEquals(1, countData.getDataCount()); 246 assertEquals(2, countData.getData(0).getBucketInfoCount()); 247 assertEquals(2, countData.getData(0).getBucketInfo(0).getCount()); 248 assertEquals(1, countData.getData(0).getBucketInfo(1).getCount()); 249 } 250 251 public void testPartialBucketCountMetric() throws Exception { 252 if (statsdDisabled()) { 253 return; 254 } 255 int matcherId = 1; 256 StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder(); 257 builder.addCountMetric(StatsdConfigProto.CountMetric.newBuilder() 258 .setId(MetricsUtils.COUNT_METRIC_ID) 259 .setBucket(StatsdConfigProto.TimeUnit.ONE_DAY) // Should ensure partial bucket. 260 .setWhat(matcherId)) 261 .addAtomMatcher(MetricsUtils.simpleAtomMatcher(matcherId)); 262 uploadConfig(builder); 263 264 doAppBreadcrumbReportedStart(0); 265 266 builder.getCountMetricBuilder(0).setBucket(StatsdConfigProto.TimeUnit.CTS); 267 uploadConfig(builder); // The count metric had a partial bucket. 268 doAppBreadcrumbReportedStart(0); 269 Thread.sleep(10); 270 doAppBreadcrumbReportedStart(0); 271 Thread.sleep(WAIT_TIME_LONG); // Finish the current bucket. 272 273 ConfigMetricsReportList reports = getReportList(); 274 LogUtil.CLog.d("Got following report list: " + reports.toString()); 275 276 assertEquals("Expected 2 reports, got " + reports.getReportsCount(), 277 2, reports.getReportsCount()); 278 boolean inOrder = reports.getReports(0).getCurrentReportWallClockNanos() < 279 reports.getReports(1).getCurrentReportWallClockNanos(); 280 281 // Only 1 metric, so there should only be 1 StatsLogReport. 282 for (ConfigMetricsReport report : reports.getReportsList()) { 283 assertEquals("Expected 1 StatsLogReport in each ConfigMetricsReport", 284 1, report.getMetricsCount()); 285 assertEquals("Expected 1 CountMetricData in each report", 286 1, report.getMetrics(0).getCountMetrics().getDataCount()); 287 } 288 CountMetricData data1 = 289 reports.getReports(inOrder? 0 : 1).getMetrics(0).getCountMetrics().getData(0); 290 CountMetricData data2 = 291 reports.getReports(inOrder? 1 : 0).getMetrics(0).getCountMetrics().getData(0); 292 // Data1 should have only 1 bucket, and it should be a partial bucket. 293 // The count should be 1. 294 assertEquals("First report should only have 1 bucket", 1, data1.getBucketInfoCount()); 295 CountBucketInfo bucketInfo = data1.getBucketInfo(0); 296 assertEquals("First report should have a count of 1", 1, bucketInfo.getCount()); 297 assertTrue("First report's bucket should be less than 1 day", 298 bucketInfo.getEndBucketElapsedNanos() < 299 (bucketInfo.getStartBucketElapsedNanos() + 1_000_000_000L * 60L * 60L * 24L)); 300 301 //Second report should have a count of 2. 302 assertTrue("Second report should have at most 2 buckets", data2.getBucketInfoCount() < 3); 303 int totalCount = 0; 304 for (CountBucketInfo bucket : data2.getBucketInfoList()) { 305 totalCount += bucket.getCount(); 306 } 307 assertEquals("Second report should have a count of 2", 2, totalCount); 308 } 309 } 310