1 /* 2 * Copyright (C) 2016 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 com.android.tradefed.testtype.suite; 17 18 import com.android.annotations.VisibleForTesting; 19 import com.android.ddmlib.Log.LogLevel; 20 import com.android.tradefed.build.BuildRetrievalError; 21 import com.android.tradefed.build.IBuildInfo; 22 import com.android.tradefed.build.IDeviceBuildInfo; 23 import com.android.tradefed.config.Configuration; 24 import com.android.tradefed.config.ConfigurationDescriptor; 25 import com.android.tradefed.config.ConfigurationException; 26 import com.android.tradefed.config.DynamicRemoteFileResolver; 27 import com.android.tradefed.config.IConfiguration; 28 import com.android.tradefed.config.IConfigurationReceiver; 29 import com.android.tradefed.config.IDeviceConfiguration; 30 import com.android.tradefed.config.Option; 31 import com.android.tradefed.config.Option.Importance; 32 import com.android.tradefed.config.OptionCopier; 33 import com.android.tradefed.device.DeviceNotAvailableException; 34 import com.android.tradefed.device.DeviceProperties; 35 import com.android.tradefed.device.ITestDevice; 36 import com.android.tradefed.device.NullDevice; 37 import com.android.tradefed.device.StubDevice; 38 import com.android.tradefed.device.cloud.NestedRemoteDevice; 39 import com.android.tradefed.device.connection.AbstractConnection; 40 import com.android.tradefed.device.connection.AdbTcpConnection; 41 import com.android.tradefed.device.metric.CollectorHelper; 42 import com.android.tradefed.device.metric.IMetricCollector; 43 import com.android.tradefed.device.metric.IMetricCollectorReceiver; 44 import com.android.tradefed.error.HarnessRuntimeException; 45 import com.android.tradefed.error.IHarnessException; 46 import com.android.tradefed.invoker.IInvocationContext; 47 import com.android.tradefed.invoker.TestInformation; 48 import com.android.tradefed.invoker.logger.CurrentInvocation; 49 import com.android.tradefed.invoker.logger.CurrentInvocation.IsolationGrade; 50 import com.android.tradefed.invoker.logger.InvocationMetricLogger; 51 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey; 52 import com.android.tradefed.invoker.logger.TfObjectTracker; 53 import com.android.tradefed.invoker.shard.token.ITokenRequest; 54 import com.android.tradefed.invoker.shard.token.TokenProperty; 55 import com.android.tradefed.invoker.tracing.CloseableTraceScope; 56 import com.android.tradefed.log.ITestLogger; 57 import com.android.tradefed.log.LogUtil.CLog; 58 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 59 import com.android.tradefed.postprocessor.IPostProcessor; 60 import com.android.tradefed.result.FailureDescription; 61 import com.android.tradefed.result.FileInputStreamSource; 62 import com.android.tradefed.result.ITestInvocationListener; 63 import com.android.tradefed.result.ITestLoggerReceiver; 64 import com.android.tradefed.result.InputStreamSource; 65 import com.android.tradefed.result.LogDataType; 66 import com.android.tradefed.result.LogSaverResultForwarder; 67 import com.android.tradefed.result.ResultAndLogForwarder; 68 import com.android.tradefed.result.error.DeviceErrorIdentifier; 69 import com.android.tradefed.result.error.InfraErrorIdentifier; 70 import com.android.tradefed.result.error.TestErrorIdentifier; 71 import com.android.tradefed.result.proto.ModuleProtoResultReporter; 72 import com.android.tradefed.result.skipped.SkipContext; 73 import com.android.tradefed.result.skipped.SkipFeature; 74 import com.android.tradefed.retry.IRetryDecision; 75 import com.android.tradefed.retry.RetryStrategy; 76 import com.android.tradefed.service.TradefedFeatureClient; 77 import com.android.tradefed.suite.checker.ISystemStatusChecker; 78 import com.android.tradefed.suite.checker.ISystemStatusCheckerReceiver; 79 import com.android.tradefed.suite.checker.StatusCheckerResult; 80 import com.android.tradefed.suite.checker.StatusCheckerResult.CheckStatus; 81 import com.android.tradefed.targetprep.ITargetPreparer; 82 import com.android.tradefed.testtype.Abi; 83 import com.android.tradefed.testtype.IAbi; 84 import com.android.tradefed.testtype.IBuildReceiver; 85 import com.android.tradefed.testtype.IDeviceTest; 86 import com.android.tradefed.testtype.IInvocationContextReceiver; 87 import com.android.tradefed.testtype.IRemoteTest; 88 import com.android.tradefed.testtype.IReportNotExecuted; 89 import com.android.tradefed.testtype.IRuntimeHintProvider; 90 import com.android.tradefed.testtype.IShardableTest; 91 import com.android.tradefed.testtype.ITestCollector; 92 import com.android.tradefed.testtype.suite.SuiteResultCacheUtil.CacheResultDescriptor; 93 import com.android.tradefed.util.AbiFormatter; 94 import com.android.tradefed.util.AbiUtils; 95 import com.android.tradefed.util.FileUtil; 96 import com.android.tradefed.util.MultiMap; 97 import com.android.tradefed.util.SearchArtifactUtil; 98 import com.android.tradefed.util.StreamUtil; 99 import com.android.tradefed.util.TimeUtil; 100 101 import com.google.common.collect.ImmutableMap; 102 import com.google.common.collect.ImmutableSet; 103 import com.proto.tradefed.feature.FeatureResponse; 104 105 import java.io.File; 106 import java.io.FileNotFoundException; 107 import java.io.FileOutputStream; 108 import java.io.IOException; 109 import java.io.InputStream; 110 import java.io.PrintWriter; 111 import java.lang.reflect.InvocationTargetException; 112 import java.util.ArrayList; 113 import java.util.Arrays; 114 import java.util.Collection; 115 import java.util.Collections; 116 import java.util.HashMap; 117 import java.util.HashSet; 118 import java.util.Iterator; 119 import java.util.LinkedHashMap; 120 import java.util.LinkedHashSet; 121 import java.util.List; 122 import java.util.Map; 123 import java.util.Map.Entry; 124 import java.util.Random; 125 import java.util.Set; 126 import java.util.stream.Collectors; 127 128 /** 129 * Abstract class used to run Test Suite. This class provide the base of how the Suite will be run. 130 * Each implementation can define the list of tests via the {@link #loadTests()} method. 131 */ 132 public abstract class ITestSuite 133 implements IRemoteTest, 134 IDeviceTest, 135 IBuildReceiver, 136 ISystemStatusCheckerReceiver, 137 IShardableTest, 138 ITestCollector, 139 IInvocationContextReceiver, 140 IRuntimeHintProvider, 141 IMetricCollectorReceiver, 142 IConfigurationReceiver, 143 IReportNotExecuted, 144 ITokenRequest, 145 ITestLoggerReceiver { 146 147 public static final String MODULE_START_TIME = "MODULE_START_TIME"; 148 public static final String MODULE_END_TIME = "MODULE_END_TIME"; 149 150 public static final String SKIP_SYSTEM_STATUS_CHECKER = "skip-system-status-check"; 151 public static final String RUNNER_WHITELIST = "runner-whitelist"; 152 public static final String PREPARER_WHITELIST = "preparer-whitelist"; 153 public static final String MODULE_CHECKER_PRE = "PreModuleChecker"; 154 public static final String MODULE_CHECKER_POST = "PostModuleChecker"; 155 public static final String ABI_OPTION = "abi"; 156 public static final String SKIP_HOST_ARCH_CHECK = "skip-host-arch-check"; 157 public static final String PRIMARY_ABI_RUN = "primary-abi-only"; 158 public static final String PARAMETER_KEY = "parameter"; 159 public static final String MAINLINE_PARAMETER_KEY = "mainline-param"; 160 public static final String ACTIVE_MAINLINE_PARAMETER_KEY = "active-mainline-parameter"; 161 public static final String TOKEN_KEY = "token"; 162 public static final String MODULE_METADATA_INCLUDE_FILTER = "module-metadata-include-filter"; 163 public static final String MODULE_METADATA_EXCLUDE_FILTER = "module-metadata-exclude-filter"; 164 public static final String RANDOM_SEED = "random-seed"; 165 public static final String SKIP_STAGING_ARTIFACTS = "skip-staging-artifacts"; 166 public static final String STAGE_MODULE_ARTIFACTS = "stage-module-artifacts"; 167 public static final String ENABLE_RESOLVE_SYM_LINKS = "enable-resolve-sym-links"; 168 169 private static final String PRODUCT_CPU_ABI_KEY = "ro.product.cpu.abi"; 170 171 public static final String TEST_TYPE_KEY = "test-type"; 172 public static final String TEST_TYPE_VALUE_PERFORMANCE = "performance"; 173 public static final String BUILD_ATTRIBUTE_FLAG_OVERRIDES_KEY = "flag-overrides"; 174 175 private static final Set<String> ALLOWED_PREPARERS_CONFIGS = 176 ImmutableSet.of("/suite/allowed-preparers.txt", "/suite/google-allowed-preparers.txt"); 177 178 @Deprecated 179 @Option( 180 name = "bugreport-on-failure", 181 description = 182 "Take a bugreport on every test failure. Warning: This may require a lot" 183 + "of storage space of the machine running the tests.") 184 private boolean mBugReportOnFailure = false; 185 186 @Deprecated 187 @Option( 188 name = "logcat-on-failure", 189 description = "Take a logcat snapshot on every test failure." 190 ) 191 private boolean mLogcatOnFailure = false; 192 193 @Deprecated 194 @Option( 195 name = "logcat-on-failure-size", 196 description = 197 "The max number of logcat data in bytes to capture when --logcat-on-failure is" 198 + " on. Should be an amount that can comfortably fit in memory.") 199 private int mMaxLogcatBytes = 500 * 1024; // 500K 200 201 @Deprecated 202 @Option( 203 name = "screenshot-on-failure", 204 description = "Take a screenshot on every test failure." 205 ) 206 private boolean mScreenshotOnFailure = false; 207 208 @Deprecated 209 @Option(name = "reboot-on-failure", description = "Reboot the device after every test failure.") 210 private boolean mRebootOnFailure = false; 211 212 // Options for suite runner behavior 213 @Option(name = "reboot-per-module", description = "Reboot the device before every module run.") 214 private boolean mRebootPerModule = false; 215 216 @Option(name = "skip-all-system-status-check", 217 description = "Whether all system status check between modules should be skipped") 218 private boolean mSkipAllSystemStatusCheck = false; 219 220 @Option( 221 name = SKIP_SYSTEM_STATUS_CHECKER, 222 description = 223 "Disable specific system status checkers." 224 + "Specify zero or more SystemStatusChecker as canonical class names. e.g. " 225 + "\"com.android.tradefed.suite.checker.KeyguardStatusChecker\" If not " 226 + "specified, all configured or whitelisted system status checkers will " 227 + "run." 228 ) 229 private Set<String> mSystemStatusCheckBlacklist = new HashSet<>(); 230 231 @Option(name = ENABLE_RESOLVE_SYM_LINKS, description = "Enable symlinks resolving") 232 protected boolean mEnableResolveSymlinks = false; 233 234 @Option( 235 name = "report-system-checkers", 236 description = "Whether reporting system checkers as test or not." 237 ) 238 private boolean mReportSystemChecker = false; 239 240 @Option( 241 name = "random-order", 242 description = "Whether randomizing the order of the modules to be ran or not." 243 ) 244 private boolean mRandomOrder = false; 245 246 @Option( 247 name = RANDOM_SEED, 248 description = "Seed to randomize the order of the modules." 249 ) 250 private long mRandomSeed = -1; 251 252 @Option( 253 name = "collect-tests-only", 254 description = 255 "Only invoke the suite to collect list of applicable test cases. All " 256 + "test run callbacks will be triggered, but test execution will not be " 257 + "actually carried out." 258 ) 259 private boolean mCollectTestsOnly = false; 260 261 // Abi related options 262 @Option( 263 name = ABI_OPTION, 264 shortName = 'a', 265 description = "the abi to test. For example: 'arm64-v8a'.", 266 importance = Importance.IF_UNSET 267 ) 268 private String mAbiName = null; 269 270 @Option( 271 name = SKIP_HOST_ARCH_CHECK, 272 description = "Whether host architecture check should be skipped." 273 ) 274 private boolean mSkipHostArchCheck = false; 275 276 @Option( 277 name = PRIMARY_ABI_RUN, 278 description = 279 "Whether to run tests with only the device primary abi. " 280 + "This is overriden by the --abi option." 281 ) 282 private boolean mPrimaryAbiRun = false; 283 284 @Option( 285 name = MODULE_METADATA_INCLUDE_FILTER, 286 description = 287 "Include modules for execution based on matching of metadata fields: for any of " 288 + "the specified filter name and value, if a module has a metadata field " 289 + "with the same name and value, it will be included. When both module " 290 + "inclusion and exclusion rules are applied, inclusion rules will be " 291 + "evaluated first. Using this together with test filter inclusion rules " 292 + "may result in no tests to execute if the rules don't overlap." 293 ) 294 private MultiMap<String, String> mModuleMetadataIncludeFilter = new MultiMap<>(); 295 296 @Option( 297 name = MODULE_METADATA_EXCLUDE_FILTER, 298 description = 299 "Exclude modules for execution based on matching of metadata fields: for any of " 300 + "the specified filter name and value, if a module has a metadata field " 301 + "with the same name and value, it will be excluded. When both module " 302 + "inclusion and exclusion rules are applied, inclusion rules will be " 303 + "evaluated first." 304 ) 305 private MultiMap<String, String> mModuleMetadataExcludeFilter = new MultiMap<>(); 306 307 @Option(name = RUNNER_WHITELIST, description = "Runner class(es) that are allowed to run.") 308 private Set<String> mAllowedRunners = new HashSet<>(); 309 310 @Option( 311 name = PREPARER_WHITELIST, 312 description = 313 "Preparer class(es) that are allowed to run. This mostly usefeul for dry-runs." 314 ) 315 private Set<String> mAllowedPreparers = new HashSet<>(); 316 317 @Option( 318 name = "enable-module-dynamic-download", 319 description = 320 "Whether or not to allow the downloading of dynamic @option files at module level." 321 ) 322 private boolean mEnableDynamicDownload = false; 323 324 @Option( 325 name = "intra-module-sharding", 326 description = "Whether or not to allow intra-module sharding." 327 ) 328 private boolean mIntraModuleSharding = true; 329 330 @Option( 331 name = "isolated-module", 332 description = "Whether or not to attempt the module isolation between modules" 333 ) 334 private boolean mIsolatedModule = false; 335 336 @Option( 337 name = "isolated-module-grade", 338 description = 339 "When isolated-module is enabled, this defines what action we try to attempt.") 340 private IsolatedModuleGrade mIsolatedModuleGrade = IsolatedModuleGrade.FULLY_ISOLATED; 341 342 @Option( 343 name = "recover-device-by-cvd", 344 description = 345 "Try to recover the device by cvd tool when the device is gone during test" 346 + " running.") 347 protected boolean mRecoverDeviceByCvd = false; 348 349 /** @deprecated to be deleted when next version is deployed */ 350 @Deprecated 351 @Option( 352 name = "retry-strategy", 353 description = 354 "The retry strategy to be used when re-running some tests with " 355 + "--max-testcase-run-count" 356 ) 357 private RetryStrategy mRetryStrategy = RetryStrategy.NO_RETRY; 358 359 // [Options relate to module retry and intra-module retry][ 360 @Option( 361 name = "merge-attempts", 362 description = "Whether or not to use the merge the results of the different attempts." 363 ) 364 private boolean mMergeAttempts = true; 365 // end [Options relate to module retry and intra-module retry] 366 367 @Option( 368 name = "partial-download-via-feature", 369 description = "Feature flag to test partial download via feature service.") 370 private boolean mStageArtifactsViaFeature = true; 371 372 @Option( 373 name = SKIP_STAGING_ARTIFACTS, 374 description = "Skip staging artifacts with remote-files if already staged.") 375 private boolean mSkipStagingArtifacts = false; 376 377 @Option( 378 name = "multi-devices-modules", 379 description = "Running strategy for modules that require multiple devices.") 380 private MultiDeviceModuleStrategy mMultiDevicesStrategy = MultiDeviceModuleStrategy.EXCLUDE_ALL; 381 382 @Option( 383 name = "use-snapshot-for-reset", 384 description = "Feature flag to use snapshot/restore instead of powerwash.") 385 private boolean mUseSnapshotForReset = false; 386 387 @Option( 388 name = "use-snapshot-before-first-module", 389 description = 390 "Immediately restore the device after taking a snapshot. Ensures tests are" 391 + " consistently run within a restored VM.") 392 private boolean mUseSnapshotBeforeFirstModule = false; 393 394 @Option(name = "stage-remote-file", description = "Whether to allow staging of remote files.") 395 private boolean mStageRemoteFile = true; 396 397 @Option( 398 name = "prioritize-host-config", 399 description = 400 "If there are duplicate test configs for host/target, prioritize the host" 401 + " config, otherwise use the target config.") 402 private boolean mPrioritizeHostConfig = false; 403 404 @Option( 405 name = "run-test-suite", 406 description = 407 "Entry point to execute the given test suite as defined by the Soong" 408 + " test_suites rule") 409 private String mRunTestSuite = null; 410 411 @Option( 412 name = "use-module-results-forwarder", 413 description = 414 "Feature flag to enable whether metrics should be forwarded by ModuleListener" 415 + " or the new forwarder.") 416 private boolean mUseModuleResultsForwarder = true; 417 418 public enum IsolatedModuleGrade { 419 REBOOT_ISOLATED, // Reboot was done before the test. 420 FULLY_ISOLATED; // Test received a fresh device. 421 } 422 423 public enum MultiDeviceModuleStrategy { 424 EXCLUDE_ALL, 425 RUN, 426 ONLY_MULTI_DEVICES 427 } 428 429 private ITestDevice mDevice; 430 private IBuildInfo mBuildInfo; 431 private List<ISystemStatusChecker> mSystemStatusCheckers; 432 private IInvocationContext mContext; 433 private List<IMetricCollector> mMetricCollectors; 434 private IConfiguration mMainConfiguration; 435 private Set<IAbi> mAbis = new LinkedHashSet<>(); 436 437 // Sharding attributes 438 private boolean mIsSharded = false; 439 private ModuleDefinition mDirectModule = null; 440 private boolean mShouldMakeDynamicModule = true; 441 442 // Current modules to run, null if not started to run yet. 443 private List<ModuleDefinition> mRunModules = null; 444 private ModuleDefinition mModuleInProgress = null; 445 private SkipContext mSkipContext = null; 446 447 // Logger to be used to files. 448 private ITestLogger mCurrentLogger = null; 449 // Whether or not we are currently in split 450 private boolean mIsSplitting = false; 451 452 private boolean mDisableAutoRetryTimeReporting = false; 453 454 private DynamicRemoteFileResolver mDynamicResolver = new DynamicRemoteFileResolver(); 455 456 @VisibleForTesting setDynamicResolver(DynamicRemoteFileResolver resolver)457 void setDynamicResolver(DynamicRemoteFileResolver resolver) { 458 mDynamicResolver = resolver; 459 } 460 461 @VisibleForTesting setDirectModule(ModuleDefinition module)462 public void setDirectModule(ModuleDefinition module) { 463 mDirectModule = module; 464 mIsSharded = true; 465 } 466 467 /** 468 * Abstract method to load the tests configuration that will be run. Each tests is defined by a 469 * {@link IConfiguration} and a unique name under which it will report results. 470 */ loadTests()471 public abstract LinkedHashMap<String, IConfiguration> loadTests(); 472 473 /** 474 * Return an instance of the class implementing {@link ITestSuite}. 475 */ createInstance()476 private ITestSuite createInstance() { 477 try { 478 return this.getClass().getDeclaredConstructor().newInstance(); 479 } catch (InstantiationException 480 | IllegalAccessException 481 | InvocationTargetException 482 | NoSuchMethodException e) { 483 throw new RuntimeException(e); 484 } 485 } 486 getTestsDir()487 public File getTestsDir() throws FileNotFoundException { 488 IBuildInfo build = getBuildInfo(); 489 File testsDir = null; 490 if (build instanceof IDeviceBuildInfo) { 491 testsDir = ((IDeviceBuildInfo) build).getTestsDir(); 492 } 493 if (testsDir != null && testsDir.exists()) { 494 return testsDir; 495 } 496 // TODO: handle multi build? 497 throw new FileNotFoundException("Could not found a tests dir folder."); 498 } 499 loadAndFilter()500 private LinkedHashMap<String, IConfiguration> loadAndFilter() { 501 LinkedHashMap<String, IConfiguration> runConfig = loadTests(); 502 if (runConfig.isEmpty()) { 503 CLog.i("No config were loaded. Nothing to run."); 504 return runConfig; 505 } 506 507 Set<String> moduleNames = new HashSet<>(); 508 LinkedHashMap<String, IConfiguration> filteredConfig = new LinkedHashMap<>(); 509 for (Entry<String, IConfiguration> config : runConfig.entrySet()) { 510 if (!mModuleMetadataIncludeFilter.isEmpty() 511 || !mModuleMetadataExcludeFilter.isEmpty()) { 512 if (!filterByConfigMetadata( 513 config.getValue(), 514 mModuleMetadataIncludeFilter, 515 mModuleMetadataExcludeFilter)) { 516 // if the module config did not pass the metadata filters, it's excluded 517 // from execution. 518 continue; 519 } 520 } 521 if (!filterByRunnerType(config.getValue(), mAllowedRunners)) { 522 // if the module config did not pass the runner type filter, it's excluded from 523 // execution. 524 continue; 525 } 526 switch (mMultiDevicesStrategy) { 527 case EXCLUDE_ALL: 528 if (config.getValue().getDeviceConfig().size() > 1) { 529 // Exclude multi-devices configs 530 continue; 531 } 532 break; 533 case ONLY_MULTI_DEVICES: 534 if (config.getValue().getDeviceConfig().size() == 1) { 535 // Exclude single devices configs 536 continue; 537 } 538 break; 539 default: 540 break; 541 } 542 filterPreparers(config.getValue(), mAllowedPreparers); 543 544 if (mMainConfiguration != null) { 545 // Copy the CoverageOptions from the main configuration to the module configuration. 546 config.getValue().setCoverageOptions(mMainConfiguration.getCoverageOptions()); 547 // Copy the CommandOptions from the main configuration to the module configuration. 548 config.getValue().setCommandOptions(mMainConfiguration.getCommandOptions()); 549 } 550 551 filteredConfig.put(config.getKey(), config.getValue()); 552 moduleNames.add(config.getValue().getConfigurationDescription().getModuleName()); 553 File configPath = 554 SearchArtifactUtil.getModuleDirFromConfig( 555 config.getValue().getConfigurationDescription()); 556 if (configPath != null) { 557 moduleNames.add(configPath.getName()); 558 } 559 } 560 561 if (stageAtInvocationLevel()) { 562 stageTestArtifacts(mDevice, moduleNames); 563 } else { 564 CLog.d(SKIP_STAGING_ARTIFACTS + " is set. Skipping #stageTestArtifacts"); 565 } 566 567 runConfig.clear(); 568 return filteredConfig; 569 } 570 stageAtInvocationLevel()571 private boolean stageAtInvocationLevel() { 572 if (mBuildInfo != null) { 573 if (mSkipStagingArtifacts 574 || mBuildInfo.getBuildAttributes().get(SKIP_STAGING_ARTIFACTS) != null) { 575 return false; 576 } else { 577 return true; 578 } 579 } 580 return false; 581 } 582 stageModuleLevel()583 private boolean stageModuleLevel() { 584 if (mBuildInfo != null) { 585 return mBuildInfo.getBuildAttributes().get(STAGE_MODULE_ARTIFACTS) != null; 586 } 587 return false; 588 } 589 590 /** Helper to download all artifacts for the given modules. */ stageTestArtifacts(ITestDevice device, Set<String> modules)591 private void stageTestArtifacts(ITestDevice device, Set<String> modules) { 592 if (mBuildInfo.getRemoteFiles() == null || mBuildInfo.getRemoteFiles().isEmpty()) { 593 CLog.d("No remote build info, skipping stageTestArtifacts"); 594 return; 595 } 596 CLog.i(String.format("Start to stage test artifacts for %d modules.", modules.size())); 597 long startTime = System.currentTimeMillis(); 598 try (CloseableTraceScope ignored = 599 new CloseableTraceScope( 600 InvocationMetricKey.stage_suite_test_artifacts.toString())) { 601 // Include the file if its path contains a folder name matching any of the module. 602 String moduleRegex = 603 modules.stream() 604 .map(m -> String.format("/%s/", m)) 605 .collect(Collectors.joining("|")); 606 List<String> includeFilters = Arrays.asList(moduleRegex); 607 // Ignore config file as it's part of config and jar zip artifact that's staged already. 608 List<String> excludeFilters = Arrays.asList("[.]config$", "[.]jar$"); 609 if (mStageArtifactsViaFeature) { 610 try (TradefedFeatureClient client = new TradefedFeatureClient()) { 611 Map<String, String> args = new HashMap<>(); 612 String destination = getTestsDir().getAbsolutePath(); 613 // In *TS cases, download from root dir reference instead of tests dir 614 if (mBuildInfo.getBuildAttributes().containsKey("ROOT_DIR")) { 615 destination = mBuildInfo.getBuildAttributes().get("ROOT_DIR"); 616 } 617 CLog.d( 618 "resolve symlinks:[%s] downloading to destination: %s the following" 619 + " include_filters: %s", 620 mEnableResolveSymlinks, destination, includeFilters); 621 args.put(ResolvePartialDownload.DESTINATION_DIR, destination); 622 args.put( 623 ResolvePartialDownload.INCLUDE_FILTERS, 624 String.join(";", includeFilters)); 625 args.put( 626 ResolvePartialDownload.EXCLUDE_FILTERS, 627 String.join(";", excludeFilters)); 628 // Pass the remote paths 629 String remotePaths = 630 mBuildInfo.getRemoteFiles().stream() 631 .map(p -> p.toString()) 632 .collect(Collectors.joining(";")); 633 args.put(ResolvePartialDownload.REMOTE_PATHS, remotePaths); 634 args.put(ENABLE_RESOLVE_SYM_LINKS, String.valueOf(mEnableResolveSymlinks)); 635 FeatureResponse rep = 636 client.triggerFeature( 637 ResolvePartialDownload.RESOLVE_PARTIAL_DOWNLOAD_FEATURE_NAME, 638 args); 639 if (rep.hasErrorInfo()) { 640 throw new HarnessRuntimeException( 641 rep.getErrorInfo().getErrorTrace(), 642 InfraErrorIdentifier.ARTIFACT_DOWNLOAD_ERROR); 643 } 644 } catch (FileNotFoundException e) { 645 throw new HarnessRuntimeException( 646 e.getMessage(), e, InfraErrorIdentifier.ARTIFACT_DOWNLOAD_ERROR); 647 } 648 } else { 649 CLog.d("Not using feature server to download %s remoteFile", mDynamicResolver); 650 mDynamicResolver.setDevice(device); 651 mDynamicResolver.addExtraArgs( 652 mMainConfiguration.getCommandOptions().getDynamicDownloadArgs()); 653 mDynamicResolver.addExtraArgs( 654 ImmutableMap.of( 655 ENABLE_RESOLVE_SYM_LINKS, String.valueOf(mEnableResolveSymlinks))); 656 for (File remoteFile : mBuildInfo.getRemoteFiles()) { 657 try { 658 mDynamicResolver.resolvePartialDownloadZip( 659 getTestsDir(), 660 remoteFile.toString(), 661 includeFilters, 662 excludeFilters); 663 } catch (BuildRetrievalError | FileNotFoundException e) { 664 String message = 665 String.format( 666 "Failed to download partial zip from %s for modules: %s", 667 remoteFile, String.join(", ", modules)); 668 CLog.e(message); 669 CLog.e(e); 670 if (e instanceof IHarnessException) { 671 throw new HarnessRuntimeException(message, (IHarnessException) e); 672 } 673 throw new HarnessRuntimeException( 674 message, e, InfraErrorIdentifier.ARTIFACT_DOWNLOAD_ERROR); 675 } 676 } 677 } 678 } 679 long elapsedTime = System.currentTimeMillis() - startTime; 680 InvocationMetricLogger.addInvocationMetrics( 681 InvocationMetricKey.STAGE_TESTS_TIME, elapsedTime); 682 CLog.i( 683 String.format( 684 "Staging test artifacts for %d modules finished in %s.", 685 modules.size(), TimeUtil.formatElapsedTime(elapsedTime))); 686 } 687 688 /** Helper that creates and returns the list of {@link ModuleDefinition} to be executed. */ createExecutionList()689 private List<ModuleDefinition> createExecutionList() { 690 List<ModuleDefinition> runModules = new ArrayList<>(); 691 if (mDirectModule != null) { 692 // If we are sharded and already know what to run then we just do it. 693 runModules.add(mDirectModule); 694 mDirectModule.setDevice(mDevice); 695 mDirectModule.setBuild(mBuildInfo); 696 return runModules; 697 } 698 try (CloseableTraceScope ignore = new CloseableTraceScope("suite:createExecutionList")) { 699 long start = System.currentTimeMillis(); 700 LinkedHashMap<String, IConfiguration> runConfig = loadAndFilter(); 701 InvocationMetricLogger.addInvocationPairMetrics( 702 InvocationMetricKey.TEST_SETUP_PAIR, start, System.currentTimeMillis()); 703 if (runConfig.isEmpty()) { 704 CLog.i("No config were loaded. Nothing to run."); 705 return runModules; 706 } 707 708 Map<String, List<ITargetPreparer>> suitePreparersPerDevice = 709 getAllowedPreparerPerDevice(mMainConfiguration); 710 711 for (Entry<String, IConfiguration> config : runConfig.entrySet()) { 712 // Validate the configuration, it will throw if not valid. 713 ValidateSuiteConfigHelper.validateConfig(config.getValue()); 714 Map<String, List<ITargetPreparer>> preparersPerDevice = 715 getPreparerPerDevice(config.getValue()); 716 // add the prioritize-host-config value in the module config 717 config.getValue() 718 .getConfigurationDescription() 719 .addMetadata( 720 ConfigurationDescriptor.PRIORITIZE_HOST_CONFIG_KEY, 721 String.valueOf(mPrioritizeHostConfig)); 722 ModuleDefinition module = 723 new ModuleDefinition( 724 config.getKey(), 725 config.getValue().getTests(), 726 preparersPerDevice, 727 suitePreparersPerDevice, 728 config.getValue().getMultiTargetPreparers(), 729 config.getValue()); 730 if (mDisableAutoRetryTimeReporting) { 731 module.disableAutoRetryReportingTime(); 732 } 733 module.setDevice(mDevice); 734 module.setBuild(mBuildInfo); 735 runModules.add(module); 736 } 737 738 /** Randomize all the modules to be ran if random-order is set and no sharding. */ 739 if (mRandomOrder) { 740 randomizeTestModules(runModules, mRandomSeed); 741 } 742 743 CLog.logAndDisplay(LogLevel.DEBUG, "[Total Unique Modules = %s]", runModules.size()); 744 // Free the map once we are done with it. 745 runConfig = null; 746 return runModules; 747 } 748 } 749 750 /** 751 * Helper method that handle randomizing the order of the modules. 752 * 753 * @param runModules The {@code List<ModuleDefinition>} of the test modules to be ran. 754 * @param randomSeed The {@code long} seed used to randomize the order of test modules, use the 755 * current time as seed if no specified seed provided. 756 */ 757 @VisibleForTesting randomizeTestModules(List<ModuleDefinition> runModules, long randomSeed)758 void randomizeTestModules(List<ModuleDefinition> runModules, long randomSeed) { 759 // Use current time as seed if no specified seed provided. 760 if (randomSeed == -1) { 761 randomSeed = System.currentTimeMillis(); 762 } 763 CLog.i("Randomizing all the modules with seed: %s", randomSeed); 764 Collections.shuffle(runModules, new Random(randomSeed)); 765 mBuildInfo.addBuildAttribute(RANDOM_SEED, String.valueOf(randomSeed)); 766 } 767 checkClassLoad(Set<String> classes, String type)768 private void checkClassLoad(Set<String> classes, String type) { 769 for (String c : classes) { 770 try { 771 Class.forName(c); 772 } catch (ClassNotFoundException e) { 773 ConfigurationException ex = 774 new ConfigurationException( 775 String.format( 776 "--%s must contains valid class, %s was not found", 777 type, c), 778 e); 779 throw new RuntimeException(ex); 780 } 781 } 782 } 783 784 /** Create the mapping of device to its target_preparer. */ getPreparerPerDevice(IConfiguration config)785 private Map<String, List<ITargetPreparer>> getPreparerPerDevice(IConfiguration config) { 786 Map<String, List<ITargetPreparer>> res = new LinkedHashMap<>(); 787 for (IDeviceConfiguration holder : config.getDeviceConfig()) { 788 List<ITargetPreparer> preparers = new ArrayList<>(); 789 res.put(holder.getDeviceName(), preparers); 790 preparers.addAll(holder.getTargetPreparers()); 791 } 792 return res; 793 } 794 795 /** Create the mapping of device to its target_preparer that's allowed to rerun. */ getAllowedPreparerPerDevice(IConfiguration config)796 private Map<String, List<ITargetPreparer>> getAllowedPreparerPerDevice(IConfiguration config) { 797 // For unittests, mMainConfiguration might not have been set. 798 if (config == null) { 799 return new LinkedHashMap<String, List<ITargetPreparer>>(); 800 } 801 // Read the list of allowed suite level target preparers from resource files. 802 Set<String> allowedSuitePreparers = new HashSet<>(); 803 for (String resource : ALLOWED_PREPARERS_CONFIGS) { 804 try (InputStream resStream = ITestSuite.class.getResourceAsStream(resource)) { 805 if (resStream == null) { 806 CLog.d("Resource not found for allowed preparers: %s", resource); 807 continue; 808 } 809 List<String> preparers = 810 Arrays.asList(StreamUtil.getStringFromStream(resStream).split("\n")); 811 allowedSuitePreparers.addAll(preparers); 812 } catch (IOException e) { 813 CLog.e(e); 814 } 815 } 816 817 Map<String, List<ITargetPreparer>> res = new LinkedHashMap<>(); 818 for (IDeviceConfiguration holder : config.getDeviceConfig()) { 819 List<ITargetPreparer> preparers = new ArrayList<>(); 820 for (ITargetPreparer preparer : holder.getTargetPreparers()) { 821 if (allowedSuitePreparers.contains(preparer.getClass().getCanonicalName())) { 822 preparers.add(preparer); 823 } 824 } 825 res.put(holder.getDeviceName(), preparers); 826 } 827 return res; 828 } 829 830 /** 831 * Opportunity to clean up all the things that were needed during the suites setup but are not 832 * required to run the tests. 833 */ cleanUpSuiteSetup()834 public void cleanUpSuiteSetup() { 835 // Empty by default. 836 } 837 838 /** Generic run method for all test loaded from {@link #loadTests()}. */ 839 @Override run(TestInformation testInfo, ITestInvocationListener listener)840 public final void run(TestInformation testInfo, ITestInvocationListener listener) 841 throws DeviceNotAvailableException { 842 mCurrentLogger = listener; 843 // Load and check the module checkers, runners and preparers in black and whitelist 844 checkClassLoad(mSystemStatusCheckBlacklist, SKIP_SYSTEM_STATUS_CHECKER); 845 checkClassLoad(mAllowedRunners, RUNNER_WHITELIST); 846 checkClassLoad(mAllowedPreparers, PREPARER_WHITELIST); 847 848 mRunModules = createExecutionList(); 849 // Check if we have something to run. 850 if (mRunModules.isEmpty()) { 851 CLog.i("No tests to be run."); 852 return; 853 } 854 855 // Allow checkers to log files for easier debugging. 856 for (ISystemStatusChecker checker : mSystemStatusCheckers) { 857 if (checker instanceof ITestLoggerReceiver) { 858 ((ITestLoggerReceiver) checker).setTestLogger(listener); 859 } 860 } 861 862 if (mUseSnapshotForReset) { 863 AbstractConnection connection = mDevice.getConnection(); 864 if (connection instanceof AdbTcpConnection) { 865 // Capture a snapshot once at the beginning of the suite 866 if (((AdbTcpConnection) connection).getSuiteSnapshots().containsKey(mDevice)) { 867 CLog.d("Suite snapshot already taken for '%s'", mDevice.getSerialNumber()); 868 } else { 869 String snapshotId = mContext.getInvocationId(); 870 ((AdbTcpConnection) connection).snapshotDevice(mDevice, snapshotId); 871 ((AdbTcpConnection) connection).getSuiteSnapshots().put(mDevice, snapshotId); 872 if (mUseSnapshotBeforeFirstModule) { 873 ((AdbTcpConnection) connection) 874 .recoverVirtualDevice(mDevice, snapshotId, null); 875 } 876 } 877 } 878 } 879 880 // Only print the running log if we are going to run something. 881 if (mRunModules.get(0).hasTests()) { 882 CLog.logAndDisplay( 883 LogLevel.INFO, 884 "%s running %s modules: %s", 885 mDevice.getSerialNumber(), 886 mRunModules.size(), 887 mRunModules); 888 } 889 890 if (mSkipContext == null) { 891 mSkipContext = SkipFeature.getSkipContext(); 892 } 893 /** Run all the module, make sure to reduce the list to release resources as we go. */ 894 while (!mRunModules.isEmpty()) { 895 ModuleDefinition module = mRunModules.remove(0); 896 mModuleInProgress = module; 897 boolean moduleStartReported = false; 898 boolean moduleEndReported = false; 899 ITestInvocationListener listenerWithCollectors = null; 900 try { 901 if (!shouldModuleRun(module)) { 902 continue; 903 } 904 // Before running the module we ensure it has tests at this point or skip completely 905 // to avoid running SystemCheckers and preparation for nothing. 906 if (!module.hasTests()) { 907 continue; 908 } 909 910 /** Create the list of listeners applicable at the module level. */ 911 List<ITestInvocationListener> moduleListeners = createModuleListeners(); 912 913 try (CloseableTraceScope ignore = new CloseableTraceScope(module.getId())) { 914 if (!stageAtInvocationLevel() && stageModuleLevel()) { 915 Set<String> moduleNames = new LinkedHashSet<String>(); 916 moduleNames.add( 917 module.getModuleConfiguration() 918 .getConfigurationDescription() 919 .getModuleName()); 920 File configPath = 921 SearchArtifactUtil.getModuleDirFromConfig( 922 module.getModuleInvocationContext()); 923 if (configPath != null) { 924 moduleNames.add(configPath.getName()); 925 } 926 stageTestArtifacts(mDevice, moduleNames); 927 } 928 // Populate the module context with devices and builds 929 for (String deviceName : mContext.getDeviceConfigNames()) { 930 module.getModuleInvocationContext() 931 .addAllocatedDevice(deviceName, mContext.getDevice(deviceName)); 932 module.getModuleInvocationContext() 933 .addDeviceBuildInfo(deviceName, mContext.getBuildInfo(deviceName)); 934 } 935 // Add isolation status before module start for reporting 936 if (!IsolationGrade.NOT_ISOLATED.equals( 937 CurrentInvocation.moduleCurrentIsolation())) { 938 module.getModuleInvocationContext() 939 .addInvocationAttribute( 940 ModuleDefinition.MODULE_ISOLATED, 941 CurrentInvocation.moduleCurrentIsolation().toString()); 942 } 943 // Unify invocation level listeners, module listeners and module post-processors 944 ITestInvocationListener allListenersWithoutLogSaver = 945 listenerWithPostProcessors(module, listener, moduleListeners); 946 // NOTE: do not set log saver again, since the previous log saver should have 947 // already set it to the correct listeners. 948 ITestInvocationListener allListenersWithLogSaver = 949 new LogSaverResultForwarder( 950 mMainConfiguration.getLogSaver(), 951 Arrays.asList(allListenersWithoutLogSaver), 952 module.getModuleConfiguration(), 953 false); 954 // Only the module callback will be called here. 955 listenerWithCollectors = allListenersWithLogSaver; 956 if (mMetricCollectors != null) { 957 for (IMetricCollector collector : 958 CollectorHelper.cloneCollectors(mMetricCollectors)) { 959 if (collector.isDisabled()) { 960 CLog.d("%s has been disabled. Skipping.", collector); 961 } else if (!collector.captureModuleLevel()) { 962 CLog.d("%s isn't applicable at module level. Skipping.", collector); 963 } else { 964 if (collector instanceof IConfigurationReceiver) { 965 ((IConfigurationReceiver) collector) 966 .setConfiguration(module.getModuleConfiguration()); 967 } 968 try (CloseableTraceScope ignored = 969 new CloseableTraceScope( 970 "init_for_module_" 971 + collector.getClass().getSimpleName())) { 972 listenerWithCollectors = 973 collector.init( 974 module.getModuleInvocationContext(), 975 listenerWithCollectors); 976 TfObjectTracker.countWithParents(collector.getClass()); 977 } 978 } 979 } 980 } 981 File moduleConfig = dumpModuleConfig(module); 982 String baseModuleName = 983 module.getModuleInvocationContext() 984 .getConfigurationDescriptor() 985 .getModuleName(); 986 boolean shouldSkipModule = mSkipContext.shouldSkipModule(baseModuleName); 987 ModuleProtoResultReporter moduleReporter = null; 988 CacheResultDescriptor cacheDescriptor = null; 989 File moduleDir = 990 SearchArtifactUtil.getModuleDirFromConfig( 991 module.getModuleInvocationContext()); 992 if (moduleDir == null) { 993 InvocationMetricLogger.addInvocationMetrics( 994 InvocationMetricKey.MODULE_CACHE_NO_DIR, 1); 995 } 996 if (!shouldSkipModule 997 && mMainConfiguration.getCommandOptions().shouldUploadCacheResults() 998 && moduleDir != null 999 && mMainConfiguration.getCommandOptions().getRemoteCacheInstanceName() 1000 != null) { 1001 cacheDescriptor = 1002 SuiteResultCacheUtil.lookUpModuleResults( 1003 mMainConfiguration, 1004 module, 1005 moduleConfig, 1006 moduleDir, 1007 mSkipContext); 1008 if (!cacheDescriptor.isCacheHit()) { 1009 try { 1010 File protoResults = 1011 FileUtil.createTempFile("module-results", ".proto"); 1012 // Do not report granular results until we need them they consume a 1013 // lot of memory 1014 moduleReporter = 1015 new ModuleProtoResultReporter(testInfo.getContext(), false); 1016 moduleReporter.setOutputFile(protoResults); 1017 moduleListeners.add(moduleReporter); 1018 } catch (IOException e) { 1019 CLog.e(e); 1020 } 1021 } 1022 } 1023 module.getModuleInvocationContext() 1024 .addInvocationAttribute( 1025 MODULE_START_TIME, Long.toString(System.currentTimeMillis())); 1026 listenerWithCollectors.testModuleStarted(module.getModuleInvocationContext()); 1027 moduleStartReported = true; 1028 boolean applyCachedResults = 1029 cacheDescriptor != null 1030 && cacheDescriptor.isCacheHit() 1031 && (mMainConfiguration.getCommandOptions().reportCacheResults() 1032 || (mSkipContext.isPresubmit() 1033 && mMainConfiguration 1034 .getCommandOptions() 1035 .reportCacheResultsInPresubmit())) 1036 && mSkipContext.shouldUseCache(); 1037 // If we are not gonna use the config file, delete right away after logging. 1038 boolean deleteRightAway = (moduleReporter == null); 1039 if (moduleConfig != null && !applyCachedResults && !shouldSkipModule) { 1040 // TODO(b/372243975): report logs even while applying caching 1041 try (InputStreamSource source = 1042 new FileInputStreamSource(moduleConfig, deleteRightAway)) { 1043 allListenersWithLogSaver.testLog( 1044 "module-configuration", LogDataType.HARNESS_CONFIG, source); 1045 } 1046 } 1047 TestInformation moduleInfo = 1048 TestInformation.createModuleTestInfo( 1049 testInfo, module.getModuleInvocationContext()); 1050 boolean moduleRan = true; 1051 try { 1052 if (shouldSkipModule) { 1053 moduleRan = false; 1054 CLog.d( 1055 "Skipping module '%s' due to no changes in artifacts.", 1056 baseModuleName); 1057 module.getModuleInvocationContext() 1058 .addInvocationAttribute( 1059 ModuleDefinition.MODULE_SKIPPED, 1060 "No relevant changes to device image or test artifacts" 1061 + " detected."); 1062 module.getModuleInvocationContext() 1063 .addInvocationAttribute(ModuleDefinition.SPARSE_MODULE, "true"); 1064 InvocationMetricLogger.addInvocationMetrics( 1065 InvocationMetricKey.PARTIAL_SKIP_MODULE_UNCHANGED_COUNT, 1); 1066 } else if (applyCachedResults) { 1067 CLog.d("Reporting cached results for module %s", module.getId()); 1068 module.getModuleInvocationContext() 1069 .addInvocationAttribute( 1070 ModuleDefinition.MODULE_SKIPPED, 1071 cacheDescriptor.getDetails()); 1072 module.getModuleInvocationContext() 1073 .addInvocationAttribute(ModuleDefinition.SPARSE_MODULE, "true"); 1074 } else { 1075 runSingleModule(module, moduleInfo, allListenersWithoutLogSaver); 1076 } 1077 } finally { 1078 module.getModuleInvocationContext() 1079 .addInvocationAttribute( 1080 MODULE_END_TIME, Long.toString(System.currentTimeMillis())); 1081 if (mMainConfiguration.getCommandOptions().shouldUploadCacheResults() 1082 && moduleReporter != null) { 1083 File protoResults = moduleReporter.getOutputFile(); 1084 if (!moduleReporter.stopCaching()) { 1085 SuiteResultCacheUtil.uploadModuleResults( 1086 mMainConfiguration, 1087 testInfo, 1088 module, 1089 moduleConfig, 1090 protoResults, 1091 moduleDir, 1092 mSkipContext); 1093 } 1094 FileUtil.deleteFile(protoResults); 1095 moduleListeners.remove(moduleReporter); 1096 } 1097 FileUtil.deleteFile(moduleConfig); 1098 if (!applyCachedResults) { 1099 // Following modules will not be isolated if no action is taken 1100 CurrentInvocation.setModuleIsolation(IsolationGrade.NOT_ISOLATED); 1101 } 1102 } 1103 if (moduleRan) { 1104 // Module isolation routine 1105 moduleIsolation(mContext, allListenersWithLogSaver); 1106 } 1107 } 1108 } catch (DeviceNotAvailableException e) { 1109 CLog.e( 1110 "A DeviceNotAvailableException occurred, following modules did not run: %s", 1111 mRunModules); 1112 // allow current module to properly report module start/end 1113 mModuleInProgress.setReportModuleStart(!moduleStartReported); 1114 mModuleInProgress.setReportModuleEnd(true); 1115 String inProgressMessage = 1116 String.format( 1117 "Module %s was interrupted after starting due to device not" 1118 + " available. Results might not be accurate or complete.", 1119 mModuleInProgress.getId()); 1120 if (listenerWithCollectors != null) { 1121 mModuleInProgress.reportNotExecuted(listenerWithCollectors, inProgressMessage); 1122 } else { 1123 mModuleInProgress.reportNotExecuted(listener, inProgressMessage); 1124 } 1125 moduleEndReported = true; 1126 reportNotExecuted(listener, "Module did not run due to device not available."); 1127 throw e; 1128 } finally { 1129 // if module end not reported(no DNAE happened), report it now 1130 if (moduleStartReported && !moduleEndReported) { 1131 if (listenerWithCollectors != null) { 1132 listenerWithCollectors.testModuleEnded(); 1133 } else { 1134 listener.testModuleEnded(); 1135 } 1136 } 1137 // clear out module invocation context since we are now done with module 1138 // execution 1139 mModuleInProgress = null; 1140 } 1141 } 1142 } 1143 1144 /** 1145 * Returns a listener with module-level post processors (for perf modules) instered to the 1146 * listener chain. 1147 */ listenerWithPostProcessors( ModuleDefinition module, ITestInvocationListener invocationListener, List<ITestInvocationListener> moduleListeners)1148 private ITestInvocationListener listenerWithPostProcessors( 1149 ModuleDefinition module, 1150 ITestInvocationListener invocationListener, 1151 List<ITestInvocationListener> moduleListeners) { 1152 // Strip LogSaverResultForwarder from invocationListener as a RetryLogSaverResultForwarder 1153 // will be added during module execution later. 1154 if (invocationListener instanceof LogSaverResultForwarder) { 1155 List<ITestInvocationListener> origListeners = 1156 ((LogSaverResultForwarder) invocationListener).getListeners(); 1157 invocationListener = new ResultAndLogForwarder(origListeners); 1158 } 1159 1160 IConfiguration config = module.getModuleConfiguration(); 1161 List<String> testTypes = config.getConfigurationDescription().getMetaData(TEST_TYPE_KEY); 1162 List<ITestInvocationListener> allListeners = new ArrayList<>(); 1163 allListeners.add(invocationListener); 1164 // wrap module listeners with a forwarder in order to keep the array object intact. 1165 allListeners.add(new ResultAndLogForwarder(moduleListeners)); 1166 ITestInvocationListener allListenerWithForwarder = new ResultAndLogForwarder(allListeners); 1167 1168 if (testTypes == null || !testTypes.contains(TEST_TYPE_VALUE_PERFORMANCE)) { 1169 return allListenerWithForwarder; // not a perf module 1170 } 1171 List<IPostProcessor> topLevelPostProcessors = mMainConfiguration.getPostProcessors(); 1172 List<IPostProcessor> modulePostProcessors = config.getPostProcessors(); 1173 if (modulePostProcessors.size() > 0 && topLevelPostProcessors.size() > 0) { 1174 CLog.w("Post processors specified at both top level and module level (%s)", module); 1175 } 1176 // set log saver for module level post postprocessor manually to allow chained log 1177 // processing at module level. Do this before init() to avoid passing down the log saver 1178 // to invocation level listeners/reporters. 1179 for (IPostProcessor postProcessor : modulePostProcessors) { 1180 postProcessor.setLogSaver(mMainConfiguration.getLogSaver()); 1181 } 1182 for (IPostProcessor postProcessor : modulePostProcessors) { 1183 try { 1184 allListenerWithForwarder = postProcessor.init(allListenerWithForwarder); 1185 } catch (Exception e) { 1186 CLog.e( 1187 "Post processor %s is ignored as it fails to init() with exception: %s", 1188 postProcessor.getClass().getSimpleName(), e); 1189 } 1190 } 1191 return allListenerWithForwarder; 1192 } 1193 1194 /** Log the module configuration. */ dumpModuleConfig(ModuleDefinition module)1195 private File dumpModuleConfig(ModuleDefinition module) { 1196 boolean restore = false; 1197 try { 1198 File configFile = 1199 FileUtil.createTempFile( 1200 module.getModuleConfiguration() 1201 .getConfigurationDescription() 1202 .getModuleName(), 1203 ".xml", 1204 CurrentInvocation.getWorkFolder()); 1205 if (module.getModuleConfiguration().getTests().isEmpty()) { 1206 module.getModuleConfiguration().setTests(module.getTests()); 1207 restore = true; 1208 } 1209 try (FileOutputStream stream = new FileOutputStream(configFile); 1210 PrintWriter pw = new PrintWriter(stream, true)) { 1211 module.getModuleConfiguration() 1212 .dumpXml( 1213 pw, 1214 new ArrayList<String>(Configuration.NON_MODULE_OBJECTS), 1215 true, 1216 false); 1217 pw.flush(); 1218 return configFile; 1219 } finally { 1220 if (restore) { 1221 module.getModuleConfiguration().setTests(new ArrayList<>()); 1222 } 1223 } 1224 } catch (RuntimeException | IOException e) { 1225 CLog.e(e); 1226 } 1227 return null; 1228 } 1229 1230 /** 1231 * Returns the list of {@link ITestInvocationListener} applicable to the {@link ModuleListener} 1232 * level. These listeners will be re-used for each module, they will not be re-instantiated so 1233 * they should not assume an internal state. 1234 */ createModuleListeners()1235 protected List<ITestInvocationListener> createModuleListeners() { 1236 return new ArrayList<>(); 1237 } 1238 1239 /** 1240 * Routine that attempt to reset a device between modules in order to provide isolation. 1241 * 1242 * @param context The invocation context. 1243 * @param logger A logger where extra logs can be saved. 1244 * @throws DeviceNotAvailableException 1245 */ moduleIsolation(IInvocationContext context, ITestLogger logger)1246 private void moduleIsolation(IInvocationContext context, ITestLogger logger) 1247 throws DeviceNotAvailableException { 1248 if (!mIsolatedModule) { 1249 return; 1250 } 1251 if (IsolatedModuleGrade.REBOOT_ISOLATED.equals(mIsolatedModuleGrade)) { 1252 CLog.d("isolated-module is enabled with grade REBOOT_ISOLATED."); 1253 try (CloseableTraceScope ignored = new CloseableTraceScope("isolated_module_reboot")) { 1254 for (ITestDevice device : context.getDevices()) { 1255 device.reboot(); 1256 } 1257 CurrentInvocation.setModuleIsolation(IsolationGrade.REBOOT_ISOLATED); 1258 CurrentInvocation.setRunIsolation(IsolationGrade.REBOOT_ISOLATED); 1259 } 1260 } else if (IsolatedModuleGrade.FULLY_ISOLATED.equals(mIsolatedModuleGrade)) { 1261 // TODO: we can probably make it smarter: Did any test ran for example? 1262 ITestDevice device = context.getDevices().get(0); 1263 if (device instanceof NestedRemoteDevice) { 1264 boolean res = ((NestedRemoteDevice) device).resetVirtualDevice(); 1265 if (!res) { 1266 String serial = device.getSerialNumber(); 1267 throw new DeviceNotAvailableException( 1268 String.format( 1269 "Failed to reset the AVD '%s' during module isolation.", 1270 serial), 1271 serial); 1272 } 1273 } else if (mUseSnapshotForReset) { 1274 AbstractConnection connection = device.getConnection(); 1275 if (connection instanceof AdbTcpConnection) { 1276 String snapshot = 1277 ((AdbTcpConnection) connection).getSuiteSnapshots().get(device); 1278 // snapshot should not be null, otherwise the device would have crashed. 1279 ((AdbTcpConnection) connection).recoverVirtualDevice(device, snapshot, null); 1280 } 1281 } 1282 } 1283 } 1284 1285 /** 1286 * Helper method that handle running a single module logic. 1287 * 1288 * @param module The {@link ModuleDefinition} to be ran. 1289 * @param moduleInfo The {@link TestInformation} for the module. 1290 * @param allListeners The {@link ITestInvocationListener} where to report results 1291 * @param failureListener special listener that we add to collect information on failures. 1292 * @throws DeviceNotAvailableException 1293 */ runSingleModule( ModuleDefinition module, TestInformation moduleInfo, ITestInvocationListener allListeners)1294 private void runSingleModule( 1295 ModuleDefinition module, 1296 TestInformation moduleInfo, 1297 ITestInvocationListener allListeners) 1298 throws DeviceNotAvailableException { 1299 Map<String, String> properties = new LinkedHashMap<>(); 1300 ITestInvocationListener allListenersWithLogSaver = 1301 new LogSaverResultForwarder( 1302 mMainConfiguration.getLogSaver(), 1303 Arrays.asList(allListeners), 1304 module.getModuleConfiguration(), 1305 false); 1306 try (CloseableTraceScope ignored = new CloseableTraceScope("module_pre_check")) { 1307 if (mRebootPerModule) { 1308 if ("user".equals(mDevice.getProperty(DeviceProperties.BUILD_TYPE))) { 1309 CLog.e( 1310 "reboot-per-module should only be used during development, " 1311 + "this is a\" user\" build device"); 1312 } else { 1313 CLog.d("Rebooting device before starting next module"); 1314 mDevice.reboot(); 1315 } 1316 } 1317 1318 if (!mSkipAllSystemStatusCheck && !mSystemStatusCheckers.isEmpty()) { 1319 properties.putAll( 1320 runPreModuleCheck( 1321 module.getId(), 1322 mSystemStatusCheckers, 1323 mDevice, 1324 allListenersWithLogSaver)); 1325 } 1326 if (mCollectTestsOnly) { 1327 module.setCollectTestsOnly(mCollectTestsOnly); 1328 } 1329 if (mRecoverDeviceByCvd) { 1330 module.setRecoverVirtualDevice(mRecoverDeviceByCvd); 1331 } 1332 if (mUseModuleResultsForwarder) { 1333 module.setUseModuleResultsForwarder(mUseModuleResultsForwarder); 1334 } 1335 // Pass the run defined collectors to be used. 1336 module.setMetricCollectors(CollectorHelper.cloneCollectors(mMetricCollectors)); 1337 // Pass the main invocation logSaver 1338 module.setLogSaver(mMainConfiguration.getLogSaver()); 1339 1340 IRetryDecision decision = mMainConfiguration.getRetryDecision(); 1341 // Pass whether we should merge the attempts of not 1342 if (mMergeAttempts 1343 && decision.getMaxTestRunAttempts(module) > 1 1344 && !RetryStrategy.NO_RETRY.equals(decision.getRetryStrategy())) { 1345 CLog.d("Overriding '--merge-attempts' to false for auto-retry."); 1346 mMergeAttempts = false; 1347 } 1348 module.setMergeAttemps(mMergeAttempts); 1349 // Pass the retry decision to be used. 1350 module.setRetryDecision(decision); 1351 // Restore the config, as the setter might have override it with module config. 1352 if (decision instanceof IConfigurationReceiver) { 1353 ((IConfigurationReceiver) decision).setConfiguration(mMainConfiguration); 1354 } 1355 1356 module.setEnableDynamicDownload(mEnableDynamicDownload); 1357 module.transferSuiteLevelOptions(mMainConfiguration); 1358 } 1359 // Actually run the module 1360 module.run( 1361 moduleInfo, 1362 allListeners, 1363 getConfiguration().getRetryDecision().getMaxTestRunAttempts(module)); 1364 1365 if (!mSkipAllSystemStatusCheck && !mSystemStatusCheckers.isEmpty()) { 1366 try (CloseableTraceScope ignored = new CloseableTraceScope("module_post_check")) { 1367 properties.putAll( 1368 runPostModuleCheck( 1369 module.getId(), 1370 mSystemStatusCheckers, 1371 mDevice, 1372 allListenersWithLogSaver)); 1373 } 1374 } 1375 for (Map.Entry<String, String> entry : properties.entrySet()) { 1376 module.getModuleInvocationContext() 1377 .addInvocationAttribute(entry.getKey(), entry.getValue()); 1378 } 1379 } 1380 1381 /** 1382 * Helper to run the System Status checkers preExecutionChecks defined for the test and log 1383 * their failures. 1384 */ runPreModuleCheck( String moduleName, List<ISystemStatusChecker> checkers, ITestDevice device, ITestInvocationListener listener)1385 private Map<String, String> runPreModuleCheck( 1386 String moduleName, 1387 List<ISystemStatusChecker> checkers, 1388 ITestDevice device, 1389 ITestInvocationListener listener) 1390 throws DeviceNotAvailableException { 1391 long startTime = System.currentTimeMillis(); 1392 CLog.i("Running system status checker before module execution: %s", moduleName); 1393 Map<String, String> failures = new LinkedHashMap<>(); 1394 Map<String, String> properties = new LinkedHashMap<>(); 1395 boolean bugreportNeeded = false; 1396 for (ISystemStatusChecker checker : checkers) { 1397 // Track usage of the checker 1398 TfObjectTracker.countWithParents(checker.getClass()); 1399 // Check if the status checker should be skipped. 1400 if (mSystemStatusCheckBlacklist.contains(checker.getClass().getName())) { 1401 CLog.d( 1402 "%s was skipped via %s", 1403 checker.getClass().getName(), SKIP_SYSTEM_STATUS_CHECKER); 1404 continue; 1405 } 1406 1407 StatusCheckerResult result = new StatusCheckerResult(CheckStatus.FAILED); 1408 try { 1409 result = checker.preExecutionCheck(device); 1410 } catch (RuntimeException e) { 1411 CLog.e(e); 1412 // Catch RuntimeException to avoid leaking throws that go to the invocation. 1413 result.setErrorMessage(e.getMessage()); 1414 result.setBugreportNeeded(true); 1415 } 1416 properties.putAll(result.getModuleProperties()); 1417 if (!CheckStatus.SUCCESS.equals(result.getStatus())) { 1418 String errorMessage = 1419 (result.getErrorMessage() == null) ? "" : result.getErrorMessage(); 1420 failures.put(checker.getClass().getCanonicalName(), errorMessage); 1421 bugreportNeeded = bugreportNeeded | result.isBugreportNeeded(); 1422 CLog.w("System status checker [%s] failed.", checker.getClass().getCanonicalName()); 1423 } 1424 } 1425 if (!failures.isEmpty()) { 1426 CLog.w("There are failed system status checkers: %s", failures.toString()); 1427 if (bugreportNeeded && !(device.getIDevice() instanceof StubDevice)) { 1428 device.logBugreport( 1429 String.format("bugreport-checker-pre-module-%s", moduleName), listener); 1430 } 1431 } 1432 1433 // We report System checkers like tests. 1434 reportModuleCheckerResult(MODULE_CHECKER_PRE, moduleName, failures, startTime, listener); 1435 InvocationMetricLogger.addInvocationPairMetrics( 1436 InvocationMetricKey.STATUS_CHECKER_PAIR, startTime, System.currentTimeMillis()); 1437 return properties; 1438 } 1439 1440 /** 1441 * Helper to run the System Status checkers postExecutionCheck defined for the test and log 1442 * their failures. 1443 */ runPostModuleCheck( String moduleName, List<ISystemStatusChecker> checkers, ITestDevice device, ITestInvocationListener listener)1444 private Map<String, String> runPostModuleCheck( 1445 String moduleName, 1446 List<ISystemStatusChecker> checkers, 1447 ITestDevice device, 1448 ITestInvocationListener listener) 1449 throws DeviceNotAvailableException { 1450 long startTime = System.currentTimeMillis(); 1451 CLog.i("Running system status checker after module execution: %s", moduleName); 1452 Map<String, String> failures = new LinkedHashMap<>(); 1453 Map<String, String> properties = new LinkedHashMap<>(); 1454 boolean bugreportNeeded = false; 1455 for (ISystemStatusChecker checker : checkers) { 1456 // Check if the status checker should be skipped. 1457 if (mSystemStatusCheckBlacklist.contains(checker.getClass().getName())) { 1458 continue; 1459 } 1460 1461 StatusCheckerResult result = new StatusCheckerResult(CheckStatus.FAILED); 1462 try { 1463 result = checker.postExecutionCheck(device); 1464 } catch (RuntimeException e) { 1465 CLog.e(e); 1466 // Catch RuntimeException to avoid leaking throws that go to the invocation. 1467 result.setErrorMessage(e.getMessage()); 1468 result.setBugreportNeeded(true); 1469 } catch (DeviceNotAvailableException dnae) { 1470 // Wrap the DNAE to provide a better error message 1471 String message = 1472 String.format( 1473 "Device became unavailable after %s due to: %s", 1474 moduleName, dnae.getMessage()); 1475 DeviceNotAvailableException wrapper = 1476 new DeviceNotAvailableException(message, dnae, dnae.getSerial()); 1477 throw wrapper; 1478 } 1479 properties.putAll(result.getModuleProperties()); 1480 if (!CheckStatus.SUCCESS.equals(result.getStatus())) { 1481 String errorMessage = 1482 (result.getErrorMessage() == null) ? "" : result.getErrorMessage(); 1483 failures.put(checker.getClass().getCanonicalName(), errorMessage); 1484 bugreportNeeded = bugreportNeeded | result.isBugreportNeeded(); 1485 CLog.w("System status checker [%s] failed", checker.getClass().getCanonicalName()); 1486 } 1487 } 1488 if (!failures.isEmpty()) { 1489 CLog.w("There are failed system status checkers: %s", failures.toString()); 1490 if (bugreportNeeded && !(device.getIDevice() instanceof StubDevice)) { 1491 device.logBugreport( 1492 String.format("bugreport-checker-post-module-%s", moduleName), listener); 1493 } 1494 } 1495 1496 // We report System checkers like tests. 1497 reportModuleCheckerResult(MODULE_CHECKER_POST, moduleName, failures, startTime, listener); 1498 InvocationMetricLogger.addInvocationPairMetrics( 1499 InvocationMetricKey.STATUS_CHECKER_PAIR, startTime, System.currentTimeMillis()); 1500 return properties; 1501 } 1502 1503 /** Helper to report status checker results as test results. */ reportModuleCheckerResult( String identifier, String moduleName, Map<String, String> failures, long startTime, ITestInvocationListener listener)1504 private void reportModuleCheckerResult( 1505 String identifier, 1506 String moduleName, 1507 Map<String, String> failures, 1508 long startTime, 1509 ITestInvocationListener listener) { 1510 if (!mReportSystemChecker) { 1511 // do not log here, otherwise it could be very verbose. 1512 return; 1513 } 1514 // Avoid messing with the final test count by making them empty runs. 1515 listener.testRunStarted(identifier + "_" + moduleName, 0, 0, System.currentTimeMillis()); 1516 if (!failures.isEmpty()) { 1517 FailureDescription description = 1518 FailureDescription.create( 1519 String.format("%s failed '%s' checkers", moduleName, failures)) 1520 .setErrorIdentifier(TestErrorIdentifier.MODULE_CHANGED_SYSTEM_STATUS); 1521 listener.testRunFailed(description); 1522 } 1523 listener.testRunEnded( 1524 System.currentTimeMillis() - startTime, new HashMap<String, Metric>()); 1525 } 1526 1527 /** Returns true if we are currently in {@link #split(int)}. */ isSplitting()1528 public boolean isSplitting() { 1529 return mIsSplitting; 1530 } 1531 1532 /** {@inheritDoc} */ 1533 @Override split(Integer shardCountHint, TestInformation testInfo)1534 public Collection<IRemoteTest> split(Integer shardCountHint, TestInformation testInfo) { 1535 if (shardCountHint == null || shardCountHint <= 1 || mIsSharded) { 1536 // cannot shard or already sharded 1537 return null; 1538 } 1539 // TODO: Replace by relying on testInfo directly 1540 setBuild(testInfo.getBuildInfo()); 1541 setDevice(testInfo.getDevice()); 1542 setInvocationContext(testInfo.getContext()); 1543 1544 mIsSplitting = true; 1545 try { 1546 long start = System.currentTimeMillis(); 1547 LinkedHashMap<String, IConfiguration> runConfig = loadAndFilter(); 1548 InvocationMetricLogger.addInvocationPairMetrics( 1549 InvocationMetricKey.TEST_SETUP_PAIR, start, System.currentTimeMillis()); 1550 if (runConfig.isEmpty()) { 1551 CLog.i("No config were loaded. Nothing to run."); 1552 return null; 1553 } 1554 injectInfo(runConfig, testInfo); 1555 1556 // We split individual tests on double the shardCountHint to provide better average. 1557 // The test pool mechanism prevent this from creating too much overhead. 1558 List<ModuleDefinition> splitModules = 1559 ModuleSplitter.splitConfiguration( 1560 testInfo, 1561 runConfig, 1562 getAllowedPreparerPerDevice(mMainConfiguration), 1563 shardCountHint, 1564 mShouldMakeDynamicModule, 1565 mIntraModuleSharding); 1566 runConfig.clear(); 1567 runConfig = null; 1568 1569 // Clean up the parent that will get sharded: It is fine to clean up before copying the 1570 // options, because the sharded module is already created/populated so there is no need 1571 // to carry these extra data. 1572 cleanUpSuiteSetup(); 1573 1574 SkipContext skipContext = SkipFeature.getSkipContext(); 1575 // create an association of one ITestSuite <=> one ModuleDefinition as the smallest 1576 // execution unit supported. 1577 List<IRemoteTest> splitTests = new ArrayList<>(); 1578 for (ModuleDefinition m : splitModules) { 1579 ITestSuite suite = createInstance(); 1580 OptionCopier.copyOptionsNoThrow(this, suite); 1581 suite.mIsSharded = true; 1582 suite.mDirectModule = m; 1583 suite.setSkipContext(skipContext); 1584 splitTests.add(suite); 1585 } 1586 // return the list of ITestSuite with their ModuleDefinition assigned 1587 return splitTests; 1588 } finally { 1589 // Done splitting at that point 1590 mIsSplitting = false; 1591 } 1592 } 1593 1594 /** 1595 * Inject {@link ITestDevice} and {@link IBuildInfo} to the {@link IRemoteTest}s in the config 1596 * before sharding since they may be needed. 1597 */ injectInfo( LinkedHashMap<String, IConfiguration> runConfig, TestInformation testInfo)1598 private void injectInfo( 1599 LinkedHashMap<String, IConfiguration> runConfig, TestInformation testInfo) { 1600 for (IConfiguration config : runConfig.values()) { 1601 for (IRemoteTest test : config.getTests()) { 1602 if (test instanceof IBuildReceiver) { 1603 ((IBuildReceiver) test).setBuild(testInfo.getBuildInfo()); 1604 } 1605 if (test instanceof IDeviceTest) { 1606 ((IDeviceTest) test).setDevice(testInfo.getDevice()); 1607 } 1608 if (test instanceof IInvocationContextReceiver) { 1609 ((IInvocationContextReceiver) test).setInvocationContext(testInfo.getContext()); 1610 } 1611 if (test instanceof ITestCollector) { 1612 ((ITestCollector) test).setCollectTestsOnly(mCollectTestsOnly); 1613 } 1614 } 1615 } 1616 } 1617 1618 /** {@inheritDoc} */ 1619 @Override setDevice(ITestDevice device)1620 public void setDevice(ITestDevice device) { 1621 mDevice = device; 1622 } 1623 1624 /** 1625 * {@inheritDoc} 1626 */ 1627 @Override getDevice()1628 public ITestDevice getDevice() { 1629 return mDevice; 1630 } 1631 1632 /** Set the value of mAbiName */ setAbiName(String abiName)1633 public void setAbiName(String abiName) { 1634 mAbiName = abiName; 1635 } 1636 1637 /** 1638 * {@inheritDoc} 1639 */ 1640 @Override setBuild(IBuildInfo buildInfo)1641 public void setBuild(IBuildInfo buildInfo) { 1642 mBuildInfo = buildInfo; 1643 mBuildInfo.allowStagingRemoteFile(mStageRemoteFile); 1644 } 1645 1646 /** 1647 * Implementation of {@link ITestSuite} may require the build info to load the tests. 1648 */ getBuildInfo()1649 public IBuildInfo getBuildInfo() { 1650 return mBuildInfo; 1651 } 1652 1653 /** Set the value of mPrimaryAbiRun */ setPrimaryAbiRun(boolean primaryAbiRun)1654 public void setPrimaryAbiRun(boolean primaryAbiRun) { 1655 mPrimaryAbiRun = primaryAbiRun; 1656 } 1657 1658 /** 1659 * {@inheritDoc} 1660 */ 1661 @Override setSystemStatusChecker(List<ISystemStatusChecker> systemCheckers)1662 public void setSystemStatusChecker(List<ISystemStatusChecker> systemCheckers) { 1663 mSystemStatusCheckers = systemCheckers; 1664 } 1665 1666 /** 1667 * Run the test suite in collector only mode, this requires all the sub-tests to implements this 1668 * interface too. 1669 */ 1670 @Override setCollectTestsOnly(boolean shouldCollectTest)1671 public void setCollectTestsOnly(boolean shouldCollectTest) { 1672 mCollectTestsOnly = shouldCollectTest; 1673 } 1674 1675 /** {@inheritDoc} */ 1676 @Override setMetricCollectors(List<IMetricCollector> collectors)1677 public void setMetricCollectors(List<IMetricCollector> collectors) { 1678 mMetricCollectors = collectors; 1679 } 1680 1681 /** 1682 * When doing distributed sharding, we cannot have ModuleDefinition that shares tests in a pool 1683 * otherwise intra-module sharding will not work, so we allow to disable it. 1684 */ setShouldMakeDynamicModule(boolean dynamicModule)1685 public void setShouldMakeDynamicModule(boolean dynamicModule) { 1686 mShouldMakeDynamicModule = dynamicModule; 1687 } 1688 1689 /** {@inheritDoc} */ 1690 @Override setInvocationContext(IInvocationContext invocationContext)1691 public void setInvocationContext(IInvocationContext invocationContext) { 1692 mContext = invocationContext; 1693 } 1694 1695 /** 1696 * Returns the invocation context. 1697 */ getInvocationContext()1698 public IInvocationContext getInvocationContext() { 1699 return mContext; 1700 } 1701 1702 /** {@inheritDoc} */ 1703 @Override setTestLogger(ITestLogger testLogger)1704 public void setTestLogger(ITestLogger testLogger) { 1705 mCurrentLogger = testLogger; 1706 } 1707 getCurrentTestLogger()1708 public ITestLogger getCurrentTestLogger() { 1709 return mCurrentLogger; 1710 } 1711 1712 /** {@inheritDoc} */ 1713 @Override getRuntimeHint()1714 public long getRuntimeHint() { 1715 if (mDirectModule != null) { 1716 CLog.d( 1717 " %s: %s", 1718 mDirectModule.getId(), 1719 TimeUtil.formatElapsedTime(mDirectModule.getRuntimeHint())); 1720 return mDirectModule.getRuntimeHint(); 1721 } 1722 return 0L; 1723 } 1724 1725 /** {@inheritDoc} */ 1726 @Override setConfiguration(IConfiguration configuration)1727 public void setConfiguration(IConfiguration configuration) { 1728 mMainConfiguration = configuration; 1729 } 1730 1731 /** Returns the invocation {@link IConfiguration}. */ getConfiguration()1732 public final IConfiguration getConfiguration() { 1733 return mMainConfiguration; 1734 } 1735 1736 /** {@inheritDoc} */ 1737 @Override reportNotExecuted(ITestInvocationListener listener)1738 public void reportNotExecuted(ITestInvocationListener listener) { 1739 reportNotExecuted(listener, IReportNotExecuted.NOT_EXECUTED_FAILURE); 1740 } 1741 1742 /** {@inheritDoc} */ 1743 @Override reportNotExecuted(ITestInvocationListener listener, String message)1744 public void reportNotExecuted(ITestInvocationListener listener, String message) { 1745 // If the runner is already in progress, report the remaining tests as not executed. 1746 List<ModuleDefinition> runModules = null; 1747 if (mRunModules != null) { 1748 runModules = new ArrayList<>(mRunModules); 1749 } 1750 if (runModules == null) { 1751 runModules = createExecutionList(); 1752 } 1753 1754 while (!runModules.isEmpty()) { 1755 ModuleDefinition module = runModules.remove(0); 1756 module.reportNotExecuted(listener, message); 1757 } 1758 } 1759 getModuleMetadataIncludeFilters()1760 public MultiMap<String, String> getModuleMetadataIncludeFilters() { 1761 return mModuleMetadataIncludeFilter; 1762 } 1763 addModuleMetadataIncludeFilters(MultiMap<String, String> filters)1764 public void addModuleMetadataIncludeFilters(MultiMap<String, String> filters) { 1765 mModuleMetadataIncludeFilter.putAll(filters); 1766 } 1767 addModuleMetadataExcludeFilters(MultiMap<String, String> filters)1768 public void addModuleMetadataExcludeFilters(MultiMap<String, String> filters) { 1769 mModuleMetadataExcludeFilter.putAll(filters); 1770 } 1771 1772 /** 1773 * Returns the {@link ModuleDefinition} to be executed directly, or null if none yet (when the 1774 * ITestSuite has not been sharded yet). 1775 */ getDirectModule()1776 public ModuleDefinition getDirectModule() { 1777 return mDirectModule; 1778 } 1779 1780 @Override getRequiredTokens(TestInformation testInfo)1781 public Set<TokenProperty> getRequiredTokens(TestInformation testInfo) { 1782 if (mDirectModule == null) { 1783 return null; 1784 } 1785 return mDirectModule.getRequiredTokens(testInfo); 1786 } 1787 1788 /** 1789 * Gets the set of ABIs supported by both Compatibility testing {@link 1790 * AbiUtils#getAbisSupportedByCompatibility()} and the device under test. 1791 * 1792 * @return The set of ABIs to run the tests on 1793 * @throws DeviceNotAvailableException 1794 */ getAbis(ITestDevice device)1795 public Set<IAbi> getAbis(ITestDevice device) throws DeviceNotAvailableException { 1796 if (!mAbis.isEmpty()) { 1797 return mAbis; 1798 } 1799 Set<IAbi> abis = new LinkedHashSet<>(); 1800 Set<String> archAbis = getAbisForBuildTargetArch(); 1801 // Handle null-device: use abi in common with host and suite build 1802 if (mPrimaryAbiRun) { 1803 if (mAbiName == null) { 1804 // Get the primary from the device and make it the --abi to run. 1805 mAbiName = getPrimaryAbi(device); 1806 } else { 1807 CLog.d( 1808 "Option --%s supersedes the option --%s, using abi: %s", 1809 ABI_OPTION, PRIMARY_ABI_RUN, mAbiName); 1810 } 1811 } 1812 if (mAbiName != null) { 1813 // A particular abi was requested, it still needs to be supported by the build. 1814 if ((!mSkipHostArchCheck && !archAbis.contains(mAbiName)) 1815 || !AbiUtils.isAbiSupportedByCompatibility(mAbiName)) { 1816 throw new IllegalArgumentException( 1817 String.format( 1818 "Your tests suite hasn't been built with " 1819 + "abi '%s' support, this suite currently supports '%s'.", 1820 mAbiName, archAbis)); 1821 } else { 1822 abis.add(new Abi(mAbiName, AbiUtils.getBitness(mAbiName))); 1823 return abis; 1824 } 1825 } else { 1826 // Run on all abi in common between the device and suite builds. 1827 List<String> deviceAbis = getDeviceAbis(device); 1828 if (deviceAbis.isEmpty()) { 1829 throw new HarnessRuntimeException( 1830 String.format( 1831 "Couldn't determinate the abi of the device '%s'.", 1832 device.getSerialNumber()), 1833 DeviceErrorIdentifier.DEVICE_UNEXPECTED_RESPONSE); 1834 } 1835 for (String abi : deviceAbis) { 1836 if ((mSkipHostArchCheck || archAbis.contains(abi)) 1837 && AbiUtils.isAbiSupportedByCompatibility(abi)) { 1838 abis.add(new Abi(abi, AbiUtils.getBitness(abi))); 1839 } else { 1840 CLog.d( 1841 "abi '%s' is supported by device but not by this suite build (%s), " 1842 + "tests will not run against it.", 1843 abi, archAbis); 1844 } 1845 } 1846 if (abis.isEmpty()) { 1847 throw new IllegalArgumentException( 1848 String.format( 1849 "None of the abi supported by this tests suite build ('%s') are " 1850 + "supported by the device ('%s').", 1851 archAbis, deviceAbis)); 1852 } 1853 return abis; 1854 } 1855 } 1856 1857 /** Returns the primary abi of the device or host if it's a null device. */ getPrimaryAbi(ITestDevice device)1858 private String getPrimaryAbi(ITestDevice device) throws DeviceNotAvailableException { 1859 if (device.getIDevice() instanceof NullDevice) { 1860 Set<String> hostAbis = getHostAbis(); 1861 return hostAbis.iterator().next(); 1862 } 1863 String property = device.getProperty(PRODUCT_CPU_ABI_KEY); 1864 if (property == null) { 1865 String serial = device.getSerialNumber(); 1866 throw new DeviceNotAvailableException( 1867 String.format( 1868 "Device '%s' was not online to query %s", serial, PRODUCT_CPU_ABI_KEY), 1869 serial, 1870 DeviceErrorIdentifier.DEVICE_UNAVAILABLE); 1871 } 1872 return property.trim(); 1873 } 1874 1875 /** Returns the list of abis supported by the device or host if it's a null device. */ getDeviceAbis(ITestDevice device)1876 private List<String> getDeviceAbis(ITestDevice device) throws DeviceNotAvailableException { 1877 if (device.getIDevice() instanceof NullDevice) { 1878 return new ArrayList<>(getHostAbis()); 1879 } 1880 // Make it an arrayList to be able to modify the content. 1881 return new ArrayList<>(Arrays.asList(AbiFormatter.getSupportedAbis(device, ""))); 1882 } 1883 1884 /** Return the abis supported by the Host build target architecture. Exposed for testing. */ 1885 @VisibleForTesting getAbisForBuildTargetArch()1886 protected Set<String> getAbisForBuildTargetArch() { 1887 return getAbisForBuildTargetArchFromSuite(); 1888 } 1889 1890 /** Returns the possible abis from the TestSuiteInfo. */ getAbisForBuildTargetArchFromSuite()1891 public static Set<String> getAbisForBuildTargetArchFromSuite() { 1892 // If TestSuiteInfo does not exists, the stub arch will be replaced by all possible abis. 1893 Set<String> abis = new LinkedHashSet<>(); 1894 for (String arch : TestSuiteInfo.getInstance().getTargetArchs()) { 1895 abis.addAll(AbiUtils.getAbisForArch(arch)); 1896 } 1897 return abis; 1898 } 1899 1900 /** Returns the host machine abis. */ 1901 @VisibleForTesting getHostAbis()1902 protected Set<String> getHostAbis() { 1903 return AbiUtils.getHostAbi(); 1904 } 1905 1906 /** Returns the abi requested with the option -a or --abi. */ getRequestedAbi()1907 public final String getRequestedAbi() { 1908 return mAbiName; 1909 } 1910 1911 /** 1912 * Apply the metadata filter to the config and see if the config should run. 1913 * 1914 * @param config The {@link IConfiguration} being evaluated. 1915 * @param include the metadata include filter 1916 * @param exclude the metadata exclude filter 1917 * @return True if the module should run, false otherwise. 1918 */ 1919 @VisibleForTesting filterByConfigMetadata( IConfiguration config, MultiMap<String, String> include, MultiMap<String, String> exclude)1920 public boolean filterByConfigMetadata( 1921 IConfiguration config, 1922 MultiMap<String, String> include, 1923 MultiMap<String, String> exclude) { 1924 MultiMap<String, String> metadata = config.getConfigurationDescription().getAllMetaData(); 1925 boolean shouldInclude = false; 1926 for (String key : include.keySet()) { 1927 Set<String> filters = new HashSet<>(include.get(key)); 1928 if (metadata.containsKey(key)) { 1929 filters.retainAll(metadata.get(key)); 1930 if (!filters.isEmpty()) { 1931 // inclusion filter is not empty and there's at least one matching inclusion 1932 // rule so there's no need to match other inclusion rules 1933 shouldInclude = true; 1934 break; 1935 } 1936 } 1937 } 1938 if (!include.isEmpty() && !shouldInclude) { 1939 // if inclusion filter is not empty and we didn't find a match, the module will not be 1940 // included 1941 return false; 1942 } 1943 // Now evaluate exclusion rules, this ordering also means that exclusion rules may override 1944 // inclusion rules: a config already matched for inclusion may still be excluded if matching 1945 // rules exist 1946 for (String key : exclude.keySet()) { 1947 Set<String> filters = new HashSet<>(exclude.get(key)); 1948 if (metadata.containsKey(key)) { 1949 filters.retainAll(metadata.get(key)); 1950 if (!filters.isEmpty()) { 1951 // we found at least one matching exclusion rules, so we are excluding this 1952 // this module 1953 return false; 1954 } 1955 } 1956 } 1957 // we've matched at least one inclusion rule (if there's any) AND we didn't match any of the 1958 // exclusion rules (if there's any) 1959 return true; 1960 } 1961 1962 /** 1963 * Filter out the preparers that were not whitelisted. This is useful for collect-tests-only 1964 * where some preparers are not needed to dry run through the invocation. 1965 * 1966 * @param config the {@link IConfiguration} considered for filtering. 1967 * @param preparerWhiteList the current preparer whitelist. 1968 */ 1969 @VisibleForTesting filterPreparers(IConfiguration config, Set<String> preparerWhiteList)1970 void filterPreparers(IConfiguration config, Set<String> preparerWhiteList) { 1971 // If no filters was provided, skip the filtering. 1972 if (preparerWhiteList.isEmpty()) { 1973 return; 1974 } 1975 for (IDeviceConfiguration deviceConfig : config.getDeviceConfig()) { 1976 List<ITargetPreparer> preparers = new ArrayList<>(deviceConfig.getTargetPreparers()); 1977 for (ITargetPreparer prep : preparers) { 1978 if (!preparerWhiteList.contains(prep.getClass().getName())) { 1979 deviceConfig.getTargetPreparers().remove(prep); 1980 } 1981 } 1982 } 1983 } 1984 1985 /** 1986 * Apply the Runner whitelist filtering, removing any runner that was not whitelisted. If a 1987 * configuration has several runners, some might be removed and the config will still run. 1988 * 1989 * @param config The {@link IConfiguration} being evaluated. 1990 * @param allowedRunners The current runner whitelist. 1991 * @return True if the configuration module is allowed to run, false otherwise. 1992 */ 1993 @VisibleForTesting filterByRunnerType(IConfiguration config, Set<String> allowedRunners)1994 protected boolean filterByRunnerType(IConfiguration config, Set<String> allowedRunners) { 1995 // If no filters are provided, simply run everything. 1996 if (allowedRunners.isEmpty()) { 1997 return true; 1998 } 1999 Iterator<IRemoteTest> iterator = config.getTests().iterator(); 2000 while (iterator.hasNext()) { 2001 IRemoteTest test = iterator.next(); 2002 if (!allowedRunners.contains(test.getClass().getName())) { 2003 CLog.d( 2004 "Runner '%s' in module '%s' was skipped by the runner whitelist: '%s'.", 2005 test.getClass().getName(), config.getName(), allowedRunners); 2006 iterator.remove(); 2007 } 2008 } 2009 2010 if (config.getTests().isEmpty()) { 2011 CLog.d("Module %s does not have any more tests, skipping it.", config.getName()); 2012 return false; 2013 } 2014 return true; 2015 } 2016 disableAutoRetryTimeReporting()2017 void disableAutoRetryTimeReporting() { 2018 mDisableAutoRetryTimeReporting = true; 2019 } 2020 2021 @VisibleForTesting setModuleInProgress(ModuleDefinition moduleInProgress)2022 void setModuleInProgress(ModuleDefinition moduleInProgress) { 2023 mModuleInProgress = moduleInProgress; 2024 } 2025 setAbis(Set<IAbi> abis)2026 public final void setAbis(Set<IAbi> abis) { 2027 mAbis.addAll(abis); 2028 } 2029 shouldModuleRun(ModuleDefinition module)2030 protected boolean shouldModuleRun(ModuleDefinition module) { 2031 return true; 2032 } 2033 setMultiDeviceStrategy(MultiDeviceModuleStrategy strategy)2034 public void setMultiDeviceStrategy(MultiDeviceModuleStrategy strategy) { 2035 mMultiDevicesStrategy = strategy; 2036 } 2037 getMultiDeviceStrategy()2038 public MultiDeviceModuleStrategy getMultiDeviceStrategy() { 2039 return mMultiDevicesStrategy; 2040 } 2041 setIntraModuleSharding(boolean intraModuleSharding)2042 public void setIntraModuleSharding(boolean intraModuleSharding) { 2043 mIntraModuleSharding = intraModuleSharding; 2044 } 2045 getIntraModuleSharding()2046 public boolean getIntraModuleSharding() { 2047 return mIntraModuleSharding; 2048 } 2049 setSkipContext(SkipContext skipContext)2050 public void setSkipContext(SkipContext skipContext) { 2051 mSkipContext = skipContext; 2052 } 2053 2054 /* Return a {@link boolean} for the setting of prioritize-host-config.*/ getPrioritizeHostConfig()2055 boolean getPrioritizeHostConfig() { 2056 return mPrioritizeHostConfig; 2057 } 2058 2059 /** 2060 * Set option prioritize-host-config. 2061 * 2062 * @param prioritizeHostConfig true to prioritize host config, i.e., run host test if possible. 2063 */ 2064 @com.google.common.annotations.VisibleForTesting setPrioritizeHostConfig(boolean prioritizeHostConfig)2065 protected void setPrioritizeHostConfig(boolean prioritizeHostConfig) { 2066 mPrioritizeHostConfig = prioritizeHostConfig; 2067 } 2068 } 2069