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.ddmlib.Log.LogLevel; 19 import com.android.tradefed.build.IBuildInfo; 20 import com.android.tradefed.config.ConfigurationDescriptor; 21 import com.android.tradefed.config.IConfiguration; 22 import com.android.tradefed.device.DeviceNotAvailableException; 23 import com.android.tradefed.device.ITestDevice; 24 import com.android.tradefed.device.StubDevice; 25 import com.android.tradefed.device.metric.IMetricCollector; 26 import com.android.tradefed.invoker.IInvocationContext; 27 import com.android.tradefed.invoker.InvocationContext; 28 import com.android.tradefed.log.ILogRegistry.EventType; 29 import com.android.tradefed.log.ITestLogger; 30 import com.android.tradefed.log.LogRegistry; 31 import com.android.tradefed.log.LogUtil.CLog; 32 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 33 import com.android.tradefed.result.ILogSaver; 34 import com.android.tradefed.result.ILogSaverListener; 35 import com.android.tradefed.result.ITestInvocationListener; 36 import com.android.tradefed.result.ITestLoggerReceiver; 37 import com.android.tradefed.result.LogFile; 38 import com.android.tradefed.result.TestDescription; 39 import com.android.tradefed.result.TestResult; 40 import com.android.tradefed.result.TestRunResult; 41 import com.android.tradefed.suite.checker.ISystemStatusCheckerReceiver; 42 import com.android.tradefed.targetprep.BuildError; 43 import com.android.tradefed.targetprep.ITargetCleaner; 44 import com.android.tradefed.targetprep.ITargetPreparer; 45 import com.android.tradefed.targetprep.TargetSetupError; 46 import com.android.tradefed.targetprep.multi.IMultiTargetPreparer; 47 import com.android.tradefed.testtype.IBuildReceiver; 48 import com.android.tradefed.testtype.IDeviceTest; 49 import com.android.tradefed.testtype.IInvocationContextReceiver; 50 import com.android.tradefed.testtype.IMultiDeviceTest; 51 import com.android.tradefed.testtype.IRemoteTest; 52 import com.android.tradefed.testtype.IRuntimeHintProvider; 53 import com.android.tradefed.testtype.ITestCollector; 54 import com.android.tradefed.testtype.suite.module.BaseModuleController; 55 import com.android.tradefed.testtype.suite.module.IModuleController.RunStrategy; 56 import com.android.tradefed.util.StreamUtil; 57 import com.android.tradefed.util.proto.TfMetricProtoUtil; 58 59 import com.google.common.annotations.VisibleForTesting; 60 61 import java.io.PrintWriter; 62 import java.io.StringWriter; 63 import java.util.ArrayList; 64 import java.util.Collection; 65 import java.util.Collections; 66 import java.util.HashMap; 67 import java.util.LinkedHashMap; 68 import java.util.List; 69 import java.util.ListIterator; 70 import java.util.Map; 71 import java.util.Map.Entry; 72 73 /** 74 * Container for the test run configuration. This class is an helper to prepare and run the tests. 75 */ 76 public class ModuleDefinition implements Comparable<ModuleDefinition>, ITestCollector { 77 78 /** key names used for saving module info into {@link IInvocationContext} */ 79 /** 80 * Module name is the base name associated with the module, usually coming from the Xml TF 81 * config file the module was loaded from. 82 */ 83 public static final String MODULE_NAME = "module-name"; 84 public static final String MODULE_ABI = "module-abi"; 85 /** 86 * Module ID the name that will be used to identify uniquely the module during testRunStart. It 87 * will usually be a combination of MODULE_ABI + MODULE_NAME. 88 */ 89 public static final String MODULE_ID = "module-id"; 90 91 public static final String MODULE_CONTROLLER = "module_controller"; 92 93 private final IInvocationContext mModuleInvocationContext; 94 private final IConfiguration mModuleConfiguration; 95 private ILogSaver mLogSaver; 96 97 private final String mId; 98 private Collection<IRemoteTest> mTests = null; 99 private Map<String, List<ITargetPreparer>> mPreparersPerDevice = null; 100 101 private List<IMultiTargetPreparer> mMultiPreparers = new ArrayList<>(); 102 private IBuildInfo mBuild; 103 private ITestDevice mDevice; 104 private Map<ITestDevice, IBuildInfo> mDeviceInfos; 105 private List<IMetricCollector> mRunMetricCollectors; 106 private boolean mCollectTestsOnly = false; 107 108 private List<TestRunResult> mTestsResults = new ArrayList<>(); 109 private int mExpectedTests = 0; 110 private boolean mIsFailedModule = false; 111 112 // Tracking of preparers performance 113 private long mElapsedPreparation = 0l; 114 private long mElapsedTearDown = 0l; 115 116 private long mElapsedTest = 0l; 117 118 public static final String PREPARATION_TIME = "PREP_TIME"; 119 public static final String TEAR_DOWN_TIME = "TEARDOWN_TIME"; 120 public static final String TEST_TIME = "TEST_TIME"; 121 122 /** 123 * Constructor 124 * 125 * @param name unique name of the test configuration. 126 * @param tests list of {@link IRemoteTest} that needs to run. 127 * @param preparersPerDevice list of {@link ITargetPreparer} to be used to setup the device. 128 * @param moduleConfig the {@link IConfiguration} of the underlying module config. 129 */ ModuleDefinition( String name, Collection<IRemoteTest> tests, Map<String, List<ITargetPreparer>> preparersPerDevice, List<IMultiTargetPreparer> multiPreparers, IConfiguration moduleConfig)130 public ModuleDefinition( 131 String name, 132 Collection<IRemoteTest> tests, 133 Map<String, List<ITargetPreparer>> preparersPerDevice, 134 List<IMultiTargetPreparer> multiPreparers, 135 IConfiguration moduleConfig) { 136 mId = name; 137 mTests = tests; 138 mModuleConfiguration = moduleConfig; 139 ConfigurationDescriptor configDescriptor = moduleConfig.getConfigurationDescription(); 140 mModuleInvocationContext = new InvocationContext(); 141 mModuleInvocationContext.setConfigurationDescriptor(configDescriptor); 142 143 // If available in the suite, add the abi name 144 if (configDescriptor.getAbi() != null) { 145 mModuleInvocationContext.addInvocationAttribute( 146 MODULE_ABI, configDescriptor.getAbi().getName()); 147 } 148 if (configDescriptor.getModuleName() != null) { 149 mModuleInvocationContext.addInvocationAttribute( 150 MODULE_NAME, configDescriptor.getModuleName()); 151 } 152 // If there is no specific abi, module-id should be module-name 153 mModuleInvocationContext.addInvocationAttribute(MODULE_ID, mId); 154 155 mMultiPreparers.addAll(multiPreparers); 156 mPreparersPerDevice = preparersPerDevice; 157 } 158 159 /** 160 * Returns the next {@link IRemoteTest} from the list of tests. The list of tests of a module 161 * may be shared with another one in case of sharding. 162 */ poll()163 IRemoteTest poll() { 164 synchronized (mTests) { 165 if (mTests.isEmpty()) { 166 return null; 167 } 168 IRemoteTest test = mTests.iterator().next(); 169 mTests.remove(test); 170 return test; 171 } 172 } 173 174 /** 175 * Add some {@link IRemoteTest} to be executed as part of the module. Used when merging two 176 * modules. 177 */ addTests(List<IRemoteTest> test)178 void addTests(List<IRemoteTest> test) { 179 synchronized (mTests) { 180 mTests.addAll(test); 181 } 182 } 183 184 /** Returns the current number of {@link IRemoteTest} waiting to be executed. */ numTests()185 public int numTests() { 186 synchronized (mTests) { 187 return mTests.size(); 188 } 189 } 190 191 /** 192 * Return True if the Module still has {@link IRemoteTest} to run in its pool. False otherwise. 193 */ hasTests()194 protected boolean hasTests() { 195 synchronized (mTests) { 196 return mTests.isEmpty(); 197 } 198 } 199 200 /** Return the unique module name. */ getId()201 public String getId() { 202 return mId; 203 } 204 205 /** 206 * {@inheritDoc} 207 */ 208 @Override compareTo(ModuleDefinition moduleDef)209 public int compareTo(ModuleDefinition moduleDef) { 210 return getId().compareTo(moduleDef.getId()); 211 } 212 213 /** 214 * Inject the {@link IBuildInfo} to be used during the tests. 215 */ setBuild(IBuildInfo build)216 public void setBuild(IBuildInfo build) { 217 mBuild = build; 218 } 219 220 /** 221 * Inject the {@link ITestDevice} to be used during the tests. 222 */ setDevice(ITestDevice device)223 public void setDevice(ITestDevice device) { 224 mDevice = device; 225 } 226 227 /** 228 * Inject the {@link Map} of {@link ITestDevice} and {@link IBuildInfo} for the configuration. 229 */ setDeviceInfos(Map<ITestDevice, IBuildInfo> deviceInfos)230 public void setDeviceInfos(Map<ITestDevice, IBuildInfo> deviceInfos) { 231 mDeviceInfos = deviceInfos; 232 } 233 234 /** Inject the List of {@link IMetricCollector} to be used by the module. */ setMetricCollectors(List<IMetricCollector> collectors)235 public void setMetricCollectors(List<IMetricCollector> collectors) { 236 mRunMetricCollectors = collectors; 237 } 238 239 /** Pass the invocation log saver to the module so it can use it if necessary. */ setLogSaver(ILogSaver logSaver)240 public void setLogSaver(ILogSaver logSaver) { 241 mLogSaver = logSaver; 242 } 243 244 /** 245 * Run all the {@link IRemoteTest} contained in the module and use all the preparers before and 246 * after to setup and clean the device. 247 * 248 * @param listener the {@link ITestInvocationListener} where to report results. 249 * @throws DeviceNotAvailableException in case of device going offline. 250 */ run(ITestInvocationListener listener)251 public final void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 252 run(listener, null, null); 253 } 254 255 /** 256 * Run all the {@link IRemoteTest} contained in the module and use all the preparers before and 257 * after to setup and clean the device. 258 * 259 * @param listener the {@link ITestInvocationListener} where to report results. 260 * @param moduleLevelListeners The list of listeners at the module level. 261 * @param failureListener a particular listener to collect logs on testFail. Can be null. 262 * @throws DeviceNotAvailableException in case of device going offline. 263 */ run( ITestInvocationListener listener, List<ITestInvocationListener> moduleLevelListeners, TestFailureListener failureListener)264 public final void run( 265 ITestInvocationListener listener, 266 List<ITestInvocationListener> moduleLevelListeners, 267 TestFailureListener failureListener) 268 throws DeviceNotAvailableException { 269 run(listener, moduleLevelListeners, failureListener, 1); 270 } 271 272 /** 273 * Run all the {@link IRemoteTest} contained in the module and use all the preparers before and 274 * after to setup and clean the device. 275 * 276 * @param listener the {@link ITestInvocationListener} where to report results. 277 * @param moduleLevelListeners The list of listeners at the module level. 278 * @param failureListener a particular listener to collect logs on testFail. Can be null. 279 * @param maxRunLimit the max number of runs for each testcase. 280 * @throws DeviceNotAvailableException in case of device going offline. 281 */ run( ITestInvocationListener listener, List<ITestInvocationListener> moduleLevelListeners, TestFailureListener failureListener, int maxRunLimit)282 public final void run( 283 ITestInvocationListener listener, 284 List<ITestInvocationListener> moduleLevelListeners, 285 TestFailureListener failureListener, 286 int maxRunLimit) 287 throws DeviceNotAvailableException { 288 // Load extra configuration for the module from module_controller 289 // TODO: make module_controller a full TF object 290 boolean skipTestCases = false; 291 RunStrategy rs = applyConfigurationControl(failureListener); 292 if (RunStrategy.FULL_MODULE_BYPASS.equals(rs)) { 293 CLog.d("module_controller applied and module %s should not run.", getId()); 294 return; 295 } else if (RunStrategy.SKIP_MODULE_TESTCASES.equals(rs)) { 296 CLog.d("All tests cases for %s will be marked skipped.", getId()); 297 skipTestCases = true; 298 } 299 300 CLog.d("Running module %s", getId()); 301 Exception preparationException = null; 302 // Setup 303 long prepStartTime = getCurrentTime(); 304 305 for (String deviceName : mModuleInvocationContext.getDeviceConfigNames()) { 306 ITestDevice device = mModuleInvocationContext.getDevice(deviceName); 307 for (ITargetPreparer preparer : mPreparersPerDevice.get(deviceName)) { 308 preparationException = 309 runPreparerSetup( 310 device, 311 mModuleInvocationContext.getBuildInfo(deviceName), 312 preparer, 313 listener); 314 if (preparationException != null) { 315 mIsFailedModule = true; 316 CLog.e("Some preparation step failed. failing the module %s", getId()); 317 break; 318 } 319 } 320 if (preparationException != null) { 321 // If one device errored out, we skip the remaining devices. 322 break; 323 } 324 } 325 326 // Skip multi-preparation if preparation already failed. 327 if (preparationException == null) { 328 for (IMultiTargetPreparer multiPreparer : mMultiPreparers) { 329 preparationException = runMultiPreparerSetup(multiPreparer, listener); 330 if (preparationException != null) { 331 mIsFailedModule = true; 332 CLog.e("Some preparation step failed. failing the module %s", getId()); 333 break; 334 } 335 } 336 } 337 mElapsedPreparation = getCurrentTime() - prepStartTime; 338 // Run the tests 339 try { 340 if (preparationException != null) { 341 // For reporting purpose we create a failure placeholder with the error stack 342 // similar to InitializationError of JUnit. 343 listener.testRunStarted(getId(), 1); 344 StringWriter sw = new StringWriter(); 345 preparationException.printStackTrace(new PrintWriter(sw)); 346 listener.testRunFailed(sw.toString()); 347 HashMap<String, Metric> metricsProto = new HashMap<>(); 348 metricsProto.put( 349 TEST_TIME, TfMetricProtoUtil.createSingleValue(0L, "milliseconds")); 350 listener.testRunEnded(0, metricsProto); 351 return; 352 } 353 mElapsedTest = getCurrentTime(); 354 while (true) { 355 IRemoteTest test = poll(); 356 if (test == null) { 357 return; 358 } 359 360 if (test instanceof IBuildReceiver) { 361 ((IBuildReceiver) test).setBuild(mBuild); 362 } 363 if (test instanceof IDeviceTest) { 364 ((IDeviceTest) test).setDevice(mDevice); 365 } 366 if (test instanceof IMultiDeviceTest) { 367 ((IMultiDeviceTest) test).setDeviceInfos(mDeviceInfos); 368 } 369 if (test instanceof IInvocationContextReceiver) { 370 ((IInvocationContextReceiver) test) 371 .setInvocationContext(mModuleInvocationContext); 372 } 373 if (test instanceof ISystemStatusCheckerReceiver) { 374 // We do not pass down Status checker because they are already running at the 375 // top level suite. 376 ((ISystemStatusCheckerReceiver) test).setSystemStatusChecker(new ArrayList<>()); 377 } 378 if (test instanceof ITestCollector) { 379 if (skipTestCases) { 380 mCollectTestsOnly = true; 381 } 382 ((ITestCollector) test).setCollectTestsOnly(mCollectTestsOnly); 383 } 384 385 GranularRetriableTestWrapper retriableTest = 386 prepareGranularRetriableWrapper( 387 test, 388 failureListener, 389 moduleLevelListeners, 390 skipTestCases, 391 maxRunLimit); 392 try { 393 retriableTest.run(listener); 394 } catch (DeviceNotAvailableException dnae) { 395 // We do special logging of some information in Context of the module for easier 396 // debugging. 397 CLog.e( 398 "Module %s threw a DeviceNotAvailableException on device %s during " 399 + "test %s", 400 getId(), mDevice.getSerialNumber(), test.getClass()); 401 CLog.e(dnae); 402 // log an events 403 logDeviceEvent( 404 EventType.MODULE_DEVICE_NOT_AVAILABLE, 405 mDevice.getSerialNumber(), 406 dnae, 407 getId()); 408 throw dnae; 409 } finally { 410 TestRunResult finalResult = retriableTest.getFinalTestRunResult(); 411 if (finalResult != null) { 412 mTestsResults.add(finalResult); 413 } 414 mExpectedTests += retriableTest.getNumIndividualTests(); 415 } 416 // After the run, if the test failed (even after retry the final result passed) has 417 // failed, capture a bugreport. 418 if (retriableTest.hasFailed()) { 419 captureBugreport(listener, getId()); 420 } 421 } 422 } finally { 423 long cleanStartTime = getCurrentTime(); 424 try { 425 // Tear down 426 runTearDown(); 427 } catch (DeviceNotAvailableException tearDownException) { 428 CLog.e( 429 "Module %s failed during tearDown with: %s", 430 getId(), StreamUtil.getStackTrace(tearDownException)); 431 throw tearDownException; 432 } finally { 433 if (failureListener != null) { 434 failureListener.join(); 435 } 436 mElapsedTearDown = getCurrentTime() - cleanStartTime; 437 // finalize results 438 if (preparationException == null) { 439 reportFinalResults(listener, mExpectedTests, mTestsResults); 440 } 441 } 442 } 443 } 444 445 /** 446 * Create a wrapper class for the {@link IRemoteTest} which has built-in logic to schedule 447 * multiple test runs for the same module, and have the ability to run testcases in a more 448 * granulated level (a subset of testcases in the module). 449 * 450 * @param test the {@link IRemoteTest} that is being wrapped. 451 * @param failureListener a particular listener to collect logs on testFail. Can be null. 452 * @param skipTestCases A run strategy when SKIP_MODULE_TESTCASES is defined. 453 * @param maxRunLimit a rate-limiter on testcases retrying times. 454 */ 455 @VisibleForTesting prepareGranularRetriableWrapper( IRemoteTest test, TestFailureListener failureListener, List<ITestInvocationListener> moduleLevelListeners, boolean skipTestCases, int maxRunLimit)456 GranularRetriableTestWrapper prepareGranularRetriableWrapper( 457 IRemoteTest test, 458 TestFailureListener failureListener, 459 List<ITestInvocationListener> moduleLevelListeners, 460 boolean skipTestCases, 461 int maxRunLimit) { 462 GranularRetriableTestWrapper retriableTest = 463 new GranularRetriableTestWrapper( 464 test, failureListener, moduleLevelListeners, maxRunLimit); 465 retriableTest.setModuleId(getId()); 466 retriableTest.setMarkTestsSkipped(skipTestCases); 467 retriableTest.setMetricCollectors(mRunMetricCollectors); 468 retriableTest.setModuleConfig(mModuleConfiguration); 469 retriableTest.setInvocationContext(mModuleInvocationContext); 470 retriableTest.setLogSaver(mLogSaver); 471 return retriableTest; 472 } 473 captureBugreport(ITestLogger listener, String moduleId)474 private void captureBugreport(ITestLogger listener, String moduleId) { 475 for (ITestDevice device : mModuleInvocationContext.getDevices()) { 476 if (device.getIDevice() instanceof StubDevice) { 477 continue; 478 } 479 device.logBugreport( 480 String.format( 481 "module-%s-failure-%s-bugreport", moduleId, device.getSerialNumber()), 482 listener); 483 } 484 } 485 486 /** Helper to log the device events. */ logDeviceEvent(EventType event, String serial, Throwable t, String moduleId)487 private void logDeviceEvent(EventType event, String serial, Throwable t, String moduleId) { 488 Map<String, String> args = new HashMap<>(); 489 args.put("serial", serial); 490 args.put("trace", StreamUtil.getStackTrace(t)); 491 args.put("module-id", moduleId); 492 LogRegistry.getLogRegistry().logEvent(LogLevel.DEBUG, event, args); 493 } 494 495 /** Finalize results to report them all and count if there are missing tests. */ reportFinalResults( ITestInvocationListener listener, int totalExpectedTests, List<TestRunResult> listResults)496 private void reportFinalResults( 497 ITestInvocationListener listener, 498 int totalExpectedTests, 499 List<TestRunResult> listResults) { 500 long elapsedTime = 0l; 501 HashMap<String, Metric> metricsProto = new HashMap<>(); 502 listener.testRunStarted(getId(), totalExpectedTests); 503 int numResults = 0; 504 Map<String, LogFile> aggLogFiles = new LinkedHashMap<>(); 505 for (TestRunResult runResult : listResults) { 506 numResults += runResult.getTestResults().size(); 507 forwardTestResults(runResult.getTestResults(), listener); 508 if (runResult.isRunFailure()) { 509 listener.testRunFailed(runResult.getRunFailureMessage()); 510 mIsFailedModule = true; 511 } 512 elapsedTime += runResult.getElapsedTime(); 513 // put metrics from the tests 514 metricsProto.putAll(runResult.getRunProtoMetrics()); 515 aggLogFiles.putAll(runResult.getRunLoggedFiles()); 516 } 517 // put metrics from the preparation 518 metricsProto.put( 519 PREPARATION_TIME, 520 TfMetricProtoUtil.createSingleValue(mElapsedPreparation, "milliseconds")); 521 metricsProto.put( 522 TEAR_DOWN_TIME, 523 TfMetricProtoUtil.createSingleValue(mElapsedTearDown, "milliseconds")); 524 metricsProto.put( 525 TEST_TIME, TfMetricProtoUtil.createSingleValue(elapsedTime, "milliseconds")); 526 if (totalExpectedTests != numResults) { 527 String error = 528 String.format( 529 "Module %s only ran %d out of %d expected tests.", 530 getId(), numResults, totalExpectedTests); 531 listener.testRunFailed(error); 532 CLog.e(error); 533 mIsFailedModule = true; 534 } 535 536 // Provide a strong association of the run to its logs. 537 for (Entry<String, LogFile> logFile : aggLogFiles.entrySet()) { 538 if (listener instanceof ILogSaverListener) { 539 ((ILogSaverListener) listener).logAssociation(logFile.getKey(), logFile.getValue()); 540 } 541 } 542 listener.testRunEnded(getCurrentTime() - mElapsedTest, metricsProto); 543 } 544 forwardTestResults( Map<TestDescription, TestResult> testResults, ITestInvocationListener listener)545 private void forwardTestResults( 546 Map<TestDescription, TestResult> testResults, ITestInvocationListener listener) { 547 for (Map.Entry<TestDescription, TestResult> testEntry : testResults.entrySet()) { 548 listener.testStarted(testEntry.getKey(), testEntry.getValue().getStartTime()); 549 switch (testEntry.getValue().getStatus()) { 550 case FAILURE: 551 listener.testFailed(testEntry.getKey(), testEntry.getValue().getStackTrace()); 552 break; 553 case ASSUMPTION_FAILURE: 554 listener.testAssumptionFailure( 555 testEntry.getKey(), testEntry.getValue().getStackTrace()); 556 break; 557 case IGNORED: 558 listener.testIgnored(testEntry.getKey()); 559 break; 560 case INCOMPLETE: 561 listener.testFailed( 562 testEntry.getKey(), "Test did not complete due to exception."); 563 break; 564 default: 565 break; 566 } 567 // Provide a strong association of the test to its logs. 568 for (Entry<String, LogFile> logFile : 569 testEntry.getValue().getLoggedFiles().entrySet()) { 570 if (listener instanceof ILogSaverListener) { 571 ((ILogSaverListener) listener) 572 .logAssociation(logFile.getKey(), logFile.getValue()); 573 } 574 } 575 listener.testEnded( 576 testEntry.getKey(), 577 testEntry.getValue().getEndTime(), 578 testEntry.getValue().getProtoMetrics()); 579 } 580 } 581 582 /** Run all the prepare steps. */ runPreparerSetup( ITestDevice device, IBuildInfo build, ITargetPreparer preparer, ITestLogger logger)583 private Exception runPreparerSetup( 584 ITestDevice device, IBuildInfo build, ITargetPreparer preparer, ITestLogger logger) 585 throws DeviceNotAvailableException { 586 if (preparer.isDisabled()) { 587 // If disabled skip completely. 588 return null; 589 } 590 CLog.d("Preparer: %s", preparer.getClass().getSimpleName()); 591 try { 592 // set the logger in case they need it. 593 if (preparer instanceof ITestLoggerReceiver) { 594 ((ITestLoggerReceiver) preparer).setTestLogger(logger); 595 } 596 preparer.setUp(device, build); 597 return null; 598 } catch (BuildError | TargetSetupError e) { 599 CLog.e("Unexpected Exception from preparer: %s", preparer.getClass().getName()); 600 CLog.e(e); 601 return e; 602 } 603 } 604 605 /** Run all multi target preparer step. */ runMultiPreparerSetup(IMultiTargetPreparer preparer, ITestLogger logger)606 private Exception runMultiPreparerSetup(IMultiTargetPreparer preparer, ITestLogger logger) { 607 if (preparer.isDisabled()) { 608 // If disabled skip completely. 609 return null; 610 } 611 CLog.d("Multi preparer: %s", preparer.getClass().getSimpleName()); 612 try { 613 // set the logger in case they need it. 614 if (preparer instanceof ITestLoggerReceiver) { 615 ((ITestLoggerReceiver) preparer).setTestLogger(logger); 616 } 617 preparer.setUp(mModuleInvocationContext); 618 return null; 619 } catch (BuildError | TargetSetupError | DeviceNotAvailableException e) { 620 CLog.e("Unexpected Exception from preparer: %s", preparer.getClass().getName()); 621 CLog.e(e); 622 return e; 623 } 624 } 625 626 /** Run all the tear down steps from preparers. */ runTearDown()627 private void runTearDown() throws DeviceNotAvailableException { 628 // Tear down 629 List<IMultiTargetPreparer> cleanerList = new ArrayList<>(mMultiPreparers); 630 Collections.reverse(cleanerList); 631 for (IMultiTargetPreparer multiCleaner : cleanerList) { 632 if (multiCleaner.isDisabled() || multiCleaner.isTearDownDisabled()) { 633 // If disabled skip completely. 634 continue; 635 } 636 CLog.d("Multi cleaner: %s", multiCleaner.getClass().getSimpleName()); 637 multiCleaner.tearDown(mModuleInvocationContext, null); 638 } 639 640 for (String deviceName : mModuleInvocationContext.getDeviceConfigNames()) { 641 ITestDevice device = mModuleInvocationContext.getDevice(deviceName); 642 List<ITargetPreparer> preparers = mPreparersPerDevice.get(deviceName); 643 ListIterator<ITargetPreparer> itr = preparers.listIterator(preparers.size()); 644 while (itr.hasPrevious()) { 645 ITargetPreparer preparer = itr.previous(); 646 if (preparer instanceof ITargetCleaner) { 647 ITargetCleaner cleaner = (ITargetCleaner) preparer; 648 // do not call the cleaner if it was disabled 649 if (cleaner.isDisabled() || cleaner.isTearDownDisabled()) { 650 CLog.d("%s has been disabled. skipping.", cleaner); 651 continue; 652 } 653 cleaner.tearDown( 654 device, mModuleInvocationContext.getBuildInfo(deviceName), null); 655 } 656 } 657 } 658 } 659 660 /** Returns the current time. */ getCurrentTime()661 private long getCurrentTime() { 662 return System.currentTimeMillis(); 663 } 664 665 @Override setCollectTestsOnly(boolean collectTestsOnly)666 public void setCollectTestsOnly(boolean collectTestsOnly) { 667 mCollectTestsOnly = collectTestsOnly; 668 } 669 670 /** Returns a list of tests that ran in this module. */ getTestsResults()671 List<TestRunResult> getTestsResults() { 672 return mTestsResults; 673 } 674 675 /** Returns the number of tests that was expected to be run */ getNumExpectedTests()676 int getNumExpectedTests() { 677 return mExpectedTests; 678 } 679 680 /** Returns True if a testRunFailure has been called on the module * */ hasModuleFailed()681 public boolean hasModuleFailed() { 682 return mIsFailedModule; 683 } 684 685 /** {@inheritDoc} */ 686 @Override toString()687 public String toString() { 688 return getId(); 689 } 690 691 /** Returns the approximate time to run all the tests in the module. */ getRuntimeHint()692 public long getRuntimeHint() { 693 long hint = 0l; 694 for (IRemoteTest test : mTests) { 695 if (test instanceof IRuntimeHintProvider) { 696 hint += ((IRuntimeHintProvider) test).getRuntimeHint(); 697 } else { 698 hint += 60000; 699 } 700 } 701 return hint; 702 } 703 704 /** Returns the list of {@link IRemoteTest} defined for this module. */ 705 @VisibleForTesting getTests()706 List<IRemoteTest> getTests() { 707 return new ArrayList<>(mTests); 708 } 709 710 /** Returns the list of {@link ITargetPreparer} associated with the given device name */ 711 @VisibleForTesting getTargetPreparerForDevice(String deviceName)712 List<ITargetPreparer> getTargetPreparerForDevice(String deviceName) { 713 return mPreparersPerDevice.get(deviceName); 714 } 715 716 /** Returns the {@link IInvocationContext} associated with the module. */ getModuleInvocationContext()717 public IInvocationContext getModuleInvocationContext() { 718 return mModuleInvocationContext; 719 } 720 721 /** 722 * Allow to load a module_controller object to tune how should a particular module run. 723 * 724 * @param failureListener The {@link TestFailureListener} taking actions on tests failures. 725 * @return The strategy to use to run the tests. 726 */ applyConfigurationControl(TestFailureListener failureListener)727 private RunStrategy applyConfigurationControl(TestFailureListener failureListener) { 728 Object ctrlObject = mModuleConfiguration.getConfigurationObject(MODULE_CONTROLLER); 729 if (ctrlObject != null && ctrlObject instanceof BaseModuleController) { 730 BaseModuleController controller = (BaseModuleController) ctrlObject; 731 // module_controller can also control the log collection for the one module 732 if (failureListener != null) { 733 failureListener.applyModuleConfiguration( 734 controller.shouldCaptureBugreport(), 735 controller.shouldCaptureLogcat(), 736 controller.shouldCaptureScreenshot()); 737 } 738 return controller.shouldRunModule(mModuleInvocationContext); 739 } 740 return RunStrategy.RUN; 741 } 742 } 743