OSDN Git Service

Externalize ADT JUnit launch strings.
[android-x86/sdk.git] / eclipse / plugins / com.android.ide.eclipse.adt / src / com / android / ide / eclipse / adt / internal / launch / junit / runtime / RemoteAdtTestRunner.java
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
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
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
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.ide.eclipse.adt.internal.launch.junit.runtime;
18
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;
24
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;
29
30 /**
31  * Supports Eclipse JUnit execution of Android tests.
32  * <p/>
33  * Communicates back to a Eclipse JDT JUnit client via a socket connection.
34  * 
35  * @see org.eclipse.jdt.internal.junit.runner.RemoteTestRunner for more details on the protocol
36  */
37 @SuppressWarnings("restriction")
38 public class RemoteAdtTestRunner extends RemoteTestRunner {
39
40     private AndroidJUnitLaunchInfo mLaunchInfo;
41     private TestExecution mExecution;
42     
43     /**
44      * Initialize the JDT JUnit test runner parameters from the {@code args}.
45      * 
46      * @param args name-value pair of arguments to pass to parent JUnit runner. 
47      * @param launchInfo the Android specific test launch info
48      */
49     protected void init(String[] args, AndroidJUnitLaunchInfo launchInfo) {
50         defaultInit(args);
51         mLaunchInfo = launchInfo;
52     }   
53
54     /**
55      * Runs a set of tests, and reports back results using parent class.
56      * <p/>
57      * JDT Unit expects to be sent data in the following sequence:
58      * <ol>
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
62      *   class.</li>
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>
66      * </ol>  
67      * <p/>
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.
72      * 
73      * @param testClassNames ignored - the AndroidJUnitLaunchInfo will be used to determine which
74      *     tests to run.
75      * @param testName ignored
76      * @param execution used to report test progress
77      */
78     @Override
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;
82         
83         RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mLaunchInfo.getAppPackage(), 
84                 mLaunchInfo.getRunner(), mLaunchInfo.getDevice()); 
85
86         if (mLaunchInfo.getTestClass() != null) {
87             if (mLaunchInfo.getTestMethod() != null) {
88                 runner.setMethodName(mLaunchInfo.getTestClass(), mLaunchInfo.getTestMethod());
89             } else {    
90                 runner.setClassName(mLaunchInfo.getTestClass());
91             }    
92         }
93
94         if (mLaunchInfo.getTestPackage() != null) {
95             runner.setTestPackageName(mLaunchInfo.getTestPackage());
96         }
97
98         // set log only to first collect test case info, so Eclipse has correct test case count/
99         // tree info
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());
106             // abort here
107             notifyTestRunEnded(0);
108             return;
109         }
110         notifyTestRunStarted(collector.getTestCaseCount());
111         collector.sendTrees(this);
112         
113         // now do real execution
114         runner.setLogOnly(false);
115         if (mLaunchInfo.isDebugMode()) {
116             runner.setDebug(true);
117         }
118         runner.run(new TestRunListener());
119     }
120     
121     /**
122      * Main entry method to run tests
123      * 
124      * @param programArgs JDT JUnit program arguments to be processed by parent
125      * @param junitInfo the {@link AndroidJUnitLaunchInfo} containing info about this test ru
126      */
127     public void runTests(String[] programArgs, AndroidJUnitLaunchInfo junitInfo) {
128         init(programArgs, junitInfo);
129         run();
130     } 
131
132     /**
133      * Stop the current test run.
134      */
135     public void terminate() {
136         stop();
137     }
138
139     @Override
140     protected void stop() {
141         if (mExecution != null) {
142             mExecution.stop();
143         }    
144     }
145
146     private void notifyTestRunEnded(long elapsedTime) {
147         // copy from parent - not ideal, but method is private
148         sendMessage(MessageIds.TEST_RUN_END + elapsedTime);
149         flush();
150         //shutDown();
151     }
152
153     /**
154      * @param errorMessage
155      */
156     private void reportError(String errorMessage) {
157         AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), 
158                 String.format(LaunchMessages.RemoteAdtTestRunner_RunFailedMsg_s, errorMessage));
159         // is this needed?
160         //notifyTestRunStopped(-1);
161     }
162
163     /**
164      * TestRunListener that communicates results in real-time back to JDT JUnit 
165      */
166     private class TestRunListener implements ITestRunListener {
167
168         /* (non-Javadoc)
169          * @see com.android.ddmlib.testrunner.ITestRunListener#testEnded(com.android.ddmlib.testrunner.TestIdentifier)
170          */
171         public void testEnded(TestIdentifier test) {
172             mExecution.getListener().notifyTestEnded(new TestCaseReference(test));
173         }
174
175         /* (non-Javadoc)
176          * @see com.android.ddmlib.testrunner.ITestRunListener#testFailed(com.android.ddmlib.testrunner.ITestRunListener.TestFailure, com.android.ddmlib.testrunner.TestIdentifier, java.lang.String)
177          */
178         public void testFailed(TestFailure status, TestIdentifier test, String trace) {
179             String statusString;
180             if (status == TestFailure.ERROR) {
181                 statusString = MessageIds.TEST_ERROR;
182             } else {
183                 statusString = MessageIds.TEST_FAILED;
184             }
185             TestReferenceFailure failure = 
186                 new TestReferenceFailure(new TestCaseReference(test), 
187                         statusString, trace, null);
188             mExecution.getListener().notifyTestFailed(failure);
189         }
190
191         /* (non-Javadoc)
192          * @see com.android.ddmlib.testrunner.ITestRunListener#testRunEnded(long)
193          */
194         public void testRunEnded(long elapsedTime) {
195             notifyTestRunEnded(elapsedTime);
196             AdtPlugin.printToConsole(mLaunchInfo.getProject(),
197                     LaunchMessages.RemoteAdtTestRunner_RunCompleteMsg);
198         }
199
200         /* (non-Javadoc)
201          * @see com.android.ddmlib.testrunner.ITestRunListener#testRunFailed(java.lang.String)
202          */
203         public void testRunFailed(String errorMessage) {
204             reportError(errorMessage);
205         }
206
207         /* (non-Javadoc)
208          * @see com.android.ddmlib.testrunner.ITestRunListener#testRunStarted(int)
209          */
210         public void testRunStarted(int testCount) {
211             // ignore
212         }
213
214         /* (non-Javadoc)
215          * @see com.android.ddmlib.testrunner.ITestRunListener#testRunStopped(long)
216          */
217         public void testRunStopped(long elapsedTime) {
218             notifyTestRunStopped(elapsedTime);
219             AdtPlugin.printToConsole(mLaunchInfo.getProject(),
220                     LaunchMessages.RemoteAdtTestRunner_RunStoppedMsg);
221         }
222
223         /* (non-Javadoc)
224          * @see com.android.ddmlib.testrunner.ITestRunListener#testStarted(com.android.ddmlib.testrunner.TestIdentifier)
225          */
226         public void testStarted(TestIdentifier test) {
227             TestCaseReference testId = new TestCaseReference(test);
228             mExecution.getListener().notifyTestStarted(testId);
229         }
230     }
231 }