OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / sdk / eclipse / plugins / com.android.ide.eclipse.adt / src / com / android / ide / eclipse / adt / internal / launch / junit / AndroidJUnitLaunchAction.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 package com.android.ide.eclipse.adt.internal.launch.junit;
17
18 import com.android.ddmlib.IDevice;
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.internal.launch.DelayedLaunchInfo;
21 import com.android.ide.eclipse.adt.internal.launch.IAndroidLaunchAction;
22 import com.android.ide.eclipse.adt.internal.launch.LaunchMessages;
23 import com.android.ide.eclipse.adt.internal.launch.junit.runtime.AndroidJUnitLaunchInfo;
24 import com.android.ide.eclipse.adt.internal.launch.junit.runtime.RemoteAdtTestRunner;
25
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.core.runtime.IStatus;
29 import org.eclipse.debug.core.ILaunch;
30 import org.eclipse.debug.core.ILaunchConfiguration;
31 import org.eclipse.debug.core.ILaunchManager;
32 import org.eclipse.debug.core.model.IProcess;
33 import org.eclipse.debug.core.model.IStreamsProxy;
34 import org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate;
35 import org.eclipse.jdt.launching.IVMRunner;
36 import org.eclipse.jdt.launching.VMRunnerConfiguration;
37 import org.eclipse.swt.widgets.Display;
38
39 /**
40  * A launch action that executes a instrumentation test run on an Android device.
41  */
42 class AndroidJUnitLaunchAction implements IAndroidLaunchAction {
43
44     private final AndroidJUnitLaunchInfo mLaunchInfo;
45     
46     /**
47      * Creates a AndroidJUnitLaunchAction.
48      * 
49      * @param launchInfo the {@link AndroidJUnitLaunchInfo} for the JUnit run 
50      */
51     public AndroidJUnitLaunchAction(AndroidJUnitLaunchInfo launchInfo) {
52         mLaunchInfo = launchInfo;
53     }
54     
55     /**
56      * Launch a instrumentation test run on given Android device. 
57      * Reuses JDT JUnit launch delegate so results can be communicated back to JDT JUnit UI.
58      * <p/>
59      * Note: Must be executed on non-UI thread.
60      * 
61      * @see IAndroidLaunchAction#doLaunchAction(DelayedLaunchInfo, IDevice)
62      */
63     public boolean doLaunchAction(DelayedLaunchInfo info, IDevice device) {
64         String msg = String.format(LaunchMessages.AndroidJUnitLaunchAction_LaunchInstr_2s,
65                 mLaunchInfo.getRunner(), device.getSerialNumber());
66         AdtPlugin.printToConsole(info.getProject(), msg);
67         
68         try {
69            mLaunchInfo.setDebugMode(info.isDebugMode());
70            mLaunchInfo.setDevice(info.getDevice());
71            JUnitLaunchDelegate junitDelegate = new JUnitLaunchDelegate(mLaunchInfo);
72            final String mode = info.isDebugMode() ? ILaunchManager.DEBUG_MODE : 
73                ILaunchManager.RUN_MODE; 
74
75            junitDelegate.launch(info.getLaunch().getLaunchConfiguration(), mode, info.getLaunch(),
76                    info.getMonitor());
77
78            // TODO: need to add AMReceiver-type functionality somewhere
79         } catch (CoreException e) {
80             AdtPlugin.printErrorToConsole(info.getProject(),
81                     LaunchMessages.AndroidJUnitLaunchAction_LaunchFail);
82         }
83         return true;
84     }
85
86     /**
87      * {@inheritDoc}
88      */
89     public String getLaunchDescription() {
90         return String.format(LaunchMessages.AndroidJUnitLaunchAction_LaunchDesc_s,
91                 mLaunchInfo.getRunner());
92     }
93
94     /**
95      * Extends the JDT JUnit launch delegate to allow for JUnit UI reuse. 
96      */
97     private static class JUnitLaunchDelegate extends JUnitLaunchConfigurationDelegate {
98         
99         private AndroidJUnitLaunchInfo mLaunchInfo;
100
101         public JUnitLaunchDelegate(AndroidJUnitLaunchInfo launchInfo) {
102             mLaunchInfo = launchInfo;
103         }
104
105         /* (non-Javadoc)
106          * @see org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor)
107          */
108         @Override
109         public synchronized void launch(ILaunchConfiguration configuration, String mode,
110                 ILaunch launch, IProgressMonitor monitor) throws CoreException {
111             // TODO: is progress monitor adjustment needed here?
112             super.launch(configuration, mode, launch, monitor);
113         }
114
115         /**
116          * {@inheritDoc}
117          * @see org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate#verifyMainTypeName(org.eclipse.debug.core.ILaunchConfiguration)
118          */
119         @Override
120         public String verifyMainTypeName(ILaunchConfiguration configuration) {
121             return "com.android.ide.eclipse.adt.junit.internal.runner.RemoteAndroidTestRunner"; //$NON-NLS-1$
122         }
123
124         /**
125          * Overrides parent to return a VM Runner implementation which launches a thread, rather
126          * than a separate VM process
127          */
128         @Override
129         public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) {
130             return new VMTestRunner(mLaunchInfo);
131         }
132
133         /**
134          * {@inheritDoc}
135          * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#getLaunch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String)
136          */
137         @Override
138         public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) {
139             return mLaunchInfo.getLaunch();
140         }     
141     }
142
143     /**
144      * Provides a VM runner implementation which starts a inline implementation of a launch process
145      */
146     private static class VMTestRunner implements IVMRunner {
147         
148         private final AndroidJUnitLaunchInfo mJUnitInfo;
149         
150         VMTestRunner(AndroidJUnitLaunchInfo info) {
151             mJUnitInfo = info;
152         }
153
154         /**
155          * {@inheritDoc}
156          * @throws CoreException
157          */
158         public void run(final VMRunnerConfiguration config, ILaunch launch,
159                 IProgressMonitor monitor) throws CoreException {
160             
161             TestRunnerProcess runnerProcess = 
162                 new TestRunnerProcess(config, mJUnitInfo);
163             launch.addProcess(runnerProcess);
164             runnerProcess.run();
165         }
166     }
167
168     /**
169      * Launch process that executes the tests.
170      */
171     private static class TestRunnerProcess implements IProcess  {
172
173         private final VMRunnerConfiguration mRunConfig;
174         private final AndroidJUnitLaunchInfo mJUnitInfo;
175         private RemoteAdtTestRunner mTestRunner = null;
176         private boolean mIsTerminated = false;
177         
178         TestRunnerProcess(VMRunnerConfiguration runConfig, AndroidJUnitLaunchInfo info) {
179             mRunConfig = runConfig;
180             mJUnitInfo = info;
181         }
182         
183         /* (non-Javadoc)
184          * @see org.eclipse.debug.core.model.IProcess#getAttribute(java.lang.String)
185          */
186         public String getAttribute(String key) {
187             return null;
188         }
189
190         /**
191          * {@inheritDoc}
192          * @see org.eclipse.debug.core.model.IProcess#getExitValue()
193          */
194         public int getExitValue() {
195             return 0;
196         }
197
198         /* (non-Javadoc)
199          * @see org.eclipse.debug.core.model.IProcess#getLabel()
200          */
201         public String getLabel() {
202             return mJUnitInfo.getLaunch().getLaunchMode();
203         }
204
205         /* (non-Javadoc)
206          * @see org.eclipse.debug.core.model.IProcess#getLaunch()
207          */
208         public ILaunch getLaunch() {
209             return mJUnitInfo.getLaunch();
210         }
211
212         /* (non-Javadoc)
213          * @see org.eclipse.debug.core.model.IProcess#getStreamsProxy()
214          */
215         public IStreamsProxy getStreamsProxy() {
216             return null;
217         }
218
219         /* (non-Javadoc)
220          * @see org.eclipse.debug.core.model.IProcess#setAttribute(java.lang.String, 
221          * java.lang.String)
222          */
223         public void setAttribute(String key, String value) {
224             // ignore           
225         }
226
227         /* (non-Javadoc)
228          * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
229          */
230         @SuppressWarnings("unchecked")
231         public Object getAdapter(Class adapter) {
232             return null;
233         }
234
235         /* (non-Javadoc)
236          * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
237          */
238         public boolean canTerminate() {
239             return true;
240         }
241
242         /* (non-Javadoc)
243          * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
244          */
245         public boolean isTerminated() {
246             return mIsTerminated;
247         }
248
249         /**
250          * {@inheritDoc}
251          * @see org.eclipse.debug.core.model.ITerminate#terminate()
252          */
253         public void terminate() {
254             if (mTestRunner != null) {
255                 mTestRunner.terminate();
256             }    
257             mIsTerminated = true;
258         } 
259
260         /**
261          * Launches a test runner that will communicate results back to JDT JUnit UI.
262          * <p/>
263          * Must be executed on a non-UI thread.
264          */
265         public void run() {
266             if (Display.getCurrent() != null) {
267                 AdtPlugin.log(IStatus.ERROR, "Adt test runner executed on UI thread");
268                 AdtPlugin.printErrorToConsole(mJUnitInfo.getProject(),
269                         "Test launch failed due to internal error: Running tests on UI thread");
270                 terminate();
271                 return;
272             }
273             mTestRunner = new RemoteAdtTestRunner();
274             mTestRunner.runTests(mRunConfig.getProgramArguments(), mJUnitInfo);
275         }
276     }
277 }
278