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.IBuildInfo; 21 import com.android.tradefed.config.ConfigurationException; 22 import com.android.tradefed.config.IConfiguration; 23 import com.android.tradefed.config.IConfigurationReceiver; 24 import com.android.tradefed.config.IDeviceConfiguration; 25 import com.android.tradefed.config.Option; 26 import com.android.tradefed.config.Option.Importance; 27 import com.android.tradefed.config.OptionCopier; 28 import com.android.tradefed.device.DeviceNotAvailableException; 29 import com.android.tradefed.device.ITestDevice; 30 import com.android.tradefed.device.NullDevice; 31 import com.android.tradefed.device.StubDevice; 32 import com.android.tradefed.device.cloud.NestedRemoteDevice; 33 import com.android.tradefed.device.metric.CollectorHelper; 34 import com.android.tradefed.device.metric.IMetricCollector; 35 import com.android.tradefed.device.metric.IMetricCollectorReceiver; 36 import com.android.tradefed.invoker.IInvocationContext; 37 import com.android.tradefed.invoker.shard.token.ITokenRequest; 38 import com.android.tradefed.invoker.shard.token.TokenProperty; 39 import com.android.tradefed.log.ITestLogger; 40 import com.android.tradefed.log.LogUtil.CLog; 41 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 42 import com.android.tradefed.result.ITestInvocationListener; 43 import com.android.tradefed.result.ITestLoggerReceiver; 44 import com.android.tradefed.result.ResultForwarder; 45 import com.android.tradefed.suite.checker.ISystemStatusChecker; 46 import com.android.tradefed.suite.checker.ISystemStatusCheckerReceiver; 47 import com.android.tradefed.suite.checker.StatusCheckerResult; 48 import com.android.tradefed.suite.checker.StatusCheckerResult.CheckStatus; 49 import com.android.tradefed.targetprep.ITargetPreparer; 50 import com.android.tradefed.testtype.Abi; 51 import com.android.tradefed.testtype.IAbi; 52 import com.android.tradefed.testtype.IBuildReceiver; 53 import com.android.tradefed.testtype.IDeviceTest; 54 import com.android.tradefed.testtype.IInvocationContextReceiver; 55 import com.android.tradefed.testtype.IMultiDeviceTest; 56 import com.android.tradefed.testtype.IRemoteTest; 57 import com.android.tradefed.testtype.IReportNotExecuted; 58 import com.android.tradefed.testtype.IRuntimeHintProvider; 59 import com.android.tradefed.testtype.IShardableTest; 60 import com.android.tradefed.testtype.ITestCollector; 61 import com.android.tradefed.util.AbiFormatter; 62 import com.android.tradefed.util.AbiUtils; 63 import com.android.tradefed.util.MultiMap; 64 import com.android.tradefed.util.TimeUtil; 65 66 import com.google.inject.Inject; 67 import com.google.inject.Injector; 68 69 import java.util.ArrayList; 70 import java.util.Arrays; 71 import java.util.Collection; 72 import java.util.Collections; 73 import java.util.HashMap; 74 import java.util.HashSet; 75 import java.util.Iterator; 76 import java.util.LinkedHashMap; 77 import java.util.LinkedHashSet; 78 import java.util.List; 79 import java.util.Map; 80 import java.util.Map.Entry; 81 import java.util.Random; 82 import java.util.Set; 83 84 /** 85 * Abstract class used to run Test Suite. This class provide the base of how the Suite will be run. 86 * Each implementation can define the list of tests via the {@link #loadTests()} method. 87 */ 88 public abstract class ITestSuite 89 implements IRemoteTest, 90 IDeviceTest, 91 IMultiDeviceTest, 92 IBuildReceiver, 93 ISystemStatusCheckerReceiver, 94 IShardableTest, 95 ITestCollector, 96 IInvocationContextReceiver, 97 IRuntimeHintProvider, 98 IMetricCollectorReceiver, 99 IConfigurationReceiver, 100 IReportNotExecuted, 101 ITokenRequest { 102 103 /** The Retry Strategy to be used when re-running some tests. */ 104 public enum RetryStrategy { 105 /** Rerun all the tests for the number of attempts specified. */ 106 ITERATIONS, 107 /** 108 * Rerun all the tests until the max count is reached or a failure occurs whichever come 109 * first. 110 */ 111 RERUN_UNTIL_FAILURE, 112 /** 113 * Rerun all the test case failures until passed or the max number of attempts specified. 114 */ 115 RETRY_TEST_CASE_FAILURE, 116 /** Rerun all the test run failures until passed or the max number of attempts specified. */ 117 RETRY_TEST_RUN_FAILURE, 118 /** 119 * Rerun all the test run and test cases failures until passed or the max number of attempts 120 * specified. Test run failures are rerun in priority (a.k.a. if a run failure and a test 121 * case failure occur, the run failure is rerun). 122 */ 123 RETRY_ANY_FAILURE, 124 } 125 126 public static final String SKIP_SYSTEM_STATUS_CHECKER = "skip-system-status-check"; 127 public static final String RUNNER_WHITELIST = "runner-whitelist"; 128 public static final String PREPARER_WHITELIST = "preparer-whitelist"; 129 public static final String MODULE_CHECKER_PRE = "PreModuleChecker"; 130 public static final String MODULE_CHECKER_POST = "PostModuleChecker"; 131 public static final String ABI_OPTION = "abi"; 132 public static final String SKIP_HOST_ARCH_CHECK = "skip-host-arch-check"; 133 public static final String PRIMARY_ABI_RUN = "primary-abi-only"; 134 public static final String PARAMETER_KEY = "parameter"; 135 public static final String TOKEN_KEY = "token"; 136 public static final String MODULE_METADATA_INCLUDE_FILTER = "module-metadata-include-filter"; 137 public static final String MODULE_METADATA_EXCLUDE_FILTER = "module-metadata-exclude-filter"; 138 139 private static final String PRODUCT_CPU_ABI_KEY = "ro.product.cpu.abi"; 140 141 // Options for test failure case 142 @Option( 143 name = "bugreport-on-failure", 144 description = 145 "Take a bugreport on every test failure. Warning: This may require a lot" 146 + "of storage space of the machine running the tests." 147 ) 148 private boolean mBugReportOnFailure = false; 149 150 @Deprecated 151 @Option( 152 name = "logcat-on-failure", 153 description = "Take a logcat snapshot on every test failure." 154 ) 155 private boolean mLogcatOnFailure = false; 156 157 @Deprecated 158 @Option( 159 name = "logcat-on-failure-size", 160 description = 161 "The max number of logcat data in bytes to capture when " 162 + "--logcat-on-failure is on. Should be an amount that can comfortably fit in memory." 163 ) 164 private int mMaxLogcatBytes = 500 * 1024; // 500K 165 166 @Deprecated 167 @Option( 168 name = "screenshot-on-failure", 169 description = "Take a screenshot on every test failure." 170 ) 171 private boolean mScreenshotOnFailure = false; 172 173 @Option(name = "reboot-on-failure", 174 description = "Reboot the device after every test failure.") 175 private boolean mRebootOnFailure = false; 176 177 // Options for suite runner behavior 178 @Option(name = "reboot-per-module", description = "Reboot the device before every module run.") 179 private boolean mRebootPerModule = false; 180 181 @Option(name = "reboot-at-last-retry", 182 description = "Reboot the device at the last intra-module retry") 183 private boolean mRebootAtLastRetry = false; 184 185 @Option(name = "skip-all-system-status-check", 186 description = "Whether all system status check between modules should be skipped") 187 private boolean mSkipAllSystemStatusCheck = false; 188 189 @Option( 190 name = SKIP_SYSTEM_STATUS_CHECKER, 191 description = 192 "Disable specific system status checkers." 193 + "Specify zero or more SystemStatusChecker as canonical class names. e.g. " 194 + "\"com.android.tradefed.suite.checker.KeyguardStatusChecker\" If not " 195 + "specified, all configured or whitelisted system status checkers will " 196 + "run." 197 ) 198 private Set<String> mSystemStatusCheckBlacklist = new HashSet<>(); 199 200 @Option( 201 name = "report-system-checkers", 202 description = "Whether reporting system checkers as test or not." 203 ) 204 private boolean mReportSystemChecker = false; 205 206 @Deprecated 207 @Option( 208 name = "random-order", 209 description = "Whether randomizing the order of the modules to be ran or not." 210 ) 211 private boolean mRandomOrder = false; 212 213 @Deprecated 214 @Option( 215 name = "random-seed", 216 description = "Seed to randomize the order of the modules." 217 ) 218 private long mRandomSeed = -1; 219 220 @Option( 221 name = "collect-tests-only", 222 description = 223 "Only invoke the suite to collect list of applicable test cases. All " 224 + "test run callbacks will be triggered, but test execution will not be " 225 + "actually carried out." 226 ) 227 private boolean mCollectTestsOnly = false; 228 229 // Abi related options 230 @Option( 231 name = ABI_OPTION, 232 shortName = 'a', 233 description = "the abi to test. For example: 'arm64-v8a'.", 234 importance = Importance.IF_UNSET 235 ) 236 private String mAbiName = null; 237 238 @Option( 239 name = SKIP_HOST_ARCH_CHECK, 240 description = "Whether host architecture check should be skipped." 241 ) 242 private boolean mSkipHostArchCheck = false; 243 244 @Option( 245 name = PRIMARY_ABI_RUN, 246 description = 247 "Whether to run tests with only the device primary abi. " 248 + "This is overriden by the --abi option." 249 ) 250 private boolean mPrimaryAbiRun = false; 251 252 @Option( 253 name = MODULE_METADATA_INCLUDE_FILTER, 254 description = 255 "Include modules for execution based on matching of metadata fields: for any of " 256 + "the specified filter name and value, if a module has a metadata field " 257 + "with the same name and value, it will be included. When both module " 258 + "inclusion and exclusion rules are applied, inclusion rules will be " 259 + "evaluated first. Using this together with test filter inclusion rules " 260 + "may result in no tests to execute if the rules don't overlap." 261 ) 262 private MultiMap<String, String> mModuleMetadataIncludeFilter = new MultiMap<>(); 263 264 @Option( 265 name = MODULE_METADATA_EXCLUDE_FILTER, 266 description = 267 "Exclude modules for execution based on matching of metadata fields: for any of " 268 + "the specified filter name and value, if a module has a metadata field " 269 + "with the same name and value, it will be excluded. When both module " 270 + "inclusion and exclusion rules are applied, inclusion rules will be " 271 + "evaluated first." 272 ) 273 private MultiMap<String, String> mModuleMetadataExcludeFilter = new MultiMap<>(); 274 275 @Option(name = RUNNER_WHITELIST, description = "Runner class(es) that are allowed to run.") 276 private Set<String> mAllowedRunners = new HashSet<>(); 277 278 @Option( 279 name = PREPARER_WHITELIST, 280 description = 281 "Preparer class(es) that are allowed to run. This mostly usefeul for dry-runs." 282 ) 283 private Set<String> mAllowedPreparers = new HashSet<>(); 284 285 @Option( 286 name = "intra-module-sharding", 287 description = "Whether or not to allow intra-module sharding." 288 ) 289 private boolean mIntraModuleSharding = true; 290 291 @Option( 292 name = "isolated-module", 293 description = "Whether or not to attempt the module isolation between modules" 294 ) 295 private boolean mIsolatedModule = false; 296 297 @Option( 298 name = "reboot-before-test", 299 description = "Reboot the device before the test suite starts." 300 ) 301 private boolean mRebootBeforeTest = false; 302 303 // [Options relate to module retry and intra-module retry][ 304 @Option( 305 name = "max-testcase-run-count", 306 description = 307 "If the IRemoteTest can have its testcases run multiple times, " 308 + "the max number of runs for each testcase." 309 ) 310 private int mMaxRunLimit = 1; 311 312 @Option( 313 name = "retry-strategy", 314 description = 315 "The retry strategy to be used when re-running some tests with " 316 + "--max-testcase-run-count" 317 ) 318 private RetryStrategy mRetryStrategy = RetryStrategy.RETRY_TEST_CASE_FAILURE; 319 320 @Option( 321 name = "merge-attempts", 322 description = "Whether or not to use the merge the results of the different attempts." 323 ) 324 private boolean mMergeAttempts = true; 325 // end [Options relate to module retry and intra-module retry] 326 327 private ITestDevice mDevice; 328 private IBuildInfo mBuildInfo; 329 private Map<ITestDevice, IBuildInfo> mDeviceInfos; 330 private List<ISystemStatusChecker> mSystemStatusCheckers; 331 private IInvocationContext mContext; 332 private List<IMetricCollector> mMetricCollectors; 333 private IConfiguration mMainConfiguration; 334 335 // Sharding attributes 336 private boolean mIsSharded = false; 337 private ModuleDefinition mDirectModule = null; 338 private boolean mShouldMakeDynamicModule = true; 339 340 // Guice object 341 private Injector mInjector; 342 343 // Current modules to run, null if not started to run yet. 344 private List<ModuleDefinition> mRunModules = null; 345 346 /** 347 * Get the current Guice {@link Injector} from the invocation. It should allow us to continue 348 * the object injection of modules. 349 */ 350 @Inject setInvocationInjector(Injector injector)351 public void setInvocationInjector(Injector injector) { 352 mInjector = injector; 353 } 354 355 /** Forward our invocation scope guice objects to whoever needs them in modules. */ applyGuiceInjection(LinkedHashMap<String, IConfiguration> runConfig)356 private void applyGuiceInjection(LinkedHashMap<String, IConfiguration> runConfig) { 357 if (mInjector == null) { 358 // TODO: Convert to a strong failure 359 CLog.d("No injector received by the suite."); 360 return; 361 } 362 for (IConfiguration config : runConfig.values()) { 363 for (IRemoteTest test : config.getTests()) { 364 mInjector.injectMembers(test); 365 } 366 } 367 } 368 369 /** 370 * Abstract method to load the tests configuration that will be run. Each tests is defined by a 371 * {@link IConfiguration} and a unique name under which it will report results. 372 */ loadTests()373 public abstract LinkedHashMap<String, IConfiguration> loadTests(); 374 375 /** 376 * Return an instance of the class implementing {@link ITestSuite}. 377 */ createInstance()378 private ITestSuite createInstance() { 379 try { 380 return this.getClass().newInstance(); 381 } catch (InstantiationException | IllegalAccessException e) { 382 throw new RuntimeException(e); 383 } 384 } 385 loadAndFilter()386 private LinkedHashMap<String, IConfiguration> loadAndFilter() { 387 LinkedHashMap<String, IConfiguration> runConfig = loadTests(); 388 if (runConfig.isEmpty()) { 389 CLog.i("No config were loaded. Nothing to run."); 390 return runConfig; 391 } 392 // Apply our guice scope to all modules objects 393 applyGuiceInjection(runConfig); 394 395 LinkedHashMap<String, IConfiguration> filteredConfig = new LinkedHashMap<>(); 396 for (Entry<String, IConfiguration> config : runConfig.entrySet()) { 397 if (!mModuleMetadataIncludeFilter.isEmpty() 398 || !mModuleMetadataExcludeFilter.isEmpty()) { 399 if (!filterByConfigMetadata( 400 config.getValue(), 401 mModuleMetadataIncludeFilter, 402 mModuleMetadataExcludeFilter)) { 403 // if the module config did not pass the metadata filters, it's excluded 404 // from execution. 405 continue; 406 } 407 } 408 if (!filterByRunnerType(config.getValue(), mAllowedRunners)) { 409 // if the module config did not pass the runner type filter, it's excluded from 410 // execution. 411 continue; 412 } 413 filterPreparers(config.getValue(), mAllowedPreparers); 414 filteredConfig.put(config.getKey(), config.getValue()); 415 } 416 runConfig.clear(); 417 return filteredConfig; 418 } 419 420 /** Helper that creates and returns the list of {@link ModuleDefinition} to be executed. */ createExecutionList()421 private List<ModuleDefinition> createExecutionList() { 422 List<ModuleDefinition> runModules = new ArrayList<>(); 423 if (mDirectModule != null) { 424 // If we are sharded and already know what to run then we just do it. 425 runModules.add(mDirectModule); 426 mDirectModule.setDevice(mDevice); 427 mDirectModule.setDeviceInfos(mDeviceInfos); 428 mDirectModule.setBuild(mBuildInfo); 429 return runModules; 430 } 431 432 LinkedHashMap<String, IConfiguration> runConfig = loadAndFilter(); 433 if (runConfig.isEmpty()) { 434 CLog.i("No config were loaded. Nothing to run."); 435 return runModules; 436 } 437 438 for (Entry<String, IConfiguration> config : runConfig.entrySet()) { 439 // Validate the configuration, it will throw if not valid. 440 ValidateSuiteConfigHelper.validateConfig(config.getValue()); 441 Map<String, List<ITargetPreparer>> preparersPerDevice = 442 getPreparerPerDevice(config.getValue()); 443 ModuleDefinition module = 444 new ModuleDefinition( 445 config.getKey(), 446 config.getValue().getTests(), 447 preparersPerDevice, 448 config.getValue().getMultiTargetPreparers(), 449 config.getValue()); 450 module.setDevice(mDevice); 451 module.setDeviceInfos(mDeviceInfos); 452 module.setBuild(mBuildInfo); 453 runModules.add(module); 454 } 455 456 /** Randomize all the modules to be ran if random-order is set and no sharding.*/ 457 if (mRandomOrder) { 458 randomizeTestModules(runModules, mRandomSeed); 459 } 460 461 CLog.logAndDisplay(LogLevel.DEBUG, "[Total Unique Modules = %s]", runModules.size()); 462 // Free the map once we are done with it. 463 runConfig = null; 464 return runModules; 465 } 466 467 /** 468 * Helper method that handle randomizing the order of the modules. 469 * 470 * @param runModules The {@code List<ModuleDefinition>} of the test modules to be ran. 471 * @param randomSeed The {@code long} seed used to randomize the order of test modules, use the 472 * current time as seed if no specified seed provided. 473 */ 474 @VisibleForTesting randomizeTestModules(List<ModuleDefinition> runModules, long randomSeed)475 void randomizeTestModules(List<ModuleDefinition> runModules, long randomSeed) { 476 // Use current time as seed if no specified seed provided. 477 if (randomSeed == -1) { 478 randomSeed = System.currentTimeMillis(); 479 } 480 CLog.i("Randomizing all the modules with seed: %s", randomSeed); 481 Collections.shuffle(runModules, new Random(randomSeed)); 482 } 483 checkClassLoad(Set<String> classes, String type)484 private void checkClassLoad(Set<String> classes, String type) { 485 for (String c : classes) { 486 try { 487 Class.forName(c); 488 } catch (ClassNotFoundException e) { 489 ConfigurationException ex = 490 new ConfigurationException( 491 String.format( 492 "--%s must contains valid class, %s was not found", 493 type, c), 494 e); 495 throw new RuntimeException(ex); 496 } 497 } 498 } 499 500 /** Create the mapping of device to its target_preparer. */ getPreparerPerDevice(IConfiguration config)501 private Map<String, List<ITargetPreparer>> getPreparerPerDevice(IConfiguration config) { 502 Map<String, List<ITargetPreparer>> res = new LinkedHashMap<>(); 503 for (IDeviceConfiguration holder : config.getDeviceConfig()) { 504 List<ITargetPreparer> preparers = new ArrayList<>(); 505 res.put(holder.getDeviceName(), preparers); 506 preparers.addAll(holder.getTargetPreparers()); 507 } 508 return res; 509 } 510 511 /** 512 * Opportunity to clean up all the things that were needed during the suites setup but are not 513 * required to run the tests. 514 */ cleanUpSuiteSetup()515 void cleanUpSuiteSetup() { 516 // Empty by default. 517 } 518 519 /** Generic run method for all test loaded from {@link #loadTests()}. */ 520 @Override run(ITestInvocationListener listener)521 public final void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 522 // Load and check the module checkers, runners and preparers in black and whitelist 523 checkClassLoad(mSystemStatusCheckBlacklist, SKIP_SYSTEM_STATUS_CHECKER); 524 checkClassLoad(mAllowedRunners, RUNNER_WHITELIST); 525 checkClassLoad(mAllowedPreparers, PREPARER_WHITELIST); 526 527 mRunModules = createExecutionList(); 528 // Check if we have something to run. 529 if (mRunModules.isEmpty()) { 530 CLog.i("No tests to be run."); 531 return; 532 } 533 534 // Allow checkers to log files for easier debugging. 535 for (ISystemStatusChecker checker : mSystemStatusCheckers) { 536 if (checker instanceof ITestLoggerReceiver) { 537 ((ITestLoggerReceiver) checker).setTestLogger(listener); 538 } 539 } 540 541 // If requested reboot each device before the testing starts. 542 if (mRebootBeforeTest) { 543 for (ITestDevice device : mContext.getDevices()) { 544 if (!(device.getIDevice() instanceof StubDevice)) { 545 CLog.d( 546 "Rebooting device '%s' before test starts as requested.", 547 device.getSerialNumber()); 548 mDevice.reboot(); 549 } 550 } 551 } 552 553 /** Setup a special listener to take actions on test failures. */ 554 TestFailureListener failureListener = 555 new TestFailureListener( 556 mContext.getDevices(), mBugReportOnFailure, mRebootOnFailure); 557 /** Create the list of listeners applicable at the module level. */ 558 List<ITestInvocationListener> moduleListeners = createModuleListeners(); 559 560 // Only print the running log if we are going to run something. 561 if (mRunModules.get(0).hasTests()) { 562 CLog.logAndDisplay( 563 LogLevel.INFO, 564 "%s running %s modules: %s", 565 mDevice.getSerialNumber(), 566 mRunModules.size(), 567 mRunModules); 568 } 569 570 /** Run all the module, make sure to reduce the list to release resources as we go. */ 571 try { 572 while (!mRunModules.isEmpty()) { 573 ModuleDefinition module = mRunModules.remove(0); 574 // Before running the module we ensure it has tests at this point or skip completely 575 // to avoid running SystemCheckers and preparation for nothing. 576 if (module.hasTests()) { 577 continue; 578 } 579 580 // Populate the module context with devices and builds 581 for (String deviceName : mContext.getDeviceConfigNames()) { 582 module.getModuleInvocationContext() 583 .addAllocatedDevice(deviceName, mContext.getDevice(deviceName)); 584 module.getModuleInvocationContext() 585 .addDeviceBuildInfo(deviceName, mContext.getBuildInfo(deviceName)); 586 } 587 listener.testModuleStarted(module.getModuleInvocationContext()); 588 // Trigger module start on module level listener too 589 new ResultForwarder(moduleListeners) 590 .testModuleStarted(module.getModuleInvocationContext()); 591 try { 592 runSingleModule(module, listener, moduleListeners, failureListener); 593 } finally { 594 // Trigger module end on module level listener too 595 new ResultForwarder(moduleListeners).testModuleEnded(); 596 // clear out module invocation context since we are now done with module 597 // execution 598 listener.testModuleEnded(); 599 } 600 // Module isolation routine 601 moduleIsolation(mContext, listener); 602 } 603 } catch (DeviceNotAvailableException e) { 604 CLog.e( 605 "A DeviceNotAvailableException occurred, following modules did not run: %s", 606 mRunModules); 607 reportNotExecuted(listener, "Module did not run due to device not available."); 608 throw e; 609 } 610 } 611 612 /** 613 * Returns the list of {@link ITestInvocationListener} applicable to the {@link ModuleListener} 614 * level. These listeners will be re-used for each module, they will not be re-instantiated so 615 * they should not assume an internal state. 616 */ createModuleListeners()617 protected List<ITestInvocationListener> createModuleListeners() { 618 return new ArrayList<>(); 619 } 620 621 /** 622 * Routine that attempt to reset a device between modules in order to provide isolation. 623 * 624 * @param context The invocation context. 625 * @param logger A logger where extra logs can be saved. 626 * @throws DeviceNotAvailableException 627 */ moduleIsolation(IInvocationContext context, ITestLogger logger)628 private void moduleIsolation(IInvocationContext context, ITestLogger logger) 629 throws DeviceNotAvailableException { 630 // TODO: we can probably make it smarter: Did any test ran for example? 631 ITestDevice device = context.getDevices().get(0); 632 if (mIsolatedModule && (device instanceof NestedRemoteDevice)) { 633 boolean res = 634 ((NestedRemoteDevice) device) 635 .resetVirtualDevice( 636 logger, 637 context.getBuildInfos().get(0), 638 /* Do not collect the logs */ false); 639 if (!res) { 640 String serial = device.getSerialNumber(); 641 throw new DeviceNotAvailableException( 642 String.format( 643 "Failed to reset the AVD '%s' during module isolation.", serial), 644 serial); 645 } 646 } 647 } 648 649 /** 650 * Helper method that handle running a single module logic. 651 * 652 * @param module The {@link ModuleDefinition} to be ran. 653 * @param listener The {@link ITestInvocationListener} where to report results 654 * @param moduleListeners The {@link ITestInvocationListener}s that runs at the module level. 655 * @param failureListener special listener that we add to collect information on failures. 656 * @throws DeviceNotAvailableException 657 */ runSingleModule( ModuleDefinition module, ITestInvocationListener listener, List<ITestInvocationListener> moduleListeners, TestFailureListener failureListener)658 private void runSingleModule( 659 ModuleDefinition module, 660 ITestInvocationListener listener, 661 List<ITestInvocationListener> moduleListeners, 662 TestFailureListener failureListener) 663 throws DeviceNotAvailableException { 664 if (mRebootPerModule) { 665 if ("user".equals(mDevice.getProperty("ro.build.type"))) { 666 CLog.e( 667 "reboot-per-module should only be used during development, " 668 + "this is a\" user\" build device"); 669 } else { 670 CLog.d("Rebooting device before starting next module"); 671 mDevice.reboot(); 672 } 673 } 674 675 if (!mSkipAllSystemStatusCheck) { 676 runPreModuleCheck(module.getId(), mSystemStatusCheckers, mDevice, listener); 677 } 678 if (mCollectTestsOnly) { 679 module.setCollectTestsOnly(mCollectTestsOnly); 680 } 681 // Pass the run defined collectors to be used. 682 module.setMetricCollectors(CollectorHelper.cloneCollectors(mMetricCollectors)); 683 // Pass the main invocation logSaver 684 module.setLogSaver(mMainConfiguration.getLogSaver()); 685 // Pass the retry strategy to the module 686 module.setRetryStrategy(mRetryStrategy, mMergeAttempts); 687 // Pass the reboot strategy at the last intra-module retry to the module 688 module.setRebootAtLastRetry(mRebootAtLastRetry); 689 690 // Actually run the module 691 module.run(listener, moduleListeners, failureListener, mMaxRunLimit); 692 693 if (!mSkipAllSystemStatusCheck) { 694 runPostModuleCheck(module.getId(), mSystemStatusCheckers, mDevice, listener); 695 } 696 } 697 698 /** 699 * Helper to run the System Status checkers preExecutionChecks defined for the test and log 700 * their failures. 701 */ runPreModuleCheck( String moduleName, List<ISystemStatusChecker> checkers, ITestDevice device, ITestInvocationListener listener)702 private void runPreModuleCheck( 703 String moduleName, 704 List<ISystemStatusChecker> checkers, 705 ITestDevice device, 706 ITestInvocationListener listener) 707 throws DeviceNotAvailableException { 708 long startTime = System.currentTimeMillis(); 709 CLog.i("Running system status checker before module execution: %s", moduleName); 710 Map<String, String> failures = new LinkedHashMap<>(); 711 boolean bugreportNeeded = false; 712 for (ISystemStatusChecker checker : checkers) { 713 // Check if the status checker should be skipped. 714 if (mSystemStatusCheckBlacklist.contains(checker.getClass().getName())) { 715 CLog.d( 716 "%s was skipped via %s", 717 checker.getClass().getName(), SKIP_SYSTEM_STATUS_CHECKER); 718 continue; 719 } 720 721 StatusCheckerResult result = new StatusCheckerResult(CheckStatus.FAILED); 722 try { 723 result = checker.preExecutionCheck(device); 724 } catch (RuntimeException e) { 725 // Catch RuntimeException to avoid leaking throws that go to the invocation. 726 result.setErrorMessage(e.getMessage()); 727 result.setBugreportNeeded(true); 728 } 729 if (!CheckStatus.SUCCESS.equals(result.getStatus())) { 730 String errorMessage = 731 (result.getErrorMessage() == null) ? "" : result.getErrorMessage(); 732 failures.put(checker.getClass().getCanonicalName(), errorMessage); 733 bugreportNeeded = bugreportNeeded | result.isBugreportNeeded(); 734 CLog.w("System status checker [%s] failed.", checker.getClass().getCanonicalName()); 735 } 736 } 737 if (!failures.isEmpty()) { 738 CLog.w("There are failed system status checkers: %s", failures.toString()); 739 if (bugreportNeeded && !(device.getIDevice() instanceof StubDevice)) { 740 device.logBugreport( 741 String.format("bugreport-checker-pre-module-%s", moduleName), listener); 742 } 743 } 744 745 // We report System checkers like tests. 746 reportModuleCheckerResult(MODULE_CHECKER_PRE, moduleName, failures, startTime, listener); 747 } 748 749 /** 750 * Helper to run the System Status checkers postExecutionCheck defined for the test and log 751 * their failures. 752 */ runPostModuleCheck( String moduleName, List<ISystemStatusChecker> checkers, ITestDevice device, ITestInvocationListener listener)753 private void runPostModuleCheck( 754 String moduleName, 755 List<ISystemStatusChecker> checkers, 756 ITestDevice device, 757 ITestInvocationListener listener) 758 throws DeviceNotAvailableException { 759 long startTime = System.currentTimeMillis(); 760 CLog.i("Running system status checker after module execution: %s", moduleName); 761 Map<String, String> failures = new LinkedHashMap<>(); 762 boolean bugreportNeeded = false; 763 for (ISystemStatusChecker checker : checkers) { 764 // Check if the status checker should be skipped. 765 if (mSystemStatusCheckBlacklist.contains(checker.getClass().getName())) { 766 continue; 767 } 768 769 StatusCheckerResult result = new StatusCheckerResult(CheckStatus.FAILED); 770 try { 771 result = checker.postExecutionCheck(device); 772 } catch (RuntimeException e) { 773 // Catch RuntimeException to avoid leaking throws that go to the invocation. 774 result.setErrorMessage(e.getMessage()); 775 result.setBugreportNeeded(true); 776 } 777 if (!CheckStatus.SUCCESS.equals(result.getStatus())) { 778 String errorMessage = 779 (result.getErrorMessage() == null) ? "" : result.getErrorMessage(); 780 failures.put(checker.getClass().getCanonicalName(), errorMessage); 781 bugreportNeeded = bugreportNeeded | result.isBugreportNeeded(); 782 CLog.w("System status checker [%s] failed", checker.getClass().getCanonicalName()); 783 } 784 } 785 if (!failures.isEmpty()) { 786 CLog.w("There are failed system status checkers: %s", failures.toString()); 787 if (bugreportNeeded && !(device.getIDevice() instanceof StubDevice)) { 788 device.logBugreport( 789 String.format("bugreport-checker-post-module-%s", moduleName), listener); 790 } 791 } 792 793 // We report System checkers like tests. 794 reportModuleCheckerResult(MODULE_CHECKER_POST, moduleName, failures, startTime, listener); 795 } 796 797 /** Helper to report status checker results as test results. */ reportModuleCheckerResult( String identifier, String moduleName, Map<String, String> failures, long startTime, ITestInvocationListener listener)798 private void reportModuleCheckerResult( 799 String identifier, 800 String moduleName, 801 Map<String, String> failures, 802 long startTime, 803 ITestInvocationListener listener) { 804 if (!mReportSystemChecker) { 805 // do not log here, otherwise it could be very verbose. 806 return; 807 } 808 // Avoid messing with the final test count by making them empty runs. 809 listener.testRunStarted(identifier + "_" + moduleName, 0, 0, System.currentTimeMillis()); 810 if (!failures.isEmpty()) { 811 listener.testRunFailed(String.format("%s failed '%s' checkers", moduleName, failures)); 812 } 813 listener.testRunEnded( 814 System.currentTimeMillis() - startTime, new HashMap<String, Metric>()); 815 } 816 817 /** {@inheritDoc} */ 818 @Override split(int shardCountHint)819 public Collection<IRemoteTest> split(int shardCountHint) { 820 if (shardCountHint <= 1 || mIsSharded) { 821 // cannot shard or already sharded 822 return null; 823 } 824 825 LinkedHashMap<String, IConfiguration> runConfig = loadAndFilter(); 826 if (runConfig.isEmpty()) { 827 CLog.i("No config were loaded. Nothing to run."); 828 return null; 829 } 830 injectInfo(runConfig); 831 832 // We split individual tests on double the shardCountHint to provide better average. 833 // The test pool mechanism prevent this from creating too much overhead. 834 List<ModuleDefinition> splitModules = 835 ModuleSplitter.splitConfiguration( 836 runConfig, shardCountHint, mShouldMakeDynamicModule, mIntraModuleSharding); 837 runConfig.clear(); 838 runConfig = null; 839 840 // Clean up the parent that will get sharded: It is fine to clean up before copying the 841 // options, because the sharded module is already created/populated so there is no need 842 // to carry these extra data. 843 cleanUpSuiteSetup(); 844 845 // create an association of one ITestSuite <=> one ModuleDefinition as the smallest 846 // execution unit supported. 847 List<IRemoteTest> splitTests = new ArrayList<>(); 848 for (ModuleDefinition m : splitModules) { 849 ITestSuite suite = createInstance(); 850 OptionCopier.copyOptionsNoThrow(this, suite); 851 suite.mIsSharded = true; 852 suite.mDirectModule = m; 853 splitTests.add(suite); 854 } 855 // return the list of ITestSuite with their ModuleDefinition assigned 856 return splitTests; 857 } 858 859 /** 860 * Inject {@link ITestDevice} and {@link IBuildInfo} to the {@link IRemoteTest}s in the config 861 * before sharding since they may be needed. 862 */ injectInfo(LinkedHashMap<String, IConfiguration> runConfig)863 private void injectInfo(LinkedHashMap<String, IConfiguration> runConfig) { 864 for (IConfiguration config : runConfig.values()) { 865 for (IRemoteTest test : config.getTests()) { 866 if (test instanceof IBuildReceiver) { 867 ((IBuildReceiver) test).setBuild(mBuildInfo); 868 } 869 if (test instanceof IDeviceTest) { 870 ((IDeviceTest) test).setDevice(mDevice); 871 } 872 if (test instanceof IMultiDeviceTest) { 873 ((IMultiDeviceTest) test).setDeviceInfos(mDeviceInfos); 874 } 875 if (test instanceof IInvocationContextReceiver) { 876 ((IInvocationContextReceiver) test).setInvocationContext(mContext); 877 } 878 if (test instanceof ITestCollector) { 879 ((ITestCollector) test).setCollectTestsOnly(mCollectTestsOnly); 880 } 881 } 882 } 883 } 884 885 /** {@inheritDoc} */ 886 @Override setDevice(ITestDevice device)887 public void setDevice(ITestDevice device) { 888 mDevice = device; 889 } 890 891 /** 892 * {@inheritDoc} 893 */ 894 @Override getDevice()895 public ITestDevice getDevice() { 896 return mDevice; 897 } 898 899 /** Set the value of mAbiName */ setAbiName(String abiName)900 public void setAbiName(String abiName) { 901 mAbiName = abiName; 902 } 903 904 /** 905 * {@inheritDoc} 906 */ 907 @Override setBuild(IBuildInfo buildInfo)908 public void setBuild(IBuildInfo buildInfo) { 909 mBuildInfo = buildInfo; 910 } 911 912 /** 913 * Implementation of {@link ITestSuite} may require the build info to load the tests. 914 */ getBuildInfo()915 public IBuildInfo getBuildInfo() { 916 return mBuildInfo; 917 } 918 919 /** {@inheritDoc} */ 920 @Override setDeviceInfos(Map<ITestDevice, IBuildInfo> deviceInfos)921 public void setDeviceInfos(Map<ITestDevice, IBuildInfo> deviceInfos) { 922 mDeviceInfos = deviceInfos; 923 } 924 925 /** Set the value of mPrimaryAbiRun */ setPrimaryAbiRun(boolean primaryAbiRun)926 public void setPrimaryAbiRun(boolean primaryAbiRun) { 927 mPrimaryAbiRun = primaryAbiRun; 928 } 929 930 /** 931 * {@inheritDoc} 932 */ 933 @Override setSystemStatusChecker(List<ISystemStatusChecker> systemCheckers)934 public void setSystemStatusChecker(List<ISystemStatusChecker> systemCheckers) { 935 mSystemStatusCheckers = systemCheckers; 936 } 937 938 /** 939 * Run the test suite in collector only mode, this requires all the sub-tests to implements this 940 * interface too. 941 */ 942 @Override setCollectTestsOnly(boolean shouldCollectTest)943 public void setCollectTestsOnly(boolean shouldCollectTest) { 944 mCollectTestsOnly = shouldCollectTest; 945 } 946 947 /** {@inheritDoc} */ 948 @Override setMetricCollectors(List<IMetricCollector> collectors)949 public void setMetricCollectors(List<IMetricCollector> collectors) { 950 mMetricCollectors = collectors; 951 } 952 953 /** 954 * When doing distributed sharding, we cannot have ModuleDefinition that shares tests in a pool 955 * otherwise intra-module sharding will not work, so we allow to disable it. 956 */ setShouldMakeDynamicModule(boolean dynamicModule)957 public void setShouldMakeDynamicModule(boolean dynamicModule) { 958 mShouldMakeDynamicModule = dynamicModule; 959 } 960 961 /** {@inheritDoc} */ 962 @Override setInvocationContext(IInvocationContext invocationContext)963 public void setInvocationContext(IInvocationContext invocationContext) { 964 mContext = invocationContext; 965 } 966 967 /** Set the max number of run attempt for each module. */ setMaxRunLimit(int maxRunLimit)968 public final void setMaxRunLimit(int maxRunLimit) { 969 mMaxRunLimit = maxRunLimit; 970 } 971 972 /** {@inheritDoc} */ 973 @Override getRuntimeHint()974 public long getRuntimeHint() { 975 if (mDirectModule != null) { 976 CLog.d( 977 " %s: %s", 978 mDirectModule.getId(), 979 TimeUtil.formatElapsedTime(mDirectModule.getRuntimeHint())); 980 return mDirectModule.getRuntimeHint(); 981 } 982 return 0l; 983 } 984 985 /** {@inheritDoc} */ 986 @Override setConfiguration(IConfiguration configuration)987 public void setConfiguration(IConfiguration configuration) { 988 mMainConfiguration = configuration; 989 } 990 991 /** {@inheritDoc} */ 992 @Override reportNotExecuted(ITestInvocationListener listener)993 public void reportNotExecuted(ITestInvocationListener listener) { 994 reportNotExecuted(listener, IReportNotExecuted.NOT_EXECUTED_FAILURE); 995 } 996 997 /** {@inheritDoc} */ 998 @Override reportNotExecuted(ITestInvocationListener listener, String message)999 public void reportNotExecuted(ITestInvocationListener listener, String message) { 1000 // If the runner is already in progress, report the remaining tests as not executed. 1001 List<ModuleDefinition> runModules = null; 1002 if (mRunModules != null) { 1003 runModules = new ArrayList<>(mRunModules); 1004 } 1005 if (runModules == null) { 1006 runModules = createExecutionList(); 1007 } 1008 1009 while (!runModules.isEmpty()) { 1010 ModuleDefinition module = runModules.remove(0); 1011 module.reportNotExecuted(listener, message); 1012 } 1013 } 1014 addModuleMetadataIncludeFilters(MultiMap<String, String> filters)1015 public void addModuleMetadataIncludeFilters(MultiMap<String, String> filters) { 1016 mModuleMetadataIncludeFilter.putAll(filters); 1017 } 1018 addModuleMetadataExcludeFilters(MultiMap<String, String> filters)1019 public void addModuleMetadataExcludeFilters(MultiMap<String, String> filters) { 1020 mModuleMetadataExcludeFilter.putAll(filters); 1021 } 1022 1023 /** 1024 * Returns the {@link ModuleDefinition} to be executed directly, or null if none yet (when the 1025 * ITestSuite has not been sharded yet). 1026 */ getDirectModule()1027 public ModuleDefinition getDirectModule() { 1028 return mDirectModule; 1029 } 1030 1031 @Override getRequiredTokens()1032 public Set<TokenProperty> getRequiredTokens() { 1033 if (mDirectModule == null) { 1034 return null; 1035 } 1036 return mDirectModule.getRequiredTokens(); 1037 } 1038 1039 /** 1040 * Gets the set of ABIs supported by both Compatibility testing {@link 1041 * AbiUtils#getAbisSupportedByCompatibility()} and the device under test. 1042 * 1043 * @return The set of ABIs to run the tests on 1044 * @throws DeviceNotAvailableException 1045 */ getAbis(ITestDevice device)1046 public Set<IAbi> getAbis(ITestDevice device) throws DeviceNotAvailableException { 1047 Set<IAbi> abis = new LinkedHashSet<>(); 1048 Set<String> archAbis = getAbisForBuildTargetArch(); 1049 // Handle null-device: use abi in common with host and suite build 1050 if (mPrimaryAbiRun) { 1051 if (mAbiName == null) { 1052 // Get the primary from the device and make it the --abi to run. 1053 mAbiName = getPrimaryAbi(device); 1054 } else { 1055 CLog.d( 1056 "Option --%s supersedes the option --%s, using abi: %s", 1057 ABI_OPTION, PRIMARY_ABI_RUN, mAbiName); 1058 } 1059 } 1060 if (mAbiName != null) { 1061 // A particular abi was requested, it still needs to be supported by the build. 1062 if ((!mSkipHostArchCheck && !archAbis.contains(mAbiName)) 1063 || !AbiUtils.isAbiSupportedByCompatibility(mAbiName)) { 1064 throw new IllegalArgumentException( 1065 String.format( 1066 "Your tests suite hasn't been built with " 1067 + "abi '%s' support, this suite currently supports '%s'.", 1068 mAbiName, archAbis)); 1069 } else { 1070 abis.add(new Abi(mAbiName, AbiUtils.getBitness(mAbiName))); 1071 return abis; 1072 } 1073 } else { 1074 // Run on all abi in common between the device and suite builds. 1075 List<String> deviceAbis = getDeviceAbis(device); 1076 if (deviceAbis.isEmpty()) { 1077 throw new IllegalArgumentException( 1078 String.format( 1079 "Couldn't determinate the abi of the device '%s'.", 1080 device.getSerialNumber())); 1081 } 1082 for (String abi : deviceAbis) { 1083 if ((mSkipHostArchCheck || archAbis.contains(abi)) 1084 && AbiUtils.isAbiSupportedByCompatibility(abi)) { 1085 abis.add(new Abi(abi, AbiUtils.getBitness(abi))); 1086 } else { 1087 CLog.d( 1088 "abi '%s' is supported by device but not by this suite build (%s), " 1089 + "tests will not run against it.", 1090 abi, archAbis); 1091 } 1092 } 1093 if (abis.isEmpty()) { 1094 throw new IllegalArgumentException( 1095 String.format( 1096 "None of the abi supported by this tests suite build ('%s') are " 1097 + "supported by the device ('%s').", 1098 archAbis, deviceAbis)); 1099 } 1100 return abis; 1101 } 1102 } 1103 1104 /** Returns the primary abi of the device or host if it's a null device. */ getPrimaryAbi(ITestDevice device)1105 private String getPrimaryAbi(ITestDevice device) throws DeviceNotAvailableException { 1106 if (device.getIDevice() instanceof NullDevice) { 1107 Set<String> hostAbis = getHostAbis(); 1108 return hostAbis.iterator().next(); 1109 } 1110 String property = device.getProperty(PRODUCT_CPU_ABI_KEY); 1111 if (property == null) { 1112 String serial = device.getSerialNumber(); 1113 throw new DeviceNotAvailableException( 1114 String.format( 1115 "Device '%s' was not online to query %s", serial, PRODUCT_CPU_ABI_KEY), 1116 serial); 1117 } 1118 return property.trim(); 1119 } 1120 1121 /** Returns the list of abis supported by the device or host if it's a null device. */ getDeviceAbis(ITestDevice device)1122 private List<String> getDeviceAbis(ITestDevice device) throws DeviceNotAvailableException { 1123 if (device.getIDevice() instanceof NullDevice) { 1124 return new ArrayList<>(getHostAbis()); 1125 } 1126 // Make it an arrayList to be able to modify the content. 1127 return new ArrayList<>(Arrays.asList(AbiFormatter.getSupportedAbis(device, ""))); 1128 } 1129 1130 /** Return the abis supported by the Host build target architecture. Exposed for testing. */ 1131 @VisibleForTesting getAbisForBuildTargetArch()1132 protected Set<String> getAbisForBuildTargetArch() { 1133 // If TestSuiteInfo does not exists, the stub arch will be replaced by all possible abis. 1134 Set<String> abis = new LinkedHashSet<>(); 1135 for (String arch : TestSuiteInfo.getInstance().getTargetArchs()) { 1136 abis.addAll(AbiUtils.getAbisForArch(arch)); 1137 } 1138 return abis; 1139 } 1140 1141 /** Returns the host machine abis. */ 1142 @VisibleForTesting getHostAbis()1143 protected Set<String> getHostAbis() { 1144 return AbiUtils.getHostAbi(); 1145 } 1146 1147 /** Returns the abi requested with the option -a or --abi. */ getRequestedAbi()1148 public final String getRequestedAbi() { 1149 return mAbiName; 1150 } 1151 1152 /** Getter used to validate the proper Guice injection. */ 1153 @VisibleForTesting getInjector()1154 final Injector getInjector() { 1155 return mInjector; 1156 } 1157 1158 /** 1159 * Apply the metadata filter to the config and see if the config should run. 1160 * 1161 * @param config The {@link IConfiguration} being evaluated. 1162 * @param include the metadata include filter 1163 * @param exclude the metadata exclude filter 1164 * @return True if the module should run, false otherwise. 1165 */ 1166 @VisibleForTesting filterByConfigMetadata( IConfiguration config, MultiMap<String, String> include, MultiMap<String, String> exclude)1167 protected boolean filterByConfigMetadata( 1168 IConfiguration config, 1169 MultiMap<String, String> include, 1170 MultiMap<String, String> exclude) { 1171 MultiMap<String, String> metadata = config.getConfigurationDescription().getAllMetaData(); 1172 boolean shouldInclude = false; 1173 for (String key : include.keySet()) { 1174 Set<String> filters = new HashSet<>(include.get(key)); 1175 if (metadata.containsKey(key)) { 1176 filters.retainAll(metadata.get(key)); 1177 if (!filters.isEmpty()) { 1178 // inclusion filter is not empty and there's at least one matching inclusion 1179 // rule so there's no need to match other inclusion rules 1180 shouldInclude = true; 1181 break; 1182 } 1183 } 1184 } 1185 if (!include.isEmpty() && !shouldInclude) { 1186 // if inclusion filter is not empty and we didn't find a match, the module will not be 1187 // included 1188 return false; 1189 } 1190 // Now evaluate exclusion rules, this ordering also means that exclusion rules may override 1191 // inclusion rules: a config already matched for inclusion may still be excluded if matching 1192 // rules exist 1193 for (String key : exclude.keySet()) { 1194 Set<String> filters = new HashSet<>(exclude.get(key)); 1195 if (metadata.containsKey(key)) { 1196 filters.retainAll(metadata.get(key)); 1197 if (!filters.isEmpty()) { 1198 // we found at least one matching exclusion rules, so we are excluding this 1199 // this module 1200 return false; 1201 } 1202 } 1203 } 1204 // we've matched at least one inclusion rule (if there's any) AND we didn't match any of the 1205 // exclusion rules (if there's any) 1206 return true; 1207 } 1208 1209 /** 1210 * Filter out the preparers that were not whitelisted. This is useful for collect-tests-only 1211 * where some preparers are not needed to dry run through the invocation. 1212 * 1213 * @param config the {@link IConfiguration} considered for filtering. 1214 * @param preparerWhiteList the current preparer whitelist. 1215 */ 1216 @VisibleForTesting filterPreparers(IConfiguration config, Set<String> preparerWhiteList)1217 void filterPreparers(IConfiguration config, Set<String> preparerWhiteList) { 1218 // If no filters was provided, skip the filtering. 1219 if (preparerWhiteList.isEmpty()) { 1220 return; 1221 } 1222 for (IDeviceConfiguration deviceConfig : config.getDeviceConfig()) { 1223 List<ITargetPreparer> preparers = new ArrayList<>(deviceConfig.getTargetPreparers()); 1224 for (ITargetPreparer prep : preparers) { 1225 if (!preparerWhiteList.contains(prep.getClass().getName())) { 1226 deviceConfig.getTargetPreparers().remove(prep); 1227 } 1228 } 1229 } 1230 } 1231 1232 /** 1233 * Apply the Runner whitelist filtering, removing any runner that was not whitelisted. If a 1234 * configuration has several runners, some might be removed and the config will still run. 1235 * 1236 * @param config The {@link IConfiguration} being evaluated. 1237 * @param allowedRunners The current runner whitelist. 1238 * @return True if the configuration module is allowed to run, false otherwise. 1239 */ 1240 @VisibleForTesting filterByRunnerType(IConfiguration config, Set<String> allowedRunners)1241 protected boolean filterByRunnerType(IConfiguration config, Set<String> allowedRunners) { 1242 // If no filters are provided, simply run everything. 1243 if (allowedRunners.isEmpty()) { 1244 return true; 1245 } 1246 Iterator<IRemoteTest> iterator = config.getTests().iterator(); 1247 while (iterator.hasNext()) { 1248 IRemoteTest test = iterator.next(); 1249 if (!allowedRunners.contains(test.getClass().getName())) { 1250 CLog.d( 1251 "Runner '%s' in module '%s' was skipped by the runner whitelist: '%s'.", 1252 test.getClass().getName(), config.getName(), allowedRunners); 1253 iterator.remove(); 1254 } 1255 } 1256 1257 if (config.getTests().isEmpty()) { 1258 CLog.d("Module %s does not have any more tests, skipping it.", config.getName()); 1259 return false; 1260 } 1261 return true; 1262 } 1263 } 1264