Home | History | Annotate | Download | only in suite
      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      */
    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      */
    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      */
    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. */
    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      */
    194     protected boolean hasTests() {
    195         synchronized (mTests) {
    196             return mTests.isEmpty();
    197         }
    198     }
    199 
    200     /** Return the unique module name. */
    201     public String getId() {
    202         return mId;
    203     }
    204 
    205     /**
    206      * {@inheritDoc}
    207      */
    208     @Override
    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      */
    216     public void setBuild(IBuildInfo build) {
    217         mBuild = build;
    218     }
    219 
    220     /**
    221      * Inject the {@link ITestDevice} to be used during the tests.
    222      */
    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      */
    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. */
    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. */
    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      */
    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      */
    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      */
    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
    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 
    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. */
    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. */
    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 
    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. */
    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. */
    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. */
    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. */
    661     private long getCurrentTime() {
    662         return System.currentTimeMillis();
    663     }
    664 
    665     @Override
    666     public void setCollectTestsOnly(boolean collectTestsOnly) {
    667         mCollectTestsOnly = collectTestsOnly;
    668     }
    669 
    670     /** Returns a list of tests that ran in this module. */
    671     List<TestRunResult> getTestsResults() {
    672         return mTestsResults;
    673     }
    674 
    675     /** Returns the number of tests that was expected to be run */
    676     int getNumExpectedTests() {
    677         return mExpectedTests;
    678     }
    679 
    680     /** Returns True if a testRunFailure has been called on the module * */
    681     public boolean hasModuleFailed() {
    682         return mIsFailedModule;
    683     }
    684 
    685     /** {@inheritDoc} */
    686     @Override
    687     public String toString() {
    688         return getId();
    689     }
    690 
    691     /** Returns the approximate time to run all the tests in the module. */
    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
    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
    712     List<ITargetPreparer> getTargetPreparerForDevice(String deviceName) {
    713         return mPreparersPerDevice.get(deviceName);
    714     }
    715 
    716     /** Returns the {@link IInvocationContext} associated with the module. */
    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      */
    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