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