1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 09:25:31 +02:00

Bug 439926 - CommandTimeout tests can fail on fast machines

Change-Id: I7bd4862cb8b3900a2fc41ad7476b2dff6f541009
Signed-off-by: Marc Khouzam <marc.khouzam@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/30144
This commit is contained in:
Marc Khouzam 2014-07-18 16:06:03 -04:00
parent 947b25009a
commit 90718216f1
4 changed files with 112 additions and 73 deletions

View file

@ -20,7 +20,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Export-Package: org.eclipse.cdt.dsf.gdb,
org.eclipse.cdt.dsf.gdb.actions,
org.eclipse.cdt.dsf.gdb.breakpoints,
org.eclipse.cdt.dsf.gdb.internal;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.debug.gdbjtag.ui",
org.eclipse.cdt.dsf.gdb.internal;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.debug.gdbjtag.ui,org.eclipse.cdt.tests.dsf.gdb",
org.eclipse.cdt.dsf.gdb.internal.commands;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
org.eclipse.cdt.dsf.gdb.internal.memory;x-internal:=true,
org.eclipse.cdt.dsf.gdb.internal.service.command.commands;x-internal:=true,

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2010 Ericsson and others.
* Copyright (c) 2007, 2014 Ericsson 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
@ -31,6 +31,7 @@ import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.dsf.service.DsfSession.SessionStartedListener;
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants;
import org.eclipse.cdt.utils.spawner.ProcessFactory;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
@ -215,7 +216,8 @@ public class BaseTestCase {
launchAttributes.put(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, true);
launchAttributes.put(IGDBLaunchConfigurationConstants.ATTR_HOST, "localhost");
launchAttributes.put(IGDBLaunchConfigurationConstants.ATTR_PORT, "9999");
launchAttributes.put(ITestConstants.LAUNCH_GDB_SERVER, true);
setGdbVersion();
// Set the global launch attributes
@ -236,9 +238,7 @@ public class BaseTestCase {
boolean postMortemLaunch = launchAttributes.get(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE)
.equals(ICDTLaunchConfigurationConstants.DEBUGGER_MODE_CORE);
// First check if we should launch gdbserver in the case of a remote session
if (reallyLaunchGDBServer())
launchGdbServer();
launchGdbServer();
ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType lcType = launchMgr.getLaunchConfigurationType("org.eclipse.cdt.tests.dsf.gdb.TestLaunch");
@ -315,6 +315,12 @@ public class BaseTestCase {
* If the user specified a different host, things won't work.
*/
private void launchGdbServer() {
// First check if we should not launch gdbserver even for a remote session
if (launchAttributes.get(ITestConstants.LAUNCH_GDB_SERVER).equals(false)) {
System.out.println("Forcing to not start gdbserver for this test");
return;
}
if (launchAttributes.get(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE)
.equals(IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE)) {
if (launchAttributes.get(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP).equals(Boolean.TRUE)) {
@ -391,16 +397,6 @@ public class BaseTestCase {
Assume.assumeNoException(e);
}
}
/**
* In some tests we need to start a gdbserver session without starting gdbserver.
* This method allows super classes of this class control the launch of gdbserver.
*
* @return whether gdbserver should be started
*/
protected boolean reallyLaunchGDBServer() {
return true;
}
@BeforeClass
public static void setGlobalPreferences() {

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Mentor Graphics and others.
* Copyright (c) 2012, 2014 Mentor Graphics 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
@ -7,21 +7,32 @@
*
* Contributors:
* Mentor Graphics - Initial API and implementation
* Marc Khouzam (Ericsson) - Update tests to use long timeouts (Bug 439926)
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.gdb.tests;
import junit.framework.Assert;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.mi.service.command.commands.MITargetSelect;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner;
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase;
import org.eclipse.cdt.tests.dsf.gdb.framework.ServiceEventWaitor;
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.debug.core.DebugException;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -31,9 +42,11 @@ public class CommandTimeoutTest extends BaseTestCase {
private static boolean fgTimeoutEnabled = false;
private static int fgTimeout = IGdbDebugPreferenceConstants.COMMAND_TIMEOUT_VALUE_DEFAULT;
private static boolean fgAutoTerminate;
@BeforeClass
public static void doBeforeClass() throws Exception {
// Save the original values of the timeout-related preferences
fgTimeoutEnabled = Platform.getPreferencesService().getBoolean(
GdbPlugin.PLUGIN_ID,
IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT,
@ -44,99 +57,124 @@ public class CommandTimeoutTest extends BaseTestCase {
IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT_VALUE,
IGdbDebugPreferenceConstants.COMMAND_TIMEOUT_VALUE_DEFAULT,
null );
fgAutoTerminate = Platform.getPreferencesService().getBoolean(
GdbPlugin.PLUGIN_ID,
IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB,
true,
null );
}
@Override
public void doBeforeTest() throws Exception {
setLaunchAttributes();
// Can't run the launch right away because each test needs to first set some
// parameters. The individual tests will be responsible for starting the launch.
// Save the original values of the timeout-related preferences
}
@Override
public void doAfterTest() throws Exception {
// Don't call super here, as the launch is already terminated
// Don't call super here, as each test needs to deal with the launch in its own way
// Restore the timeout preferences
// Restore the different preferences we might have changed
IEclipsePreferences node = InstanceScope.INSTANCE.getNode( GdbPlugin.PLUGIN_ID );
node.putBoolean( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT, fgTimeoutEnabled );
node.putInt( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT_VALUE, fgTimeout );
}
protected void performLaunchAndTerminate() throws Exception {
// perform the launch
doLaunch();
// terminate the launch right away
super.doAfterTest();
}
@Override
protected boolean reallyLaunchGDBServer() {
return false;
node.putBoolean( IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB, fgAutoTerminate );
}
/**
* Enables the timeout support and sets the timeout value to minimal - 1.
* Launch is expected to timeout on the first gdb command.
* Sends a command to which GDB will take a long time to reply, so as to generate a timeout.
* This is done after the launch has completed and while the debug session is ongoing.
*/
@Test
public void firstCommandTimedOut() {
public void commandTimedOutDuringSession() throws Exception {
// Enable timeout
IEclipsePreferences node = InstanceScope.INSTANCE.getNode( GdbPlugin.PLUGIN_ID );
node.putBoolean( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT, true );
node.putInt( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT_VALUE, 1 );
node.putInt( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT_VALUE, 2000 );
// Note that sending a "target-select" command when a program is running will kill the program.
// If that triggers us to kill GDB, then our testcase won't have time to timeout.
// Therefore we set the preference to keep GDB alive even if the program is no longer running
node.putBoolean( IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB, false );
doLaunch();
final DsfSession session = getGDBLaunch().getSession();
ServiceEventWaitor<ICommandControlShutdownDMEvent> shutdownEventWaitor = new ServiceEventWaitor<ICommandControlShutdownDMEvent>(
session,
ICommandControlShutdownDMEvent.class);
// Send the command that will timeout
Query<MIInfo> query = new Query<MIInfo>() {
@Override
protected void execute( DataRequestMonitor<MIInfo> rm ) {
DsfServicesTracker tracker = new DsfServicesTracker( TestsPlugin.getBundleContext(), session.getId() );
ICommandControlService commandService = tracker.getService( ICommandControlService.class );
tracker.dispose();
commandService.queueCommand( new MITargetSelect( commandService.getContext(), "localhost", "1", false ), rm );
}
};
try {
performLaunchAndTerminate();
session.getExecutor().execute( query );
query.get();
// Cleanup in case the query does not throw the expected exception
super.doAfterTest();
Assert.fail( "Command is expected to timeout" );
}
catch( Exception e ) {
processException( e );
}
// Make sure we receive a shutdown event to confirm we have aborted the session
shutdownEventWaitor.waitForEvent(TestsPlugin.massageTimeout(5000));
}
/**
* Sends a command to which GDB will take a long time to reply, so as to generate a timeout.
* This is done during the launch to verify that we properly handle that case.
*/
@Test
public void commandTimedOutDuringLaunch() {
// Enable timeout
IEclipsePreferences node = InstanceScope.INSTANCE.getNode( GdbPlugin.PLUGIN_ID );
node.putBoolean( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT, true );
node.putInt( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT_VALUE, 2000 );
// Setup a remote launch so that it sends a "-target-remote" as part of the
// launch steps.
setLaunchAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE,
IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE );
// We won't start gdbserver, so the command will timeout
setLaunchAttribute( ITestConstants.LAUNCH_GDB_SERVER, false);
try {
doLaunch();
// Cleanup in case the launch does not throw the expected exception
super.doAfterTest();
Assert.fail( "Launch is expected to fail" );
}
catch( Exception e ) {
processException( e );
}
}
/**
* Tries to connect to gdbserver without starting it.
* Launch is expected to timeout on "target-remote" command.
*/
@Test
public void remoteConnectionTimedOut() {
if ( !isRemoteSession() )
return;
IEclipsePreferences node = InstanceScope.INSTANCE.getNode( GdbPlugin.PLUGIN_ID );
node.putBoolean( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT, true );
node.putInt( IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT_VALUE, 1000 );
try {
performLaunchAndTerminate();
Assert.fail( "Launch is expected to fail" );
}
catch( Exception e ) {
processException( e );
}
}
/**
* Checks whether the given exception is an instance of {@link CoreException}
* with the status code 20100 which indicates that a gdb command has been timed out.
*/
private void processException( Exception e ) {
if ( e instanceof DebugException ) {
Throwable t = getExceptionCause( e );
Assert.assertTrue(
Throwable t = getExceptionCause( e );
Assert.assertTrue(
"Unexpected exception",
t instanceof CoreException && ((CoreException)t).getStatus().getCode() == 20100 );
}
else {
Assert.fail( "Unexpected exception type" );
}
}
private Throwable getExceptionCause(Throwable e) {
Throwable current = e;
while ( current instanceof CoreException ) {
Throwable t = ((CoreException)current).getCause();
while ( true ) {
Throwable t = (current).getCause();
if ( t == null )
break;
current = t;

View file

@ -11,6 +11,8 @@
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.gdb.tests;
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
public interface ITestConstants {
public static final String SUFFIX_GDB_6_6 = "6.6";
@ -25,4 +27,7 @@ public interface ITestConstants {
public static final String SUFFIX_GDB_7_6 = "7.6";
public static final String SUFFIX_GDB_7_7 = "7.7";
public static final String SUFFIX_GDB_7_8 = "7.8";
// Attribute that allows a test to request not to start gdbserver even if the session is a remote one
public static final String LAUNCH_GDB_SERVER = TestsPlugin.PLUGIN_ID + ".launchGdbServer";
}