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