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