2 * Copyright (C) 2009 The Android Open Source Project
4 * Licensed under the Eclipse Public License, Version 1.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
8 * http://www.eclipse.org/org/documents/epl-v10.php
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.
17 package com.android.ide.eclipse.adt.internal.launch.junit.runtime;
19 import com.android.ddmlib.testrunner.ITestRunListener;
20 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
21 import com.android.ddmlib.testrunner.TestIdentifier;
22 import com.android.ide.eclipse.adt.AdtPlugin;
23 import com.android.ide.eclipse.adt.internal.launch.LaunchMessages;
25 import org.eclipse.jdt.internal.junit.runner.MessageIds;
26 import org.eclipse.jdt.internal.junit.runner.RemoteTestRunner;
27 import org.eclipse.jdt.internal.junit.runner.TestExecution;
28 import org.eclipse.jdt.internal.junit.runner.TestReferenceFailure;
31 * Supports Eclipse JUnit execution of Android tests.
33 * Communicates back to a Eclipse JDT JUnit client via a socket connection.
35 * @see org.eclipse.jdt.internal.junit.runner.RemoteTestRunner for more details on the protocol
37 @SuppressWarnings("restriction")
38 public class RemoteAdtTestRunner extends RemoteTestRunner {
40 private AndroidJUnitLaunchInfo mLaunchInfo;
41 private TestExecution mExecution;
44 * Initialize the JDT JUnit test runner parameters from the {@code args}.
46 * @param args name-value pair of arguments to pass to parent JUnit runner.
47 * @param launchInfo the Android specific test launch info
49 protected void init(String[] args, AndroidJUnitLaunchInfo launchInfo) {
51 mLaunchInfo = launchInfo;
55 * Runs a set of tests, and reports back results using parent class.
57 * JDT Unit expects to be sent data in the following sequence:
59 * <li>The total number of tests to be executed.</li>
60 * <li>The test 'tree' data about the tests to be executed, which is composed of the set of
61 * test class names, the number of tests in each class, and the names of each test in the
63 * <li>The test execution result for each test method. Expects individual notifications of
64 * the test execution start, any failures, and the end of the test execution.</li>
65 * <li>The end of the test run, with its elapsed time.</li>
68 * In order to satisfy this, this method performs two actual Android instrumentation runs.
69 * The first is a 'log only' run that will collect the test tree data, without actually
70 * executing the tests, and send it back to JDT JUnit. The second is the actual test execution,
71 * whose results will be communicated back in real-time to JDT JUnit.
73 * @param testClassNames ignored - the AndroidJUnitLaunchInfo will be used to determine which
75 * @param testName ignored
76 * @param execution used to report test progress
79 public void runTests(String[] testClassNames, String testName, TestExecution execution) {
80 // hold onto this execution reference so it can be used to report test progress
81 mExecution = execution;
83 RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mLaunchInfo.getAppPackage(),
84 mLaunchInfo.getRunner(), mLaunchInfo.getDevice());
86 if (mLaunchInfo.getTestClass() != null) {
87 if (mLaunchInfo.getTestMethod() != null) {
88 runner.setMethodName(mLaunchInfo.getTestClass(), mLaunchInfo.getTestMethod());
90 runner.setClassName(mLaunchInfo.getTestClass());
94 if (mLaunchInfo.getTestPackage() != null) {
95 runner.setTestPackageName(mLaunchInfo.getTestPackage());
98 // set log only to first collect test case info, so Eclipse has correct test case count/
100 runner.setLogOnly(true);
101 TestCollector collector = new TestCollector();
102 runner.run(collector);
103 if (collector.getErrorMessage() != null) {
104 // error occurred during test collection.
105 reportError(collector.getErrorMessage());
107 notifyTestRunEnded(0);
110 notifyTestRunStarted(collector.getTestCaseCount());
111 collector.sendTrees(this);
113 // now do real execution
114 runner.setLogOnly(false);
115 if (mLaunchInfo.isDebugMode()) {
116 runner.setDebug(true);
118 runner.run(new TestRunListener());
122 * Main entry method to run tests
124 * @param programArgs JDT JUnit program arguments to be processed by parent
125 * @param junitInfo the {@link AndroidJUnitLaunchInfo} containing info about this test ru
127 public void runTests(String[] programArgs, AndroidJUnitLaunchInfo junitInfo) {
128 init(programArgs, junitInfo);
133 * Stop the current test run.
135 public void terminate() {
140 protected void stop() {
141 if (mExecution != null) {
146 private void notifyTestRunEnded(long elapsedTime) {
147 // copy from parent - not ideal, but method is private
148 sendMessage(MessageIds.TEST_RUN_END + elapsedTime);
154 * @param errorMessage
156 private void reportError(String errorMessage) {
157 AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(),
158 String.format(LaunchMessages.RemoteAdtTestRunner_RunFailedMsg_s, errorMessage));
160 //notifyTestRunStopped(-1);
164 * TestRunListener that communicates results in real-time back to JDT JUnit
166 private class TestRunListener implements ITestRunListener {
169 * @see com.android.ddmlib.testrunner.ITestRunListener#testEnded(com.android.ddmlib.testrunner.TestIdentifier)
171 public void testEnded(TestIdentifier test) {
172 mExecution.getListener().notifyTestEnded(new TestCaseReference(test));
176 * @see com.android.ddmlib.testrunner.ITestRunListener#testFailed(com.android.ddmlib.testrunner.ITestRunListener.TestFailure, com.android.ddmlib.testrunner.TestIdentifier, java.lang.String)
178 public void testFailed(TestFailure status, TestIdentifier test, String trace) {
180 if (status == TestFailure.ERROR) {
181 statusString = MessageIds.TEST_ERROR;
183 statusString = MessageIds.TEST_FAILED;
185 TestReferenceFailure failure =
186 new TestReferenceFailure(new TestCaseReference(test),
187 statusString, trace, null);
188 mExecution.getListener().notifyTestFailed(failure);
192 * @see com.android.ddmlib.testrunner.ITestRunListener#testRunEnded(long)
194 public void testRunEnded(long elapsedTime) {
195 notifyTestRunEnded(elapsedTime);
196 AdtPlugin.printToConsole(mLaunchInfo.getProject(),
197 LaunchMessages.RemoteAdtTestRunner_RunCompleteMsg);
201 * @see com.android.ddmlib.testrunner.ITestRunListener#testRunFailed(java.lang.String)
203 public void testRunFailed(String errorMessage) {
204 reportError(errorMessage);
208 * @see com.android.ddmlib.testrunner.ITestRunListener#testRunStarted(int)
210 public void testRunStarted(int testCount) {
215 * @see com.android.ddmlib.testrunner.ITestRunListener#testRunStopped(long)
217 public void testRunStopped(long elapsedTime) {
218 notifyTestRunStopped(elapsedTime);
219 AdtPlugin.printToConsole(mLaunchInfo.getProject(),
220 LaunchMessages.RemoteAdtTestRunner_RunStoppedMsg);
224 * @see com.android.ddmlib.testrunner.ITestRunListener#testStarted(com.android.ddmlib.testrunner.TestIdentifier)
226 public void testStarted(TestIdentifier test) {
227 TestCaseReference testId = new TestCaseReference(test);
228 mExecution.getListener().notifyTestStarted(testId);