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 <gtest/gtest.h> 16 17#include "src/StatsLogProcessor.h" 18#include "src/stats_log_util.h" 19#include "tests/statsd_test_util.h" 20 21#include <vector> 22 23namespace android { 24namespace os { 25namespace statsd { 26 27#ifdef __ANDROID__ 28 29namespace { 30 31StatsdConfig CreateDurationMetricConfig_NoLink_SimpleCondition( 32 DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) { 33 StatsdConfig config; 34 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. 35 *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); 36 *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); 37 *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); 38 *config.add_atom_matcher() = CreateSyncEndAtomMatcher(); 39 40 auto scheduledJobPredicate = CreateScheduledJobPredicate(); 41 auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions(); 42 dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED); 43 dimensions->add_child()->set_field(2); // job name field. 44 45 auto isSyncingPredicate = CreateIsSyncingPredicate(); 46 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions(); 47 *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED, 48 {Position::FIRST}); 49 if (addExtraDimensionInCondition) { 50 syncDimension->add_child()->set_field(2 /* name field*/); 51 } 52 53 *config.add_predicate() = scheduledJobPredicate; 54 *config.add_predicate() = isSyncingPredicate; 55 56 auto metric = config.add_duration_metric(); 57 metric->set_bucket(FIVE_MINUTES); 58 metric->set_id(StringToId("scheduledJob")); 59 metric->set_what(scheduledJobPredicate.id()); 60 metric->set_condition(isSyncingPredicate.id()); 61 metric->set_aggregation_type(aggregationType); 62 auto dimensionWhat = metric->mutable_dimensions_in_what(); 63 dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED); 64 dimensionWhat->add_child()->set_field(2); // job name field. 65 *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions( 66 android::util::SYNC_STATE_CHANGED, {Position::FIRST}); 67 return config; 68} 69 70} // namespace 71 72TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition) { 73 for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : {true, false}) { 74 for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) { 75 ConfigKey cfgKey; 76 auto config = CreateDurationMetricConfig_NoLink_SimpleCondition( 77 aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension); 78 int64_t bucketStartTimeNs = 10000000000; 79 int64_t bucketSizeNs = 80 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; 81 82 auto processor = CreateStatsLogProcessor( 83 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); 84 EXPECT_EQ(processor->mMetricsManagers.size(), 1u); 85 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); 86 87 std::vector<AttributionNodeInternal> attributions1 = { 88 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"), 89 CreateAttribution(222, "GMSCoreModule2")}; 90 91 std::vector<AttributionNodeInternal> attributions2 = { 92 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"), 93 CreateAttribution(555, "GMSCoreModule2")}; 94 95 std::vector<std::unique_ptr<LogEvent>> events; 96 97 events.push_back(CreateStartScheduledJobEvent( 98 {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 1)); 99 events.push_back(CreateFinishScheduledJobEvent( 100 {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101)); 101 102 events.push_back(CreateStartScheduledJobEvent( 103 {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201)); 104 events.push_back(CreateFinishScheduledJobEvent( 105 {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500)); 106 107 events.push_back(CreateStartScheduledJobEvent( 108 {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600)); 109 events.push_back(CreateFinishScheduledJobEvent( 110 {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850)); 111 112 events.push_back(CreateStartScheduledJobEvent( 113 {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600)); 114 events.push_back(CreateFinishScheduledJobEvent( 115 {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900)); 116 117 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", 118 bucketStartTimeNs + 10)); 119 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail", 120 bucketStartTimeNs + 50)); 121 122 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", 123 bucketStartTimeNs + 200)); 124 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail", 125 bucketStartTimeNs + bucketSizeNs + 300)); 126 127 events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", 128 bucketStartTimeNs + 400)); 129 events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc", 130 bucketStartTimeNs + bucketSizeNs - 1)); 131 132 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", 133 bucketStartTimeNs + 401)); 134 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail", 135 bucketStartTimeNs + bucketSizeNs + 700)); 136 137 sortLogEventsByTimestamp(&events); 138 139 for (const auto& event : events) { 140 processor->OnLogEvent(event.get()); 141 } 142 143 ConfigMetricsReportList reports; 144 vector<uint8_t> buffer; 145 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, 146 ADB_DUMP, &buffer); 147 EXPECT_TRUE(buffer.size() > 0); 148 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); 149 backfillDimensionPath(&reports); 150 backfillStringInReport(&reports); 151 backfillStartEndTimestamp(&reports); 152 153 EXPECT_EQ(reports.reports_size(), 1); 154 EXPECT_EQ(reports.reports(0).metrics_size(), 1); 155 StatsLogReport::DurationMetricDataWrapper metrics; 156 sortMetricDataByDimensionsValue( 157 reports.reports(0).metrics(0).duration_metrics(), &metrics); 158 if (aggregationType == DurationMetric::SUM) { 159 EXPECT_EQ(metrics.data_size(), 4); 160 auto data = metrics.data(0); 161 EXPECT_EQ(data.dimensions_in_what().field(), 162 android::util::SCHEDULED_JOB_STATE_CHANGED); 163 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 164 2); // job name field 165 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), 166 "job0"); // job name 167 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(), 168 android::util::SYNC_STATE_CHANGED, 111, "App1"); 169 EXPECT_EQ(data.bucket_info_size(), 1); 170 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40); 171 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 172 bucketStartTimeNs); 173 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 174 bucketStartTimeNs + bucketSizeNs); 175 176 data = metrics.data(1); 177 EXPECT_EQ(data.dimensions_in_what().field(), 178 android::util::SCHEDULED_JOB_STATE_CHANGED); 179 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 180 2); // job name field 181 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), 182 "job1"); // job name 183 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(), 184 android::util::SYNC_STATE_CHANGED, 333, "App2"); 185 EXPECT_EQ(data.bucket_info_size(), 1); 186 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100); 187 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 188 bucketStartTimeNs + bucketSizeNs); 189 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 190 bucketStartTimeNs + 2 * bucketSizeNs); 191 192 data = metrics.data(2); 193 EXPECT_EQ(data.dimensions_in_what().field(), 194 android::util::SCHEDULED_JOB_STATE_CHANGED); 195 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 196 2); // job name field 197 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), 198 "job2"); // job name 199 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(), 200 android::util::SYNC_STATE_CHANGED, 111, "App1"); 201 EXPECT_EQ(data.bucket_info_size(), 2); 202 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 203 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 204 bucketStartTimeNs + bucketSizeNs); 205 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600); 206 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300); 207 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 208 bucketStartTimeNs + bucketSizeNs); 209 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 210 bucketStartTimeNs + 2 * bucketSizeNs); 211 212 data = metrics.data(3); 213 EXPECT_EQ(data.dimensions_in_what().field(), 214 android::util::SCHEDULED_JOB_STATE_CHANGED); 215 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 216 2); // job name field 217 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), 218 "job2"); // job name 219 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(), 220 android::util::SYNC_STATE_CHANGED, 333, "App2"); 221 EXPECT_EQ(data.bucket_info_size(), 2); 222 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600); 223 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 224 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 225 bucketStartTimeNs + bucketSizeNs); 226 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700); 227 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 228 bucketStartTimeNs + bucketSizeNs); 229 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 230 bucketStartTimeNs + 2 * bucketSizeNs); 231 } else { 232 EXPECT_EQ(metrics.data_size(), 4); 233 auto data = metrics.data(0); 234 EXPECT_EQ(data.dimensions_in_what().field(), 235 android::util::SCHEDULED_JOB_STATE_CHANGED); 236 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 237 2); // job name field 238 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), 239 "job0"); // job name 240 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(), 241 android::util::SYNC_STATE_CHANGED, 111, "App1"); 242 EXPECT_EQ(data.bucket_info_size(), 1); 243 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40); 244 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 245 bucketStartTimeNs); 246 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 247 bucketStartTimeNs + bucketSizeNs); 248 249 data = metrics.data(1); 250 EXPECT_EQ(data.dimensions_in_what().field(), 251 android::util::SCHEDULED_JOB_STATE_CHANGED); 252 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 253 2); // job name field 254 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), 255 "job1"); // job name 256 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(), 257 android::util::SYNC_STATE_CHANGED, 333, "App2"); 258 EXPECT_EQ(data.bucket_info_size(), 1); 259 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100); 260 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 261 bucketStartTimeNs + bucketSizeNs); 262 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 263 bucketStartTimeNs + 2 * bucketSizeNs); 264 265 data = metrics.data(2); 266 EXPECT_EQ(data.dimensions_in_what().field(), 267 android::util::SCHEDULED_JOB_STATE_CHANGED); 268 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 269 2); // job name field 270 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), 271 "job2"); // job name 272 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(), 273 android::util::SYNC_STATE_CHANGED, 111, "App1"); 274 EXPECT_EQ(data.bucket_info_size(), 2); 275 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 276 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 277 bucketStartTimeNs + bucketSizeNs); 278 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201); 279 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 300); 280 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 281 bucketStartTimeNs + bucketSizeNs); 282 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 283 bucketStartTimeNs + 2 * bucketSizeNs); 284 285 data = metrics.data(3); 286 EXPECT_EQ(data.dimensions_in_what().field(), 287 android::util::SCHEDULED_JOB_STATE_CHANGED); 288 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 289 2); // job name field 290 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(), 291 "job2"); // job name 292 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(), 293 android::util::SYNC_STATE_CHANGED, 333, "App2"); 294 EXPECT_EQ(data.bucket_info_size(), 2); 295 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 ); 296 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 297 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 298 bucketStartTimeNs + bucketSizeNs); 299 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700); 300 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 301 bucketStartTimeNs + bucketSizeNs); 302 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 303 bucketStartTimeNs + 2 * bucketSizeNs); 304 } 305 } 306 } 307} 308 309namespace { 310 311StatsdConfig createDurationMetric_Link_SimpleConditionConfig( 312 DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) { 313 StatsdConfig config; 314 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. 315 *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); 316 *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); 317 *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); 318 *config.add_atom_matcher() = CreateSyncEndAtomMatcher(); 319 320 auto scheduledJobPredicate = CreateScheduledJobPredicate(); 321 auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions(); 322 *dimensions = CreateAttributionUidDimensions( 323 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); 324 dimensions->add_child()->set_field(2); // job name field. 325 326 auto isSyncingPredicate = CreateIsSyncingPredicate(); 327 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions(); 328 *syncDimension = CreateAttributionUidDimensions( 329 android::util::SYNC_STATE_CHANGED, {Position::FIRST}); 330 if (addExtraDimensionInCondition) { 331 syncDimension->add_child()->set_field(2 /* name field*/); 332 } 333 334 *config.add_predicate() = scheduledJobPredicate; 335 *config.add_predicate() = isSyncingPredicate; 336 337 auto metric = config.add_duration_metric(); 338 metric->set_bucket(FIVE_MINUTES); 339 metric->set_id(StringToId("scheduledJob")); 340 metric->set_what(scheduledJobPredicate.id()); 341 metric->set_condition(isSyncingPredicate.id()); 342 metric->set_aggregation_type(aggregationType); 343 *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions( 344 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); 345 346 auto links = metric->add_links(); 347 links->set_condition(isSyncingPredicate.id()); 348 *links->mutable_fields_in_what() = 349 CreateAttributionUidDimensions( 350 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); 351 *links->mutable_fields_in_condition() = 352 CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST}); 353 return config; 354} 355 356} // namespace 357 358TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition) { 359 for (bool isFullLink : {true, false}) { 360 for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) { 361 ConfigKey cfgKey; 362 auto config = createDurationMetric_Link_SimpleConditionConfig( 363 aggregationType, !isFullLink); 364 int64_t bucketStartTimeNs = 10000000000; 365 int64_t bucketSizeNs = 366 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; 367 368 auto processor = CreateStatsLogProcessor( 369 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); 370 EXPECT_EQ(processor->mMetricsManagers.size(), 1u); 371 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); 372 373 std::vector<AttributionNodeInternal> attributions1 = { 374 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"), 375 CreateAttribution(222, "GMSCoreModule2")}; 376 377 std::vector<AttributionNodeInternal> attributions2 = { 378 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"), 379 CreateAttribution(555, "GMSCoreModule2")}; 380 381 std::vector<AttributionNodeInternal> attributions3 = { 382 CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"), 383 CreateAttribution(555, "GMSCoreModule2")}; 384 385 std::vector<std::unique_ptr<LogEvent>> events; 386 387 events.push_back(CreateStartScheduledJobEvent( 388 {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1)); 389 events.push_back(CreateFinishScheduledJobEvent( 390 {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101)); 391 392 events.push_back(CreateStartScheduledJobEvent( 393 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201)); 394 events.push_back(CreateFinishScheduledJobEvent( 395 {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500)); 396 events.push_back(CreateStartScheduledJobEvent( 397 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600)); 398 events.push_back( 399 CreateFinishScheduledJobEvent({CreateAttribution(333, "App2")}, "job2", 400 bucketStartTimeNs + bucketSizeNs + 850)); 401 402 events.push_back( 403 CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3", 404 bucketStartTimeNs + bucketSizeNs - 2)); 405 events.push_back( 406 CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3", 407 bucketStartTimeNs + bucketSizeNs + 900)); 408 409 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", 410 bucketStartTimeNs + 50)); 411 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail", 412 bucketStartTimeNs + 110)); 413 414 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", 415 bucketStartTimeNs + 300)); 416 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail", 417 bucketStartTimeNs + bucketSizeNs + 700)); 418 events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc", 419 bucketStartTimeNs + 400)); 420 events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc", 421 bucketStartTimeNs + bucketSizeNs - 1)); 422 423 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc", 424 bucketStartTimeNs + 550)); 425 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc", 426 bucketStartTimeNs + 800)); 427 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc", 428 bucketStartTimeNs + bucketSizeNs - 1)); 429 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc", 430 bucketStartTimeNs + bucketSizeNs + 700)); 431 432 sortLogEventsByTimestamp(&events); 433 434 for (const auto& event : events) { 435 processor->OnLogEvent(event.get()); 436 } 437 438 ConfigMetricsReportList reports; 439 vector<uint8_t> buffer; 440 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, 441 ADB_DUMP, &buffer); 442 EXPECT_TRUE(buffer.size() > 0); 443 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); 444 backfillDimensionPath(&reports); 445 backfillStringInReport(&reports); 446 backfillStartEndTimestamp(&reports); 447 448 EXPECT_EQ(reports.reports_size(), 1); 449 EXPECT_EQ(reports.reports(0).metrics_size(), 1); 450 StatsLogReport::DurationMetricDataWrapper metrics; 451 sortMetricDataByDimensionsValue( 452 reports.reports(0).metrics(0).duration_metrics(), &metrics); 453 454 if (aggregationType == DurationMetric::SUM) { 455 EXPECT_EQ(metrics.data_size(), 3); 456 auto data = metrics.data(0); 457 ValidateAttributionUidDimension( 458 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111); 459 EXPECT_EQ(data.bucket_info_size(), 1); 460 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50); 461 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 462 bucketStartTimeNs); 463 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 464 bucketStartTimeNs + bucketSizeNs); 465 466 data = metrics.data(1); 467 ValidateAttributionUidDimension( 468 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333); 469 EXPECT_EQ(data.bucket_info_size(), 2); 470 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 471 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 472 bucketStartTimeNs + bucketSizeNs); 473 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600); 474 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700); 475 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 476 bucketStartTimeNs + bucketSizeNs); 477 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 478 bucketStartTimeNs + 2 * bucketSizeNs); 479 480 data = metrics.data(2); 481 ValidateAttributionUidDimension( 482 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444); 483 EXPECT_EQ(data.bucket_info_size(), 2); 484 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1); 485 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 486 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 487 bucketStartTimeNs + bucketSizeNs); 488 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700); 489 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 490 bucketStartTimeNs + bucketSizeNs); 491 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 492 bucketStartTimeNs + 2 * bucketSizeNs); 493 } else { 494 EXPECT_EQ(metrics.data_size(), 3); 495 auto data = metrics.data(0); 496 ValidateAttributionUidDimension( 497 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111); 498 EXPECT_EQ(data.bucket_info_size(), 1); 499 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50); 500 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 501 bucketStartTimeNs); 502 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 503 bucketStartTimeNs + bucketSizeNs); 504 505 data = metrics.data(1); 506 ValidateAttributionUidDimension( 507 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333); 508 EXPECT_EQ(data.bucket_info_size(), 2); 509 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 510 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 511 bucketStartTimeNs + bucketSizeNs); 512 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300); 513 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700); 514 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 515 bucketStartTimeNs + bucketSizeNs); 516 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 517 bucketStartTimeNs + 2 * bucketSizeNs); 518 519 data = metrics.data(2); 520 ValidateAttributionUidDimension( 521 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444); 522 EXPECT_EQ(data.bucket_info_size(), 1); 523 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701); 524 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 525 bucketStartTimeNs + bucketSizeNs); 526 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 527 bucketStartTimeNs + 2 * bucketSizeNs); 528 } 529 } 530 } 531} 532 533namespace { 534 535StatsdConfig createDurationMetric_PartialLink_SimpleConditionConfig( 536 DurationMetric::AggregationType aggregationType) { 537 StatsdConfig config; 538 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. 539 *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); 540 *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); 541 *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); 542 *config.add_atom_matcher() = CreateSyncEndAtomMatcher(); 543 544 auto scheduledJobPredicate = CreateScheduledJobPredicate(); 545 auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions(); 546 *dimensions = CreateAttributionUidDimensions( 547 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); 548 dimensions->add_child()->set_field(2); // job name field. 549 550 auto isSyncingPredicate = CreateIsSyncingPredicate(); 551 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions(); 552 *syncDimension = CreateAttributionUidDimensions( 553 android::util::SYNC_STATE_CHANGED, {Position::FIRST}); 554 syncDimension->add_child()->set_field(2 /* name field*/); 555 556 *config.add_predicate() = scheduledJobPredicate; 557 *config.add_predicate() = isSyncingPredicate; 558 559 auto metric = config.add_duration_metric(); 560 metric->set_bucket(FIVE_MINUTES); 561 metric->set_id(StringToId("scheduledJob")); 562 metric->set_what(scheduledJobPredicate.id()); 563 metric->set_condition(isSyncingPredicate.id()); 564 metric->set_aggregation_type(aggregationType); 565 *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions( 566 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); 567 *metric->mutable_dimensions_in_condition() = *syncDimension; 568 569 auto links = metric->add_links(); 570 links->set_condition(isSyncingPredicate.id()); 571 *links->mutable_fields_in_what() = 572 CreateAttributionUidDimensions( 573 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); 574 *links->mutable_fields_in_condition() = 575 CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST}); 576 return config; 577} 578 579} // namespace 580 581TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition) { 582 for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) { 583 ConfigKey cfgKey; 584 auto config = createDurationMetric_PartialLink_SimpleConditionConfig( 585 aggregationType); 586 int64_t bucketStartTimeNs = 10000000000; 587 int64_t bucketSizeNs = 588 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; 589 590 auto processor = CreateStatsLogProcessor( 591 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); 592 EXPECT_EQ(processor->mMetricsManagers.size(), 1u); 593 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); 594 595 std::vector<AttributionNodeInternal> attributions1 = { 596 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"), 597 CreateAttribution(222, "GMSCoreModule2")}; 598 599 std::vector<AttributionNodeInternal> attributions2 = { 600 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"), 601 CreateAttribution(555, "GMSCoreModule2")}; 602 603 std::vector<AttributionNodeInternal> attributions3 = { 604 CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"), 605 CreateAttribution(555, "GMSCoreModule2")}; 606 607 std::vector<std::unique_ptr<LogEvent>> events; 608 609 events.push_back(CreateStartScheduledJobEvent( 610 {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1)); 611 events.push_back(CreateFinishScheduledJobEvent( 612 {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101)); 613 614 events.push_back(CreateStartScheduledJobEvent( 615 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201)); 616 events.push_back(CreateFinishScheduledJobEvent( 617 {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500)); 618 events.push_back(CreateStartScheduledJobEvent( 619 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600)); 620 events.push_back(CreateFinishScheduledJobEvent( 621 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + bucketSizeNs + 850)); 622 623 events.push_back( 624 CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3", 625 bucketStartTimeNs + bucketSizeNs - 2)); 626 events.push_back( 627 CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3", 628 bucketStartTimeNs + bucketSizeNs + 900)); 629 630 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", 631 bucketStartTimeNs + 50)); 632 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail", 633 bucketStartTimeNs + 110)); 634 635 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", 636 bucketStartTimeNs + 300)); 637 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail", 638 bucketStartTimeNs + bucketSizeNs + 700)); 639 events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc", 640 bucketStartTimeNs + 400)); 641 events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc", 642 bucketStartTimeNs + bucketSizeNs - 1)); 643 644 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc", 645 bucketStartTimeNs + 550)); 646 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc", 647 bucketStartTimeNs + 800)); 648 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc", 649 bucketStartTimeNs + bucketSizeNs - 1)); 650 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc", 651 bucketStartTimeNs + bucketSizeNs + 700)); 652 653 sortLogEventsByTimestamp(&events); 654 655 for (const auto& event : events) { 656 processor->OnLogEvent(event.get()); 657 } 658 659 ConfigMetricsReportList reports; 660 vector<uint8_t> buffer; 661 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, 662 &buffer); 663 EXPECT_TRUE(buffer.size() > 0); 664 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); 665 backfillDimensionPath(&reports); 666 backfillStringInReport(&reports); 667 backfillStartEndTimestamp(&reports); 668 669 EXPECT_EQ(reports.reports_size(), 1); 670 EXPECT_EQ(reports.reports(0).metrics_size(), 1); 671 StatsLogReport::DurationMetricDataWrapper metrics; 672 sortMetricDataByDimensionsValue( 673 reports.reports(0).metrics(0).duration_metrics(), &metrics); 674 675 if (aggregationType == DurationMetric::SUM) { 676 EXPECT_EQ(4, metrics.data_size()); 677 auto data = metrics.data(0); 678 ValidateAttributionUidDimension( 679 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111); 680 ValidateAttributionUidDimension( 681 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111); 682 EXPECT_EQ("ReadEmail", 683 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str()); 684 EXPECT_EQ(data.bucket_info_size(), 1); 685 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50); 686 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 687 bucketStartTimeNs); 688 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 689 bucketStartTimeNs + bucketSizeNs); 690 691 data = metrics.data(1); 692 ValidateAttributionUidDimension( 693 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333); 694 ValidateAttributionUidDimension( 695 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333); 696 EXPECT_EQ("ReadDoc", 697 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str()); 698 EXPECT_EQ(data.bucket_info_size(), 1); 699 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 700 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 701 bucketStartTimeNs + bucketSizeNs); 702 EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 400 - 100); 703 704 data = metrics.data(2); 705 ValidateAttributionUidDimension( 706 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333); 707 ValidateAttributionUidDimension( 708 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333); 709 EXPECT_EQ("ReadEmail", 710 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str()); 711 EXPECT_EQ(data.bucket_info_size(), 2); 712 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 713 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 714 bucketStartTimeNs + bucketSizeNs); 715 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600); 716 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700); 717 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 718 bucketStartTimeNs + bucketSizeNs); 719 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 720 bucketStartTimeNs + 2 * bucketSizeNs); 721 722 data = metrics.data(3); 723 ValidateAttributionUidDimension( 724 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444); 725 ValidateAttributionUidDimension( 726 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444); 727 EXPECT_EQ("ReadDoc", 728 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str()); 729 EXPECT_EQ(data.bucket_info_size(), 2); 730 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1); 731 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 732 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 733 bucketStartTimeNs + bucketSizeNs); 734 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700); 735 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 736 bucketStartTimeNs + bucketSizeNs); 737 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 738 bucketStartTimeNs + 2 * bucketSizeNs); 739 } else { 740 EXPECT_EQ(metrics.data_size(), 4); 741 auto data = metrics.data(0); 742 ValidateAttributionUidDimension( 743 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111); 744 ValidateAttributionUidDimension( 745 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111); 746 EXPECT_EQ("ReadEmail", 747 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str()); 748 EXPECT_EQ(data.bucket_info_size(), 1); 749 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50); 750 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 751 bucketStartTimeNs); 752 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 753 bucketStartTimeNs + bucketSizeNs); 754 755 data = metrics.data(1); 756 ValidateAttributionUidDimension( 757 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333); 758 ValidateAttributionUidDimension( 759 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333); 760 EXPECT_EQ("ReadDoc", 761 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str()); 762 EXPECT_EQ(data.bucket_info_size(), 2); 763 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 764 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 765 bucketStartTimeNs + bucketSizeNs); 766 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100); 767 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 768 bucketStartTimeNs + bucketSizeNs); 769 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 770 bucketStartTimeNs + 2 * bucketSizeNs); 771 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600); 772 773 data = metrics.data(2); 774 ValidateAttributionUidDimension( 775 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333); 776 ValidateAttributionUidDimension( 777 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333); 778 EXPECT_EQ("ReadEmail", 779 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str()); 780 EXPECT_EQ(data.bucket_info_size(), 2); 781 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); 782 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 783 bucketStartTimeNs + bucketSizeNs); 784 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300); 785 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700); 786 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), 787 bucketStartTimeNs + bucketSizeNs); 788 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), 789 bucketStartTimeNs + 2 * bucketSizeNs); 790 791 data = metrics.data(3); 792 ValidateAttributionUidDimension( 793 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444); 794 ValidateAttributionUidDimension( 795 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444); 796 EXPECT_EQ("ReadDoc", 797 data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str()); 798 EXPECT_EQ(data.bucket_info_size(), 1); 799 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701); 800 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), 801 bucketStartTimeNs + bucketSizeNs); 802 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), 803 bucketStartTimeNs + 2 * bucketSizeNs); 804 } 805 } 806} 807 808#else 809GTEST_LOG_(INFO) << "This test does nothing.\n"; 810#endif 811 812} // namespace statsd 813} // namespace os 814} // namespace android 815