/******************************************************************************* | |
* Copyright (c) 2009, 2010 Nokia and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: | |
* Nokia - Initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.cdt.debug.edc.tests; | |
import java.io.File; | |
import java.io.FilenameFilter; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.concurrent.ExecutionException; | |
import org.eclipse.cdt.debug.edc.ITCFAgentLauncher; | |
import org.eclipse.cdt.debug.edc.formatter.IVariableValueConverter; | |
import org.eclipse.cdt.debug.edc.internal.EDCDebugger; | |
import org.eclipse.cdt.debug.edc.internal.TCFServiceManager; | |
import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager; | |
import org.eclipse.cdt.debug.edc.internal.services.dsf.Expressions; | |
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl; | |
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC; | |
import org.eclipse.cdt.debug.edc.launch.EDCLaunch; | |
import org.eclipse.cdt.debug.edc.launch.IEDCLaunchConfigurationConstants; | |
import org.eclipse.cdt.debug.edc.services.IEDCExecutionDMC; | |
import org.eclipse.cdt.debug.edc.services.IEDCExpression; | |
import org.eclipse.cdt.debug.edc.services.Stack; | |
import org.eclipse.cdt.debug.edc.symbols.IType; | |
import org.eclipse.cdt.debug.edc.symbols.TypeUtils; | |
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; | |
import org.eclipse.cdt.dsf.concurrent.Query; | |
import org.eclipse.cdt.dsf.datamodel.IDMContext; | |
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext; | |
import org.eclipse.cdt.dsf.debug.service.IExpressions2; | |
import org.eclipse.cdt.dsf.debug.service.IExpressions2.CastInfo; | |
import org.eclipse.cdt.dsf.debug.service.IExpressions2.ICastedExpressionDMContext; | |
import org.eclipse.cdt.dsf.debug.service.IFormattedValues; | |
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; | |
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; | |
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason; | |
import org.eclipse.cdt.dsf.debug.service.IStack; | |
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; | |
import org.eclipse.cdt.dsf.service.DsfServicesTracker; | |
import org.eclipse.cdt.dsf.service.DsfSession; | |
import org.eclipse.core.runtime.CoreException; | |
import org.eclipse.core.runtime.IPath; | |
import org.eclipse.core.runtime.IStatus; | |
import org.eclipse.core.runtime.NullProgressMonitor; | |
import org.eclipse.core.runtime.Path; | |
import org.eclipse.core.runtime.Status; | |
import org.eclipse.debug.core.DebugException; | |
import org.eclipse.debug.core.DebugPlugin; | |
import org.eclipse.debug.core.ILaunch; | |
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; | |
import org.eclipse.debug.core.ILaunchListener; | |
import org.eclipse.debug.core.ILaunchManager; | |
import org.eclipse.debug.internal.ui.DebugUIPlugin; | |
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; | |
import org.eclipse.jface.dialogs.MessageDialogWithToggle; | |
import org.eclipse.jface.preference.IPreferenceStore; | |
import org.eclipse.swt.widgets.Display; | |
import org.eclipse.tm.tcf.services.IRunControl; | |
import org.eclipse.ui.IViewPart; | |
import org.eclipse.ui.IWorkbench; | |
import org.eclipse.ui.IWorkbenchPage; | |
import org.eclipse.ui.IWorkbenchWindow; | |
import org.eclipse.ui.PartInitException; | |
import org.eclipse.ui.PlatformUI; | |
import org.eclipse.ui.WorkbenchException; | |
import org.junit.Assert; | |
@SuppressWarnings("restriction") | |
public class TestUtils { | |
private static final Map<DsfSession,Map<Object,Object>> services = Collections | |
.synchronizedMap(new HashMap<DsfSession,Map<Object,Object>>()); | |
public interface Condition { | |
boolean isConditionValid()throws Exception; | |
} | |
public static final long DEFAULT_WAIT_TIMEOUT = 60000; | |
public static final long DEFAULT_WAIT_INTERVAL = 10; | |
public static void wait(Condition condition) throws Exception { | |
wait(condition, DEFAULT_WAIT_TIMEOUT, DEFAULT_WAIT_INTERVAL); | |
} | |
public static void waitOnExecutorThread(DsfSession session, Condition condition) throws Exception { | |
waitOnExecutorThread(session, condition, DEFAULT_WAIT_TIMEOUT, DEFAULT_WAIT_INTERVAL); | |
} | |
public static void wait(Condition condition, long timeout) throws Exception { | |
wait(condition, timeout, DEFAULT_WAIT_INTERVAL); | |
} | |
public static void waitOnExecutorThread(DsfSession session, Condition condition, long timeout) throws Exception { | |
waitOnExecutorThread(session, condition, timeout, DEFAULT_WAIT_INTERVAL); | |
} | |
static public class ConditionQuery extends Query<Boolean> { | |
private final Condition condition; | |
public ConditionQuery(Condition condition) { | |
super(); | |
this.condition = condition; | |
} | |
@Override | |
protected void execute(DataRequestMonitor<Boolean> rm) { | |
try { | |
rm.setData(condition.isConditionValid()); | |
} catch (Exception e) { | |
rm.setStatus(new Status(IStatus.ERROR, EDCTestPlugin.PLUGIN_ID, | |
null, e)); //$NON-NLS-1$ | |
} | |
rm.done(); | |
} | |
}; | |
public static void waitOnExecutorThread(DsfSession session, final Condition condition, final long timeout, | |
final long interval) throws Exception { | |
long limit = System.currentTimeMillis() + timeout; | |
ConditionQuery conditionRunnable = new ConditionQuery(condition); | |
session.getExecutor().execute(conditionRunnable); | |
boolean conditionValid = conditionRunnable.get(); | |
while (!conditionValid) { | |
Thread.sleep(interval); | |
if (System.currentTimeMillis() > limit) | |
throw new AssertionError(); | |
conditionRunnable = new TestUtils.ConditionQuery(condition); | |
session.getExecutor().execute(conditionRunnable); | |
conditionValid = conditionRunnable.get(); | |
} | |
} | |
public static void wait(Condition condition, long timeout, long interval) throws Exception { | |
long limit = System.currentTimeMillis() + timeout; | |
while (!condition.isConditionValid()) { | |
Display display = Display.getCurrent(); | |
if (display != null && !display.readAndDispatch()) | |
display.sleep(); | |
Thread.sleep(interval); | |
if (System.currentTimeMillis() > limit) | |
throw new AssertionError(); | |
} | |
} | |
/** | |
* Wait for UI to update so that we can see the debugger work in | |
* test workbench. | |
* For headless mode, this just does nothing and return immediately. | |
* | |
* @param timeout | |
*/ | |
public static void waitForUIUpdate(int timeout) { | |
long limit = System.currentTimeMillis() + timeout; | |
Display display = Display.getCurrent(); | |
if (display == null || null == display.getActiveShell()) | |
return; | |
while (true) { | |
while (display.readAndDispatch()); | |
if (System.currentTimeMillis() > limit) | |
break; | |
} | |
} | |
public static String[] getFileNamesByExtension(final String folderName, final String fileExtension) { | |
File folder = new File(folderName); | |
String[] files = folder.list(new FilenameFilter() { | |
public boolean accept(File dir, String name) { | |
if (fileExtension == null || fileExtension.length() == 0) | |
return true; | |
return name.endsWith(fileExtension); | |
} | |
}); | |
return files; | |
} | |
public static String[] getFileFullNamesByExtension(final String folderName, final String fileExtension) { | |
String[] files = getFileNamesByExtension(folderName, fileExtension); | |
for (int i = 0; i < files.length; i++) { | |
files[i] = folderName + File.separatorChar + files[i]; | |
} | |
return files; | |
} | |
public static boolean stringCompare(String s1, String s2, boolean ignoreCase, boolean ignoreWhite, boolean ignore0x) { | |
if (ignoreWhite) { | |
s1 = s1.replaceAll(" ", "").replaceAll("\t", ""); | |
s2 = s2.replaceAll(" ", "").replaceAll("\t", ""); | |
} | |
if (ignore0x) { | |
s1 = s1.replaceAll("0x", ""); | |
s2 = s2.replaceAll("0x", ""); | |
} | |
if (ignoreCase) | |
return s1.equalsIgnoreCase(s2); | |
else | |
return s1.equals(s2); | |
} | |
public static void hideView(final IViewPart viewPart) { | |
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { | |
public void run() { | |
IWorkbenchPage page= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); | |
page.hideView(viewPart); | |
} | |
}); | |
} | |
public static IViewPart showView(final String viewId) throws PartInitException { | |
final IViewPart[] vpHolder = new IViewPart[]{null}; | |
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { | |
public void run() { | |
IWorkbenchPage page= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); | |
try { | |
vpHolder[0] = page.showView(viewId); | |
Assert.assertNotNull("Can't open View", vpHolder[0] != null); | |
} catch (PartInitException e) { | |
Assert.fail(e.getMessage()); | |
} | |
} | |
}); | |
return vpHolder[0]; | |
} | |
public static void showDebugPerspective() { | |
showPerspective("org.eclipse.debug.ui.DebugPerspective"); | |
} | |
public static void showPerspective(final String perspective) { | |
Display display = Display.getDefault(); | |
if ( display != null ) | |
display.syncExec( new Runnable() { | |
public void run() { | |
IWorkbench workbench = PlatformUI.getWorkbench(); | |
IWorkbenchWindow activeWindow = workbench.getActiveWorkbenchWindow(); | |
try { | |
workbench.showPerspective(perspective, activeWindow); | |
} catch (WorkbenchException e) {} | |
} | |
}); | |
} | |
public static void disableDebugPerspectiveSwitchPrompt() { | |
if (null == Display.getCurrent() || null == Display.getCurrent().getActiveShell()) // in case test is run in headless mode. | |
return; | |
IPreferenceStore store = DebugUIPlugin.getDefault().getPreferenceStore(); | |
store.setValue(IInternalDebugUIConstants.PREF_SWITCH_PERSPECTIVE_ON_SUSPEND, MessageDialogWithToggle.ALWAYS); | |
} | |
public static EDCLaunch createLaunchForAlbum(String albumName) throws Exception { | |
String res_folder = EDCTestPlugin.projectRelativePath("resources/Snapshots"); | |
return createLaunchForAlbum(albumName, res_folder); | |
} | |
public static EDCLaunch createLaunchForAlbum(String albumName, String res_folder) throws Exception { | |
ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager(); | |
ILaunchConfigurationWorkingCopy configuration = lm.getLaunchConfigurationType( | |
"org.eclipse.cdt.debug.edc.snapshot").newInstance(null, "TestAlbumLaunch"); | |
IPath dsaPath = new Path(res_folder); | |
dsaPath = dsaPath.append(albumName); | |
Assert.assertTrue("The path must exist: " + dsaPath, dsaPath.toFile().exists()); | |
configuration.setAttribute(IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE, dsaPath.toOSString()); | |
final EDCLaunch[] launchHolder = new EDCLaunch[1]; | |
ILaunchListener listener = new ILaunchListener() { | |
public void launchRemoved(ILaunch launch) { | |
} | |
public void launchChanged(ILaunch launch) { | |
} | |
public void launchAdded(ILaunch launch) { | |
if (launch instanceof EDCLaunch) { | |
EDCLaunch edcLaunch = (EDCLaunch) launch; | |
launchHolder[0] = edcLaunch; | |
} | |
} | |
}; | |
lm.addLaunchListener(listener); | |
ILaunch launch = configuration.doSave().launch(ILaunchManager.DEBUG_MODE, new NullProgressMonitor(), true); | |
if (launch == null) | |
return null; | |
TestUtils.wait(new Condition() { | |
public boolean isConditionValid() { | |
return launchHolder[0] != null; | |
} | |
}); | |
lm.removeLaunchListener(listener); | |
Assert.assertNotNull(launchHolder[0]); | |
return launchHolder[0]; | |
} | |
public static DsfSession waitForSession(final EDCLaunch launch) throws Exception { | |
final DsfSession sessionHolder[] = { null }; | |
TestUtils.wait(new Condition() { | |
public boolean isConditionValid() { | |
DsfSession session = launch.getSession(); | |
if (session == null) | |
return false; | |
sessionHolder[0] = session; | |
return true; | |
} | |
}); | |
return sessionHolder[0]; | |
} | |
public static IEDCExecutionDMC waitForExecutionDMC(final DsfSession session) throws Exception { | |
final IEDCExecutionDMC contextHolder[] = { null }; | |
TestUtils.waitOnExecutorThread(session, new Condition() { | |
public boolean isConditionValid() { | |
DsfServicesTracker servicesTracker = getDsfServicesTracker(session); | |
RunControl runControlService = servicesTracker.getService(RunControl.class); | |
if (runControlService == null) | |
return false; | |
ExecutionDMC rootDMC = runControlService.getRootDMC(); | |
if (rootDMC == null) | |
return false; | |
IEDCExecutionDMC[] processes = rootDMC.getChildren(); | |
if (processes.length == 0) | |
return false; | |
contextHolder[0] = processes[0]; | |
return true; | |
} | |
}); | |
return contextHolder[0]; | |
} | |
public static IFrameDMContext waitForStackFrame(final DsfSession session, final IEDCExecutionDMC threadDMC) | |
throws Exception { | |
return waitForStackFrame(session, threadDMC, 0); | |
} | |
public static IFrameDMContext waitForStackFrame(final DsfSession session, final IEDCExecutionDMC threadDMC, final int level) | |
throws Exception { | |
final IFrameDMContext frameHolder[] = { null }; | |
TestUtils.waitOnExecutorThread(session, new Condition() { | |
public boolean isConditionValid() throws Exception { | |
DsfServicesTracker servicesTracker = getDsfServicesTracker(session); | |
Stack stackService = servicesTracker.getService(Stack.class); | |
if (stackService == null) | |
return false; | |
IFrameDMContext[] frames = stackService.getFramesForDMC(threadDMC, 0, IStack.ALL_FRAMES); | |
if (frames.length > level) { | |
frameHolder[0] = frames[level]; | |
return true; | |
} | |
return false; | |
} | |
}); | |
return frameHolder[0]; | |
} | |
public static ExecutionDMC waitForSuspendedThread(final DsfSession session) throws Exception { | |
final ExecutionDMC contextHolder[] = { null }; | |
TestUtils.waitOnExecutorThread(session, new Condition() { | |
public boolean isConditionValid() { | |
DsfServicesTracker servicesTracker = getDsfServicesTracker(session); | |
RunControl runControlService = servicesTracker.getService(RunControl.class); | |
if (runControlService == null) | |
return false; | |
ExecutionDMC rootDMC = runControlService.getRootDMC(); | |
if (rootDMC == null) | |
return false; | |
ExecutionDMC[] processes = rootDMC.getChildren(); | |
if (processes.length == 0) | |
return false; | |
for (ExecutionDMC process : processes) { | |
ExecutionDMC[] threads = process.getChildren(); | |
for (ExecutionDMC thread : threads) { | |
if (thread.isSuspended() && thread.getStateChangeReason() != StateChangeReason.SHAREDLIB) { | |
contextHolder[0] = thread; | |
return true; | |
} | |
} | |
} | |
return contextHolder[0] != null; | |
} | |
}); | |
return contextHolder[0]; | |
} | |
/** | |
* Get only the formatted value of an expression. | |
* @param session | |
* @param frame | |
* @param expr | |
* @return | |
* @throws Exception | |
* @throws ExecutionException | |
*/ | |
public static String getExpressionValue(final DsfSession session, final IDMContext frame, final String expr) | |
throws Exception, ExecutionException { | |
IEDCExpression expression = getExpressionDMC(session, frame, expr); | |
String formatted = getFormattedExpressionValue(session, frame, expression); | |
return formatted; | |
} | |
/** | |
* Get an evaluated expression context. | |
* @param session | |
* @param frame | |
* @param expr | |
* @return | |
* @throws Exception | |
* @throws ExecutionException | |
*/ | |
public static IEDCExpression getExpressionDMC(final DsfSession session, final IDMContext frame, final String expr) | |
throws Exception, ExecutionException { | |
Expressions expressionsService = getService(session, Expressions.class); | |
IEDCExpression expression = (IEDCExpression) expressionsService.createExpression(frame, expr); | |
expression.evaluateExpression(); | |
return expression; | |
} | |
/** | |
* Get the formatted string value of an expression context. | |
* @param session | |
* @param frame | |
* @param expression | |
* @return | |
* @throws Exception | |
* @throws ExecutionException | |
*/ | |
public static String getFormattedExpressionValue(final DsfSession session, final IDMContext frame, final IEDCExpression expression) | |
throws Exception, ExecutionException { | |
Expressions expressionsService = getService(session, Expressions.class); | |
FormattedValueDMContext fvc = expressionsService.getFormattedValueContext(expression, | |
IFormattedValues.NATURAL_FORMAT); | |
FormattedValueDMData formattedValue = expression.getFormattedValue(fvc); | |
IType exprType = TypeUtils.getStrippedType(expression.getEvaluatedType()); | |
IVariableValueConverter customValue = | |
FormatExtensionManager.instance().getVariableValueConverter(exprType); | |
if (customValue != null) { | |
FormattedValueDMData customFormattedValue = null; | |
try { | |
customFormattedValue = new FormattedValueDMData(customValue.getValue(expression)); | |
formattedValue = customFormattedValue; | |
} | |
catch (CoreException e) { | |
EDCTestPlugin.getMessageLogger().logException(e); | |
} | |
catch (Throwable t) { | |
EDCTestPlugin.getMessageLogger().logException(t); | |
} | |
} | |
return formattedValue.getFormattedValue(); | |
} | |
/** | |
* Get a casted expression. | |
* @param session | |
* @param frame | |
* @param expr | |
* @return casted expression DMC | |
* @throws Exception | |
* @throws ExecutionException | |
*/ | |
public static ICastedExpressionDMContext getCastedExpressionValue(final DsfSession session, final IDMContext frame, final String expr, final String type) | |
throws Exception, ExecutionException { | |
IEDCExpression expression = getExpressionDMC(session, frame, expr); | |
CastInfo castInfo = new CastInfo(type); | |
ICastedExpressionDMContext castedDMC = getCastedExpressionDMC(session, frame, expression, castInfo); | |
return castedDMC; | |
} | |
/** | |
* @param session | |
* @param frame | |
* @param expression | |
* @param castInfo | |
* @return | |
* @throws ExecutionException | |
* @throws InterruptedException | |
*/ | |
public static ICastedExpressionDMContext getCastedExpressionDMC( | |
final DsfSession session, final IDMContext frame, final IExpressionDMContext expression, | |
final CastInfo castInfo) throws InterruptedException, ExecutionException { | |
Query<ICastedExpressionDMContext> runnable = new Query<ICastedExpressionDMContext>() { | |
@Override | |
protected void execute(DataRequestMonitor<ICastedExpressionDMContext> rm) { | |
DsfServicesTracker servicesTracker = getDsfServicesTracker(session); | |
IExpressions2 expressionsService = servicesTracker.getService(IExpressions2.class); | |
rm.setData(expressionsService.createCastedExpression(expression, castInfo)); | |
rm.done(); | |
} | |
}; | |
session.getExecutor().execute(runnable); | |
return runnable.get(); | |
} | |
/** | |
* Get an evaluated expression context. | |
* @param session | |
* @param frame | |
* @param expr | |
* @return | |
* @throws Exception | |
* @throws ExecutionException | |
*/ | |
public static IExpressionDMContext[] getSubExpressionDMCs(final DsfSession session, final IDMContext frame, | |
final IExpressionDMContext expr) | |
throws Exception, ExecutionException { | |
Query<IExpressionDMContext[]> runnable = new Query<IExpressionDMContext[]>() { | |
@Override | |
protected void execute(DataRequestMonitor<IExpressionDMContext[]> rm) { | |
DsfServicesTracker servicesTracker = getDsfServicesTracker(session); | |
Expressions expressionsService = servicesTracker.getService(Expressions.class); | |
expressionsService.getSubExpressions(expr, rm); | |
} | |
}; | |
session.getExecutor().execute(runnable); | |
return runnable.get(); | |
} | |
@SuppressWarnings("unchecked") | |
static public <V> V getService(final DsfSession session, final Class<V> serviceClass) { | |
if (services.get(session) == null) | |
services.put(session, new HashMap<Object, Object>()); | |
if (!services.get(session).containsKey(serviceClass)) | |
{ | |
if (session.getExecutor().isInExecutorThread()) | |
{ | |
services.get(session).put(serviceClass, getDsfServicesTracker(session).getService(serviceClass)); | |
} | |
else | |
{ | |
Query<V> serviceQuery = new Query<V>() { | |
@Override | |
protected void execute( | |
DataRequestMonitor<V> rm) { | |
rm.setData(getDsfServicesTracker(session).getService(serviceClass)); | |
rm.done(); | |
} | |
}; | |
session.getExecutor().execute(serviceQuery); | |
try { | |
services.get(session).put(serviceClass, serviceQuery.get()); | |
} catch (Exception e) { | |
EDCDebugger.getMessageLogger().logError(null, e); | |
return null; | |
} | |
} | |
} | |
return (V) services.get(session).get(serviceClass); | |
} | |
public static DsfServicesTracker getDsfServicesTracker(final DsfSession session) { | |
return new DsfServicesTracker(EDCTestPlugin.getBundleContext(), session.getId()); | |
} | |
/** Tell if a given launcher is available. Useful when a snapshot test depends on an internal | |
* launch type. | |
* @param id the id of the org.eclipse.debug.core.launchConfigurationTypes launchConfigurationType | |
* @return true if found | |
*/ | |
public static boolean hasLaunchConfiguationType(String id) { | |
return DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType(id) != null; | |
} | |
/** | |
* Tell whether there is a TCF agent launcher available with the given ID. | |
* @param reqdLauncher | |
* @return | |
*/ | |
public static boolean hasTCFAgentLauncher(String id) { | |
TCFServiceManager tcfServiceManager = (TCFServiceManager) EDCDebugger.getDefault().getServiceManager(); | |
ITCFAgentLauncher[] registered = tcfServiceManager.findSuitableAgentLaunchers(IRunControl.NAME, Collections.<String, String>emptyMap(), true); | |
for (ITCFAgentLauncher launcher : registered) { | |
if (launcher.getClass().getName().equals(id)) | |
return true; | |
} | |
return false; | |
} | |
public static void shutdownDebugSession(EDCLaunch launch, final DsfSession session) { | |
// shutdown the launch | |
if (launch != null) { | |
final Boolean done[] = new Boolean[] {false}; | |
synchronized (launch) { | |
if (launch.isTerminated() || launch.isTerminating()) | |
return; | |
// terminating the launch will cause the session to end, but wait for | |
// it to end to prevent multiple launches from tests existing at the | |
// same time which can cause some weird behavior | |
DsfSession.addSessionEndedListener(new DsfSession.SessionEndedListener() { | |
public void sessionEnded(DsfSession se) { | |
if (session == se) { | |
done[0] = true; | |
} | |
} | |
}); | |
try { | |
launch.terminate(); | |
} catch (DebugException de) { | |
} | |
} | |
launch = null; | |
while (! done[0]) { | |
try { | |
Thread.sleep(10); | |
} catch (InterruptedException e) { | |
} | |
} | |
} | |
} | |
public static void waitForLaunchTerminated(final EDCLaunch launch) throws Exception { | |
TestUtils.wait(new Condition() { | |
public boolean isConditionValid() { | |
return launch.isTerminated(); | |
} | |
}); | |
} | |
public static void terminateLaunch(EDCLaunch launch) throws Exception { | |
launch.terminate(); | |
waitForLaunchTerminated(launch); | |
} | |
} |