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.
16 package com.android.ide.eclipse.adt.internal.launch.junit;
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;
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;
40 * A launch action that executes a instrumentation test run on an Android device.
42 class AndroidJUnitLaunchAction implements IAndroidLaunchAction {
44 private final AndroidJUnitLaunchInfo mLaunchInfo;
47 * Creates a AndroidJUnitLaunchAction.
49 * @param launchInfo the {@link AndroidJUnitLaunchInfo} for the JUnit run
51 public AndroidJUnitLaunchAction(AndroidJUnitLaunchInfo launchInfo) {
52 mLaunchInfo = launchInfo;
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.
59 * Note: Must be executed on non-UI thread.
61 * @see IAndroidLaunchAction#doLaunchAction(DelayedLaunchInfo, IDevice)
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);
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;
75 junitDelegate.launch(info.getLaunch().getLaunchConfiguration(), mode, info.getLaunch(),
78 // TODO: need to add AMReceiver-type functionality somewhere
79 } catch (CoreException e) {
80 AdtPlugin.printErrorToConsole(info.getProject(),
81 LaunchMessages.AndroidJUnitLaunchAction_LaunchFail);
89 public String getLaunchDescription() {
90 return String.format(LaunchMessages.AndroidJUnitLaunchAction_LaunchDesc_s,
91 mLaunchInfo.getRunner());
95 * Extends the JDT JUnit launch delegate to allow for JUnit UI reuse.
97 private static class JUnitLaunchDelegate extends JUnitLaunchConfigurationDelegate {
99 private AndroidJUnitLaunchInfo mLaunchInfo;
101 public JUnitLaunchDelegate(AndroidJUnitLaunchInfo launchInfo) {
102 mLaunchInfo = launchInfo;
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)
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);
117 * @see org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate#verifyMainTypeName(org.eclipse.debug.core.ILaunchConfiguration)
120 public String verifyMainTypeName(ILaunchConfiguration configuration) {
121 return "com.android.ide.eclipse.adt.junit.internal.runner.RemoteAndroidTestRunner"; //$NON-NLS-1$
125 * Overrides parent to return a VM Runner implementation which launches a thread, rather
126 * than a separate VM process
129 public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) {
130 return new VMTestRunner(mLaunchInfo);
135 * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#getLaunch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String)
138 public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) {
139 return mLaunchInfo.getLaunch();
144 * Provides a VM runner implementation which starts a inline implementation of a launch process
146 private static class VMTestRunner implements IVMRunner {
148 private final AndroidJUnitLaunchInfo mJUnitInfo;
150 VMTestRunner(AndroidJUnitLaunchInfo info) {
156 * @throws CoreException
158 public void run(final VMRunnerConfiguration config, ILaunch launch,
159 IProgressMonitor monitor) throws CoreException {
161 TestRunnerProcess runnerProcess =
162 new TestRunnerProcess(config, mJUnitInfo);
163 launch.addProcess(runnerProcess);
169 * Launch process that executes the tests.
171 private static class TestRunnerProcess implements IProcess {
173 private final VMRunnerConfiguration mRunConfig;
174 private final AndroidJUnitLaunchInfo mJUnitInfo;
175 private RemoteAdtTestRunner mTestRunner = null;
176 private boolean mIsTerminated = false;
178 TestRunnerProcess(VMRunnerConfiguration runConfig, AndroidJUnitLaunchInfo info) {
179 mRunConfig = runConfig;
184 * @see org.eclipse.debug.core.model.IProcess#getAttribute(java.lang.String)
186 public String getAttribute(String key) {
192 * @see org.eclipse.debug.core.model.IProcess#getExitValue()
194 public int getExitValue() {
199 * @see org.eclipse.debug.core.model.IProcess#getLabel()
201 public String getLabel() {
202 return mJUnitInfo.getLaunch().getLaunchMode();
206 * @see org.eclipse.debug.core.model.IProcess#getLaunch()
208 public ILaunch getLaunch() {
209 return mJUnitInfo.getLaunch();
213 * @see org.eclipse.debug.core.model.IProcess#getStreamsProxy()
215 public IStreamsProxy getStreamsProxy() {
220 * @see org.eclipse.debug.core.model.IProcess#setAttribute(java.lang.String,
223 public void setAttribute(String key, String value) {
228 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
230 @SuppressWarnings("unchecked")
231 public Object getAdapter(Class adapter) {
236 * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
238 public boolean canTerminate() {
243 * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
245 public boolean isTerminated() {
246 return mIsTerminated;
251 * @see org.eclipse.debug.core.model.ITerminate#terminate()
253 public void terminate() {
254 if (mTestRunner != null) {
255 mTestRunner.terminate();
257 mIsTerminated = true;
261 * Launches a test runner that will communicate results back to JDT JUnit UI.
263 * Must be executed on a non-UI thread.
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");
273 mTestRunner = new RemoteAdtTestRunner();
274 mTestRunner.runTests(mRunConfig.getProgramArguments(), mJUnitInfo);