1 /* 2 * Copyright (C) 2010 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 17 package com.android.tradefed.testtype; 18 19 import com.android.tradefed.config.ConfigurationException; 20 import com.android.tradefed.config.OptionCopier; 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 import com.android.tradefed.log.LogUtil.CLog; 23 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 24 import com.android.tradefed.result.CollectingTestListener; 25 import com.android.tradefed.result.ITestInvocationListener; 26 import com.android.tradefed.result.ResultForwarder; 27 import com.android.tradefed.result.TestDescription; 28 import com.android.tradefed.result.TestRunResult; 29 30 import java.util.Collection; 31 import java.util.HashMap; 32 33 /** 34 * A Test that runs a set of instrumentation tests by running one adb command for per test. 35 */ 36 class InstrumentationSerialTest implements IRemoteTest { 37 38 /** number of attempts to make if test fails to run */ 39 static final int FAILED_RUN_TEST_ATTEMPTS = 2; 40 41 /** the set of tests to run */ 42 private final Collection<TestDescription> mTests; 43 44 private final InstrumentationTest mInstrumentationTest; 45 46 /** 47 * Creates a {@link InstrumentationSerialTest}. 48 * 49 * @param instrumentationTest {@link InstrumentationTest} used to configure this class 50 * @param testsToRun a {@link Collection} of tests to run. Note this {@link Collection} will be 51 * used as is (ie a reference to the testsToRun object will be kept). 52 */ InstrumentationSerialTest( InstrumentationTest instrumentationTest, Collection<TestDescription> testsToRun)53 InstrumentationSerialTest( 54 InstrumentationTest instrumentationTest, Collection<TestDescription> testsToRun) 55 throws ConfigurationException { 56 // reuse the InstrumentationTest class to perform actual test run 57 mInstrumentationTest = createInstrumentationTest(instrumentationTest); 58 // keep local copy of tests to be run 59 mTests = testsToRun; 60 } 61 62 /** 63 * Create and initialize new instance of {@link InstrumentationTest}. Exposed for unit testing. 64 * 65 * @param instrumentationTest {@link InstrumentationTest} used to configure this class 66 * @return the newly created {@link InstrumentationTest} 67 */ createInstrumentationTest(InstrumentationTest instrumentationTest)68 InstrumentationTest createInstrumentationTest(InstrumentationTest instrumentationTest) 69 throws ConfigurationException { 70 InstrumentationTest runner = new InstrumentationTest(); 71 OptionCopier.copyOptions(instrumentationTest, runner); 72 runner.setDevice(instrumentationTest.getDevice()); 73 runner.setForceAbi(instrumentationTest.getForceAbi()); 74 // ensure testFile is not used. 75 runner.setReRunUsingTestFile(false); 76 // no need to rerun when executing tests one by one 77 runner.setRerunMode(false); 78 return runner; 79 } 80 81 /** 82 * {@inheritDoc} 83 */ 84 @Override run(final ITestInvocationListener listener)85 public void run(final ITestInvocationListener listener) throws DeviceNotAvailableException { 86 if (mInstrumentationTest.getDevice() == null) { 87 throw new IllegalArgumentException("Device has not been set"); 88 } 89 // reuse the InstrumentationTest class to perform actual test run 90 try { 91 for (TestDescription testToRun : mTests) { 92 InstrumentationTest runner = createInstrumentationTest(mInstrumentationTest); 93 runner.setClassName(testToRun.getClassName()); 94 runner.setMethodName(testToRun.getTestName()); 95 runTest(runner, listener, testToRun); 96 } 97 } catch (ConfigurationException e) { 98 CLog.e("Failed to create new InstrumentationTest: %s", e.getMessage()); 99 } 100 } 101 runTest( InstrumentationTest runner, ITestInvocationListener listener, TestDescription testToRun)102 private void runTest( 103 InstrumentationTest runner, ITestInvocationListener listener, TestDescription testToRun) 104 throws DeviceNotAvailableException { 105 // use a listener filter, to track if the test failed to run 106 CollectingTestListener trackingListener = new CollectingTestListener(); 107 for (int i=1; i <= FAILED_RUN_TEST_ATTEMPTS; i++) { 108 runner.run(new ResultForwarder(trackingListener, listener)); 109 if (trackingListener.getCurrentRunResults().getTestResults().containsKey(testToRun)) { 110 return; 111 } 112 CLog.w( 113 "Expected test %s did not run on attempt %d of %d", 114 testToRun, i, FAILED_RUN_TEST_ATTEMPTS); 115 } 116 markTestAsFailed(testToRun, trackingListener.getCurrentRunResults(), listener); 117 } 118 markTestAsFailed( TestDescription test, TestRunResult testRun, ITestInvocationListener listener)119 private void markTestAsFailed( 120 TestDescription test, TestRunResult testRun, ITestInvocationListener listener) { 121 listener.testRunStarted(testRun.getName(), 1); 122 listener.testStarted(test); 123 124 String message = 125 testRun.isRunFailure() 126 ? testRun.getRunFailureMessage() 127 : "The test was not initialized by the test runner."; 128 listener.testFailed( 129 test, String.format("Test failed to run. Test run failed due to : %s", message)); 130 131 if (testRun.isRunFailure()) { 132 listener.testRunFailed(message); 133 } 134 listener.testEnded(test, new HashMap<String, Metric>()); 135 listener.testRunEnded(0, new HashMap<String, Metric>()); 136 } 137 } 138