1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 01:15:29 +02:00

Add JUnit test to verify a query is answered as expected.

Change-Id: I603a89822e1fcbb1e7126150fd8e4de17fd7a141
This commit is contained in:
Marc Khouzam 2017-01-23 11:35:43 -05:00 committed by Gerrit Code Review @ Eclipse.org
parent 5fd108cd66
commit d941a275b4
3 changed files with 234 additions and 24 deletions

View file

@ -126,20 +126,24 @@ public class SyncUtil {
}
public static MIStoppedEvent step(int numSteps, StepType stepType) throws Throwable {
return step(numSteps,stepType, false);
}
public static MIStoppedEvent step(int numSteps, StepType stepType, boolean reverse) throws Throwable {
MIStoppedEvent retVal = null;
for (int i=0; i<numSteps; i++) {
retVal = step(stepType, DefaultTimeouts.get(ETimeout.step));
retVal = step(stepType, reverse, DefaultTimeouts.get(ETimeout.step));
}
return retVal;
}
public static MIStoppedEvent step(StepType stepType) throws Throwable {
return step(stepType, DefaultTimeouts.get(ETimeout.step));
return step(stepType, false, DefaultTimeouts.get(ETimeout.step));
}
public static MIStoppedEvent step(StepType stepType, int massagedTimeout) throws Throwable {
public static MIStoppedEvent step(StepType stepType, boolean reverse, int massagedTimeout) throws Throwable {
IContainerDMContext containerDmc = SyncUtil.getContainerContext();
return step(containerDmc, stepType, massagedTimeout);
return step(containerDmc, stepType, reverse, massagedTimeout);
}
public static MIStoppedEvent step(IExecutionDMContext dmc, StepType stepType) throws Throwable {
@ -147,32 +151,58 @@ public class SyncUtil {
}
public static MIStoppedEvent step(final IExecutionDMContext dmc, final StepType stepType, int massagedTimeout) throws Throwable {
return step(dmc, stepType, false, massagedTimeout);
}
public static MIStoppedEvent step(final IExecutionDMContext dmc, final StepType stepType, boolean reverse, int massagedTimeout) throws Throwable {
final ServiceEventWaitor<MIStoppedEvent> eventWaitor =
new ServiceEventWaitor<MIStoppedEvent>(
fSession,
MIStoppedEvent.class);
fRunControl.getExecutor().submit(new Runnable() {
@Override
public void run() {
// No need for a RequestMonitor since we will wait for the
// ServiceEvent telling us the program has been suspended again
switch(stepType) {
case STEP_INTO:
fGdbControl.queueCommand(fCommandFactory.createMIExecStep(dmc), null);
break;
case STEP_OVER:
fGdbControl.queueCommand(fCommandFactory.createMIExecNext(dmc), null);
break;
case STEP_RETURN:
fGdbControl.queueCommand(fCommandFactory.createMIExecFinish(fStack.createFrameDMContext(dmc, 0)), null);
break;
default:
fail("Unsupported step type; " + stepType.toString());
if (!reverse) {
fRunControl.getExecutor().submit(new Runnable() {
@Override
public void run() {
// No need for a RequestMonitor since we will wait for the
// ServiceEvent telling us the program has been suspended again
switch(stepType) {
case STEP_INTO:
fGdbControl.queueCommand(fCommandFactory.createMIExecStep(dmc), null);
break;
case STEP_OVER:
fGdbControl.queueCommand(fCommandFactory.createMIExecNext(dmc), null);
break;
case STEP_RETURN:
fGdbControl.queueCommand(fCommandFactory.createMIExecFinish(fStack.createFrameDMContext(dmc, 0)), null);
break;
default:
fail("Unsupported step type; " + stepType.toString());
}
}
}
});
});
} else {
fRunControl.getExecutor().submit(new Runnable() {
@Override
public void run() {
// No need for a RequestMonitor since we will wait for the
// ServiceEvent telling us the program has been suspended again
switch(stepType) {
case STEP_INTO:
fGdbControl.queueCommand(fCommandFactory.createMIExecReverseStep(dmc), null);
break;
case STEP_OVER:
fGdbControl.queueCommand(fCommandFactory.createMIExecReverseNext(dmc), null);
break;
case STEP_RETURN:
fGdbControl.queueCommand(fCommandFactory.createMIExecUncall(fStack.createFrameDMContext(dmc, 0)), null);
break;
default:
fail("Unsupported step type; " + stepType.toString());
}
}
});
}
// Wait for the execution to suspend after the step
return eventWaitor.waitForEvent(massagedTimeout);

View file

@ -0,0 +1,179 @@
/*******************************************************************************
* Copyright (c) 2017 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
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.gdb.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
import org.eclipse.cdt.dsf.gdb.service.IReverseRunControl;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MILogStreamOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase;
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil;
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
/**
* Tests MIRunControl class for some reverse debugging scenarios.
*/
@RunWith(Parameterized.class)
public class MIRunControlReverseTest extends BaseParametrizedTestCase {
private DsfServicesTracker fServicesTracker;
private DsfSession fSession;
private IGDBControl fGDBCtrl;
private IMIRunControl fRunCtrl;
private IExpressions fExpressions;
/*
* Name of the executable
*/
private static final String EXEC_NAME = "ExpressionTestApp.exe";
@Override
public void doBeforeTest() throws Exception {
assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_7_0);
super.doBeforeTest();
fSession = getGDBLaunch().getSession();
Runnable runnable = new Runnable() {
@Override
public void run() {
fServicesTracker =
new DsfServicesTracker(TestsPlugin.getBundleContext(),
fSession.getId());
fGDBCtrl = fServicesTracker.getService(IGDBControl.class);
fRunCtrl = fServicesTracker.getService(IMIRunControl.class);
fExpressions = fServicesTracker.getService(IExpressions.class);
}
};
fSession.getExecutor().submit(runnable).get();
}
@Override
public void doAfterTest() throws Exception {
super.doAfterTest();
if (fServicesTracker != null) {
fServicesTracker.dispose();
}
}
@Override
protected void setLaunchAttributes() {
super.setLaunchAttributes();
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME,
EXEC_PATH + EXEC_NAME);
}
/**
* This test verifies that we properly handle a query sent from GDB.
* When running the basic console (GDB < 7.12) GDB answer's the query itself
* and so we should not answer again. When using the full Console, GDB does
* not answer so we must answer ourselves. When using the full console
* we have both an MI and a CLI channel open; this test verifies how
* we react to getting query on the MI-only channel, which is actually
* not something GDB should do, but at least in 7.12, it does happen.
*/
@Test
public void testQueryHandling() throws Throwable {
SyncUtil.runToLocation("testLocals");
assertTrue("Reverse debugging is not supported", fRunCtrl instanceof IReverseRunControl);
final IReverseRunControl reverseService = (IReverseRunControl)fRunCtrl;
Query<Boolean> query = new Query<Boolean>() {
@Override
protected void execute(final DataRequestMonitor<Boolean> rm) {
reverseService.enableReverseMode(fGDBCtrl.getContext(), true,
new ImmediateRequestMonitor(rm) {
@Override
protected void handleSuccess() {
reverseService.isReverseModeEnabled(fGDBCtrl.getContext(), rm);
}
});
}
};
fSession.getExecutor().execute(query);
Boolean enabled = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS);
assertTrue("Reverse debugging should be enabled", enabled);
// Step forward a couple of times
SyncUtil.step(2, StepType.STEP_OVER);
// Step back once to start using the record buffer
MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER, true);
IExpressionDMContext expr = SyncUtil.createExpression(stoppedEvent.getDMContext(), "lIntVar");
// Register an event listener to check that we don't send out a 'y'
// command when we don't need to.
boolean yesCommandSent[] = new boolean[1];
yesCommandSent[0] = false;
fGDBCtrl.addEventListener(new IEventListener() {
@Override
public void eventReceived(Object output) {
for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) {
if (oobr instanceof MILogStreamOutput) {
MILogStreamOutput stream = (MILogStreamOutput) oobr;
if (stream.getCString().indexOf("Undefined command: \"y") != -1) {
yesCommandSent[0] = true;
}
}
}
}
});
String newValue = "8989";
// Now modify a variable to trigger the query as we are modifying a recorded value
Query<Void> writeQuery = new Query<Void>() {
@Override
protected void execute(final DataRequestMonitor<Void> rm) {
fExpressions.writeExpression(expr, newValue, IFormattedValues.DECIMAL_FORMAT, rm);
}
};
fSession.getExecutor().execute(writeQuery);
try {
writeQuery.get(TestsPlugin.massageTimeout(2000), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
assert false : "Timed-out waiting to write to a variable, probably because of a query.";
}
// Now verify that the write work and that GDB is answering
String value = SyncUtil.getExpressionValue(expr, IFormattedValues.DECIMAL_FORMAT);
assertEquals("Value was not writtent to variable", newValue, value);
assertTrue("Sent a 'y' command unnecessarily", !yesCommandSent[0]); //$NON-NLS-1$
}
}

View file

@ -43,6 +43,7 @@ import org.junit.runners.Suite;
OperationsWhileTargetIsRunningTest.class,
MIRunControlTest.class,
MIRunControlTargetAvailableTest.class,
MIRunControlReverseTest.class,
GDBPatternMatchingExpressionsTest.class,
GDBMultiNonStopRunControlTest.class,
GDBConsoleBreakpointsTest.class,