GP-829: Removing processContainer concept from tests.

This commit is contained in:
Dan 2021-04-13 13:29:14 -04:00
parent 3b058380a3
commit 1a3458ef7c
36 changed files with 218 additions and 330 deletions

View file

@ -26,6 +26,7 @@ import ghidra.dbg.target.schema.EnumerableTargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.PathUtils;
import ghidra.lifecycle.Internal;
import ghidra.util.Msg;
import ghidra.util.datastruct.ListenerSet;
/**
@ -245,8 +246,13 @@ public abstract class AbstractTargetObject<P extends TargetObject> implements Sp
valid = false;
model.objectInvalidated(getProxy());
listeners.fire.invalidated(getProxy(), branch, reason);
listeners.clear();
listeners.clearChained();
CompletableFuture.runAsync(() -> {
listeners.clear();
listeners.clearChained();
}, model.clientExecutor).exceptionally(ex -> {
Msg.error(this, "Error emptying invalidated object's listener set: ", ex);
return null;
});
}
protected void doInvalidateElements(Map<String, ?> elems, String reason) {

View file

@ -16,7 +16,8 @@
package ghidra.dbg.test;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
@ -33,7 +34,6 @@ import ghidra.dbg.error.DebuggerIllegalArgumentException;
import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
import ghidra.dbg.testutil.ElementTrackingListener;
import ghidra.program.model.address.AddressFactory;
public abstract class AbstractDebuggerModelAttacherTest extends AbstractDebuggerModelTest
@ -47,10 +47,6 @@ public abstract class AbstractDebuggerModelAttacherTest extends AbstractDebugger
return null;
}
public List<String> getExpectedProcessesContainerPath() {
return null;
}
public abstract TargetParameterMap getExpectedAttachParameters();
public abstract void assertEnvironment(TargetEnvironment environment);
@ -65,16 +61,6 @@ public abstract class AbstractDebuggerModelAttacherTest extends AbstractDebugger
assertEquals(expectedAttacherPath, attacher.getPath());
}
@Test
public void testProcessContainerIsWhereExpected() throws Throwable {
List<String> expectedProcessContainerPath = getExpectedProcessesContainerPath();
assumeNotNull(expectedProcessContainerPath);
m.build();
TargetObject container = findProcessContainer();
assertEquals(expectedProcessContainerPath, container.getPath());
}
@Test
public void testAttachableContainerIsWhereExpected() throws Throwable {
List<String> expectedAttachableContainerPath = getExpectedAttachableContainerPath();
@ -195,12 +181,12 @@ public abstract class AbstractDebuggerModelAttacherTest extends AbstractDebugger
runTestAttachByObjBogusThrowsException(attacher);
}
protected void runTestAttachByPidThenDetach(TargetAttacher attacher, TargetObject container)
protected void runTestAttachByPidThenDetach(TargetAttacher attacher)
throws Throwable {
DebuggerTestSpecimen specimen = getAttachSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
runTestAttachByPid(attacher);
runTestDetach(container, specimen);
runTestDetach(specimen);
assertTrue(dummy.process.isAlive());
}
@ -212,16 +198,15 @@ public abstract class AbstractDebuggerModelAttacherTest extends AbstractDebugger
dummy = specimen.runDummy();
TargetAttacher attacher = findAttacher();
TargetObject container = findProcessContainer();
runTestAttachByPidThenDetach(attacher, container);
runTestAttachByPidThenDetach(attacher);
}
protected void runTestAttachByPidThenKill(TargetAttacher attacher, TargetObject container)
protected void runTestAttachByPidThenKill(TargetAttacher attacher)
throws Throwable {
DebuggerTestSpecimen specimen = getAttachSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
runTestAttachByPid(attacher);
runTestKill(container, specimen);
runTestKill(specimen);
retryVoid(() -> assertFalse(dummy.process.isAlive()), List.of(AssertionError.class));
}
@ -233,16 +218,14 @@ public abstract class AbstractDebuggerModelAttacherTest extends AbstractDebugger
dummy = specimen.runDummy();
TargetAttacher attacher = findAttacher();
TargetObject container = findProcessContainer();
runTestAttachByPidThenKill(attacher, container);
runTestAttachByPidThenKill(attacher);
}
protected void runTestAttachByPidThenResumeInterrupt(TargetAttacher attacher,
TargetObject container) throws Throwable {
protected void runTestAttachByPidThenResumeInterrupt(TargetAttacher attacher) throws Throwable {
DebuggerTestSpecimen specimen = getAttachSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
runTestAttachByPid(attacher);
runTestResumeInterruptMany(container, specimen, 3);
runTestResumeInterruptMany(specimen, 3);
assertTrue(dummy.process.isAlive());
}
@ -254,16 +237,14 @@ public abstract class AbstractDebuggerModelAttacherTest extends AbstractDebugger
dummy = specimen.runDummy();
TargetAttacher attacher = findAttacher();
TargetObject container = findProcessContainer();
runTestAttachByPidThenResumeInterrupt(attacher, container);
runTestAttachByPidThenResumeInterrupt(attacher);
}
protected void runTestAttachShowsInProcessContainer(TargetAttacher attacher,
TargetObject container) throws Throwable {
protected void runTestAttachShowsInProcessContainer(TargetAttacher attacher) throws Throwable {
DebuggerTestSpecimen specimen = getAttachSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
runTestAttachByPid(attacher);
retryForProcessRunning(container, specimen, this);
retryForProcessRunning(specimen, this);
}
@Test
@ -274,36 +255,6 @@ public abstract class AbstractDebuggerModelAttacherTest extends AbstractDebugger
dummy = specimen.runDummy();
TargetAttacher attacher = findAttacher();
TargetObject container = findProcessContainer();
runTestAttachShowsInProcessContainer(attacher, container);
}
protected void runTestAttachShowsInProcessContainerViaListener(TargetAttacher attacher,
TargetObject container) throws Throwable {
DebuggerTestSpecimen specimen = getAttachSpecimen();
ElementTrackingListener<? extends TargetProcess> procListener =
new ElementTrackingListener<>(TargetProcess.class);
container.addListener(procListener);
// NB. Have to express interest, otherwise model is not obligated to invoke listener
Collection<TargetProcess> procsBefore = fetchProcesses(container);
procListener.putAll(container.getCachedElements());
assertNull(getProcessRunning(procsBefore, specimen, this));
runTestAttachByPid(attacher);
retryVoid(() -> {
// Cannot fetch elements. rely only on listener.
assertNotNull(getProcessRunning(procListener.elements.values(), specimen, this));
}, List.of(AssertionError.class));
}
@Test
public void testAttachShowsInProcessContainerViaListener() throws Throwable {
DebuggerTestSpecimen specimen = getAttachSpecimen();
assumeTrue(m.hasProcessContainer());
m.build();
dummy = specimen.runDummy();
TargetAttacher attacher = findAttacher();
TargetObject container = findProcessContainer();
runTestAttachShowsInProcessContainerViaListener(attacher, container);
runTestAttachShowsInProcessContainer(attacher);
}
}

View file

@ -16,7 +16,8 @@
package ghidra.dbg.test;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import java.util.*;
import java.util.Map.Entry;
@ -38,18 +39,16 @@ import ghidra.util.Msg;
* Tests the functionality of breakpoints
*
* <p>
* Note that this test does not check for nuances regarding specification vs.
* location, as it is meant to generalize across models for interests of the UI
* only. As such, we only test that we can set breakpoints at given addresses
* and that a location manifests there, regardless of the intervening
* mechanisms. We also test some basic operations on the breakpoint (location)
* itself. Models which have separate specifications from locations, or for
* which you want to test non-address specifications will need to add their own
* tests, tailored to the semantics of that model's breakpoint specifications.
* Note that this test does not check for nuances regarding specification vs. location, as it is
* meant to generalize across models for interests of the UI only. As such, we only test that we can
* set breakpoints at given addresses and that a location manifests there, regardless of the
* intervening mechanisms. We also test some basic operations on the breakpoint (location) itself.
* Models which have separate specifications from locations, or for which you want to test
* non-address specifications will need to add their own tests, tailored to the semantics of that
* model's breakpoint specifications.
*
* <p>
* TODO: Enable, disable (if supported), delete (if supported), manipulation via
* CLI is synced
* TODO: Enable, disable (if supported), delete (if supported), manipulation via CLI is synced
*/
public abstract class AbstractDebuggerModelBreakpointsTest extends AbstractDebuggerModelTest
implements RequiresTarget {
@ -225,7 +224,7 @@ public abstract class AbstractDebuggerModelBreakpointsTest extends AbstractDebug
waitOn(container.placeBreakpoint(range, Set.of(kind)));
retryVoid(() -> {
Collection<? extends TargetBreakpointLocation> found =
m.findAll(TargetBreakpointLocation.class, target.getPath()).values();
m.findAll(TargetBreakpointLocation.class, target.getPath(), true).values();
assertAtLeastOneLocCovers(found, range, kind);
}, List.of(AssertionError.class));
}
@ -261,7 +260,7 @@ public abstract class AbstractDebuggerModelBreakpointsTest extends AbstractDebug
waitOn(container.placeBreakpoint(range, Set.of(kind)));
locs.add(retry(() -> {
Collection<? extends TargetBreakpointLocation> found =
m.findAll(TargetBreakpointLocation.class, target.getPath()).values();
m.findAll(TargetBreakpointLocation.class, target.getPath(), true).values();
return assertAtLeastOneLocCovers(found, range, kind);
}, List.of(AssertionError.class)));
}

View file

@ -27,6 +27,10 @@ import ghidra.dbg.target.TargetFocusScope;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.util.PathUtils;
/**
* TODO: Since activation and focus are separate concepts, we need to fix the terminology here and
* ensure we're testing the right things.
*/
public abstract class AbstractDebuggerModelFocusTest extends AbstractDebuggerModelTest {
/**

View file

@ -15,9 +15,10 @@
*/
package ghidra.dbg.test;
import static ghidra.lifecycle.Unfinished.*;
import static ghidra.lifecycle.Unfinished.TODO;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import java.util.List;
import java.util.stream.Collectors;
@ -27,23 +28,39 @@ import org.junit.Ignore;
import org.junit.Test;
import ghidra.async.AsyncReference;
import ghidra.dbg.DebugModelConventions;
import ghidra.dbg.DebuggerModelListener;
import ghidra.dbg.error.DebuggerModelTerminatingException;
import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetConsole.Channel;
import ghidra.dbg.target.TargetInterpreter;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.testutil.CatchOffThread;
import ghidra.util.Msg;
public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebuggerModelTest
implements RequiresAttachSpecimen, RequiresLaunchSpecimen {
/**
* Get the path of the expected result of {@link #findInterpreter()} for this test
*
* @return the expected path
*/
public List<String> getExpectedInterpreterPath() {
return null;
}
/**
* Get the CLI command to echo a string back
*
* @param msg the message to echo
* @return the command
*/
protected abstract String getEchoCommand(String msg);
/**
* If applicable, get the CLI command to terminate the session / model
*
* @return the command
*/
protected abstract String getQuitCommand();
/**
@ -53,6 +70,30 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug
*/
protected abstract String getAttachCommand();
/**
* Get the CLI command to detach from the given process
*
* <p>
* Note that the given process should already be the current/active process of the interpreter,
* so the parameter may not be needed.
*
* @param process the process to detach from, which should already be active
* @return the command
*/
protected abstract String getDetachCommand(TargetProcess process);
/**
* Get the CLI command to kill the given process
*
* <p>
* Note that the given process should already be the current/active process of the interpreter,
* so the parameter may not be needed.
*
* @param process the process to kill, which should already be active
* @return the command
*/
protected abstract String getKillCommand(TargetProcess process);
@Test
public void testInterpreterIsWhereExpected() throws Throwable {
List<String> expectedInterpreterPath = getExpectedInterpreterPath();
@ -126,6 +167,11 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug
runTestExecuteCapture(interpreter, cmd);
}
/**
* Test that the user quitting via the CLI properly terminates the model
*
* @throws Throwable expected since the model will terminate
*/
@Test(expected = DebuggerModelTerminatingException.class)
public void testExecuteQuit() throws Throwable {
String cmd = getQuitCommand();
@ -151,14 +197,22 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug
// TODO: Delete (spec vs. loc?)
}
protected void runTestLaunchViaInterpreterShowsInProcessContainer(TargetInterpreter interpreter,
TargetObject container) throws Throwable {
protected TargetProcess runTestLaunchViaInterpreterShowsInProcessContainer(
TargetInterpreter interpreter) throws Throwable {
DebuggerTestSpecimen specimen = getLaunchSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
for (String line : specimen.getLaunchScript()) {
waitOn(interpreter.execute(line));
}
retryForProcessRunning(container, specimen, this);
return retryForProcessRunning(specimen, this);
}
protected void runTestKillViaInterpreter(TargetProcess process, TargetInterpreter interpreter)
throws Throwable {
waitOn(interpreter.execute(getKillCommand(process)));
retryVoid(() -> {
assertFalse(DebugModelConventions.isProcessAlive(process));
}, List.of(AssertionError.class));
}
@Test
@ -167,18 +221,26 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug
m.build();
TargetInterpreter interpreter = findInterpreter();
TargetObject container = findProcessContainer();
assertNotNull("No process container", container);
runTestLaunchViaInterpreterShowsInProcessContainer(interpreter, container);
TargetProcess process = runTestLaunchViaInterpreterShowsInProcessContainer(interpreter);
runTestKillViaInterpreter(process, interpreter);
}
protected void runTestAttachViaInterpreterShowsInProcessContainer(TargetInterpreter interpreter,
TargetObject container) throws Throwable {
protected TargetProcess runTestAttachViaInterpreterShowsInProcessContainer(
TargetInterpreter interpreter) throws Throwable {
DebuggerTestSpecimen specimen = getAttachSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
String cmd = getAttachCommand();
waitOn(interpreter.execute(cmd));
retryForProcessRunning(container, specimen, this);
return retryForProcessRunning(specimen, this);
}
protected void runTestDetachViaInterpreter(TargetProcess process, TargetInterpreter interpreter)
throws Throwable {
waitOn(interpreter.execute(getDetachCommand(process)));
retryVoid(() -> {
assertFalse(DebugModelConventions.isProcessAlive(process));
}, List.of(AssertionError.class));
}
@Test
@ -189,8 +251,8 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug
dummy = specimen.runDummy();
TargetInterpreter interpreter = findInterpreter();
TargetObject container = findProcessContainer();
assertNotNull("No process container", container);
runTestAttachViaInterpreterShowsInProcessContainer(interpreter, container);
TargetProcess process = runTestAttachViaInterpreterShowsInProcessContainer(interpreter);
runTestDetachViaInterpreter(process, interpreter);
}
}

View file

@ -15,12 +15,12 @@
*/
package ghidra.dbg.test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@ -31,7 +31,6 @@ import ghidra.dbg.DebugModelConventions;
import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
import ghidra.dbg.testutil.ElementTrackingListener;
public abstract class AbstractDebuggerModelLauncherTest extends AbstractDebuggerModelTest
implements RequiresLaunchSpecimen {
@ -40,10 +39,6 @@ public abstract class AbstractDebuggerModelLauncherTest extends AbstractDebugger
return null;
}
public List<String> getExpectedProcessesContainerPath() {
return null;
}
public abstract TargetParameterMap getExpectedLauncherParameters();
public abstract void assertEnvironment(TargetEnvironment environment);
@ -58,16 +53,6 @@ public abstract class AbstractDebuggerModelLauncherTest extends AbstractDebugger
assertEquals(expectedLauncherPath, launcher.getPath());
}
@Test
public void testProcessContainerIsWhereExpected() throws Throwable {
List<String> expectedProcessContainerPath = getExpectedProcessesContainerPath();
assumeNotNull(expectedProcessContainerPath);
m.build();
TargetObject container = findProcessContainer();
assertEquals(expectedProcessContainerPath, container.getPath());
}
protected void runTestLaunchParameters(TargetLauncher launcher,
TargetParameterMap expectedParameters) throws Throwable {
waitAcc(launcher);
@ -123,12 +108,11 @@ public abstract class AbstractDebuggerModelLauncherTest extends AbstractDebugger
waitOn(listener.observedCreated);
}
protected void runTestLaunchThenDetach(TargetLauncher launcher,
TargetObject container) throws Throwable {
protected void runTestLaunchThenDetach(TargetLauncher launcher) throws Throwable {
DebuggerTestSpecimen specimen = getLaunchSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
runTestLaunch(launcher);
runTestDetach(container, specimen);
runTestDetach(specimen);
}
@Test
@ -137,16 +121,14 @@ public abstract class AbstractDebuggerModelLauncherTest extends AbstractDebugger
m.build();
TargetLauncher launcher = findLauncher();
TargetObject container = findProcessContainer();
runTestLaunchThenDetach(launcher, container);
runTestLaunchThenDetach(launcher);
}
protected void runTestLaunchThenKill(TargetLauncher launcher,
TargetObject container) throws Throwable {
protected void runTestLaunchThenKill(TargetLauncher launcher) throws Throwable {
DebuggerTestSpecimen specimen = getLaunchSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
runTestLaunch(launcher);
runTestKill(container, specimen);
runTestKill(specimen);
}
@Test
@ -155,16 +137,14 @@ public abstract class AbstractDebuggerModelLauncherTest extends AbstractDebugger
m.build();
TargetLauncher launcher = findLauncher();
TargetObject container = findProcessContainer();
runTestLaunchThenKill(launcher, container);
runTestLaunchThenKill(launcher);
}
protected void runTestLaunchThenResume(TargetLauncher launcher,
TargetObject container) throws Throwable {
protected void runTestLaunchThenResume(TargetLauncher launcher) throws Throwable {
DebuggerTestSpecimen specimen = getLaunchSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
runTestLaunch(launcher);
runTestResumeTerminates(container, specimen);
runTestResumeTerminates(specimen);
}
@Test
@ -173,16 +153,14 @@ public abstract class AbstractDebuggerModelLauncherTest extends AbstractDebugger
m.build();
TargetLauncher launcher = findLauncher();
TargetObject container = findProcessContainer();
runTestLaunchThenResume(launcher, container);
runTestLaunchThenResume(launcher);
}
protected void runTestLaunchShowsInProcessContainer(TargetLauncher launcher,
TargetObject container) throws Throwable {
protected void runTestLaunchShowsInProcessContainer(TargetLauncher launcher) throws Throwable {
DebuggerTestSpecimen specimen = getLaunchSpecimen();
assertNull(getProcessRunning(container, specimen, this));
assertNull(getProcessRunning(specimen, this));
runTestLaunch(launcher);
retryForProcessRunning(container, specimen, this);
retryForProcessRunning(specimen, this);
}
@Test
@ -191,34 +169,6 @@ public abstract class AbstractDebuggerModelLauncherTest extends AbstractDebugger
m.build();
TargetLauncher launcher = findLauncher();
TargetObject container = findProcessContainer();
runTestLaunchShowsInProcessContainer(launcher, container);
}
protected void runTestLaunchShowsInProcessContainerViaListener(
TargetLauncher launcher, TargetObject container) throws Throwable {
DebuggerTestSpecimen specimen = getLaunchSpecimen();
ElementTrackingListener<? extends TargetProcess> procListener =
new ElementTrackingListener<>(TargetProcess.class);
container.addListener(procListener);
// NB. Have to express interest, otherwise model is not obligated to invoke listener
Collection<TargetProcess> procsBefore = fetchProcesses(container);
procListener.putAll(container.getCachedElements());
assertNull(getProcessRunning(procsBefore, specimen, this));
runTestLaunch(launcher);
retryVoid(() -> {
// Cannot fetch elements. rely only on listener.
assertNotNull(getProcessRunning(procListener.elements.values(), specimen, this));
}, List.of(AssertionError.class));
}
@Test
public void testLaunchShowsInProcessContainerViaListener() throws Throwable {
assumeTrue(m.hasProcessContainer());
m.build();
TargetLauncher launcher = findLauncher();
TargetObject container = findProcessContainer();
runTestLaunchShowsInProcessContainerViaListener(launcher, container);
runTestLaunchShowsInProcessContainer(launcher);
}
}

View file

@ -15,7 +15,8 @@
*/
package ghidra.dbg.test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.lang.invoke.MethodHandles;
import java.util.*;
@ -131,14 +132,12 @@ public abstract class AbstractDebuggerModelScenarioCloneExitTest extends Abstrac
Msg.debug(this, "Launching " + specimen);
waitOn(launcher.launch(specimen.getLauncherArgs()));
Msg.debug(this, " Done launching");
TargetObject processContainer = findProcessContainer();
assertNotNull("No process container", processContainer);
TargetProcess process = retryForProcessRunning(processContainer, specimen, this);
TargetProcess process = retryForProcessRunning(specimen, this);
postLaunch(process);
TargetBreakpointSpecContainer breakpointContainer =
TargetBreakpointSpecContainer bpContainer =
findBreakpointSpecContainer(process.getPath());
Msg.debug(this, "Placing breakpoint");
waitOn(breakpointContainer.placeBreakpoint(getBreakpointExpression(),
waitOn(bpContainer.placeBreakpoint(getBreakpointExpression(),
Set.of(TargetBreakpointKind.SW_EXECUTE)));
assertTrue(DebugModelConventions.isProcessAlive(process));

View file

@ -182,8 +182,6 @@ public abstract class AbstractDebuggerModelScenarioForkExitTest extends Abstract
Msg.debug(this, "Launching " + specimen);
waitOn(launcher.launch(specimen.getLauncherArgs()));
Msg.debug(this, " Done launching");
TargetObject processContainer = findProcessContainer();
assertNotNull("No process container", processContainer);
TargetProcess parentProcess = waitOn(stateMonitor.observedParent);
Msg.debug(this, "Parent is " + parentProcess.getJoinedPath("."));
postLaunch(parentProcess);
@ -201,7 +199,7 @@ public abstract class AbstractDebuggerModelScenarioForkExitTest extends Abstract
Msg.debug(this, " Done " + i);
waitAcc(access(parentProcess));
try {
childProcess = retryForOtherProcessRunning(processContainer, specimen, this,
childProcess = retryForOtherProcessRunning(specimen, this,
p -> p != parentProcess, WAIT_FOR_CHILD_MS);
}
catch (AssertionError e) {

View file

@ -141,8 +141,7 @@ public abstract class AbstractDebuggerModelScenarioMemoryTest extends AbstractDe
Msg.debug(this, "Launching " + specimen);
waitOn(launcher.launch(specimen.getLauncherArgs()));
Msg.debug(this, " Done launching");
TargetObject processContainer = findProcessContainer();
TargetProcess process = retryForProcessRunning(processContainer, specimen, this);
TargetProcess process = retryForProcessRunning(specimen, this);
postLaunch(process);
Address address = Objects.requireNonNull(getAddressToWrite(process));

View file

@ -15,7 +15,6 @@
*/
package ghidra.dbg.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.lang.invoke.MethodHandles;
@ -138,9 +137,7 @@ public abstract class AbstractDebuggerModelScenarioRegistersTest extends Abstrac
Msg.debug(this, "Launching " + specimen);
waitOn(launcher.launch(specimen.getLauncherArgs()));
Msg.debug(this, " Done launching");
TargetObject processContainer = findProcessContainer();
assertNotNull(processContainer);
TargetProcess process = retryForProcessRunning(processContainer, specimen, this);
TargetProcess process = retryForProcessRunning(specimen, this);
postLaunch(process);
TargetBreakpointSpecContainer breakpointContainer =

View file

@ -122,8 +122,7 @@ public abstract class AbstractDebuggerModelScenarioStackTest extends AbstractDeb
TargetLauncher launcher = findLauncher();
waitOn(launcher.launch(specimen.getLauncherArgs()));
Msg.debug(this, " Done launching");
TargetObject processContainer = findProcessContainer();
TargetProcess process = retryForProcessRunning(processContainer, specimen, this);
TargetProcess process = retryForProcessRunning(specimen, this);
postLaunch(process);
TargetBreakpointSpecContainer breakpointContainer =
@ -157,7 +156,7 @@ public abstract class AbstractDebuggerModelScenarioStackTest extends AbstractDeb
// Sort by path should present them innermost to outermost
List<TargetStackFrame> frames = retry(() -> {
List<TargetStackFrame> result =
List.copyOf(m.findAll(TargetStackFrame.class, stack.getPath()).values());
List.copyOf(m.findAll(TargetStackFrame.class, stack.getPath(), true).values());
assertTrue("Fewer than 4 frames", result.size() > 4);
return result;
}, List.of(AssertionError.class));

View file

@ -85,19 +85,6 @@ public abstract class AbstractDebuggerModelTest extends AbstractGhidraHeadlessIn
return m.find(TargetLauncher.class, seedPath());
}
/**
* Get the process container under test
*
* <p>
* This can be overridden to force a different object under the test.
*
* @return the process container
* @throws Throwable if anything goes wrong
*/
protected TargetObject findProcessContainer() throws Throwable {
return m.findContainer(TargetProcess.class, seedPath());
}
/**
* Get the breakpoint container of a target under test
*
@ -285,9 +272,9 @@ public abstract class AbstractDebuggerModelTest extends AbstractGhidraHeadlessIn
return waitOn(listener.trapped);
}
protected void runTestDetach(TargetObject container, DebuggerTestSpecimen specimen)
protected void runTestDetach(DebuggerTestSpecimen specimen)
throws Throwable {
TargetProcess process = retryForProcessRunning(container, specimen, this);
TargetProcess process = retryForProcessRunning(specimen, this);
TargetDetachable detachable = m.suitable(TargetDetachable.class, process.getPath());
waitAcc(detachable);
waitOn(detachable.detach());
@ -295,9 +282,9 @@ public abstract class AbstractDebuggerModelTest extends AbstractGhidraHeadlessIn
List.of(AssertionError.class));
}
protected void runTestKill(TargetObject container, DebuggerTestSpecimen specimen)
protected void runTestKill(DebuggerTestSpecimen specimen)
throws Throwable {
TargetProcess process = retryForProcessRunning(container, specimen, this);
TargetProcess process = retryForProcessRunning(specimen, this);
TargetKillable killable = m.suitable(TargetKillable.class, process.getPath());
waitAcc(killable);
waitOn(killable.kill());
@ -305,9 +292,8 @@ public abstract class AbstractDebuggerModelTest extends AbstractGhidraHeadlessIn
List.of(AssertionError.class));
}
protected void runTestResumeTerminates(TargetObject container, DebuggerTestSpecimen specimen)
throws Throwable {
TargetProcess process = retryForProcessRunning(container, specimen, this);
protected void runTestResumeTerminates(DebuggerTestSpecimen specimen) throws Throwable {
TargetProcess process = retryForProcessRunning(specimen, this);
TargetResumable resumable = m.suitable(TargetResumable.class, process.getPath());
AsyncState state =
new AsyncState(m.suitable(TargetExecutionStateful.class, process.getPath()));
@ -318,9 +304,9 @@ public abstract class AbstractDebuggerModelTest extends AbstractGhidraHeadlessIn
List.of(AssertionError.class));
}
protected void runTestResumeInterruptMany(TargetObject container, DebuggerTestSpecimen specimen,
protected void runTestResumeInterruptMany(DebuggerTestSpecimen specimen,
int repetitions) throws Throwable {
TargetProcess process = retryForProcessRunning(container, specimen, this);
TargetProcess process = retryForProcessRunning(specimen, this);
TargetResumable resumable = m.suitable(TargetResumable.class, process.getPath());
TargetInterruptible interruptible =
m.suitable(TargetInterruptible.class, process.getPath());
@ -342,6 +328,6 @@ public abstract class AbstractDebuggerModelTest extends AbstractGhidraHeadlessIn
}, List.of(AssertionError.class));
}
}
waitOn(container.getModel().ping("Are you still there?"));
waitOn(m.getModel().ping("Are you still there?"));
}
}

View file

@ -206,16 +206,20 @@ public abstract class AbstractModelHost implements ModelHost, DebuggerModelTestU
@Override
public <T extends TargetObject> NavigableMap<List<String>, T> findAll(Class<T> cls,
List<String> seedPath) throws Throwable {
List<String> seedPath, boolean atLeastOne) throws Throwable {
PathMatcher matcher =
model.getRootSchema().getSuccessorSchema(seedPath).searchFor(cls, seedPath, false);
if (matcher.isEmpty()) {
return new TreeMap<>();
}
NavigableMap<List<String>, ?> found = atLeastOne
? waitOn(waiter.waitAtLeastOne(matcher))
: matcher.getCachedValues(model.getModelRoot());
// NB. Outside of testing, an "unsafe" cast of the map should be fine.
// During testing, we should expend the energy to verify the heap.
NavigableMap<List<String>, T> result = new TreeMap<>(PathComparator.KEYED);
for (Entry<List<String>, ?> ent : waitOn(waiter.waitAtLeastOne(matcher)).entrySet()) {
for (Entry<List<String>, ?> ent : found.entrySet()) {
result.put(ent.getKey(), cls.cast(ent.getValue()));
}
return result;

View file

@ -29,12 +29,11 @@ public interface ProvidesTargetViaAttachSpecimen extends RequiresTarget, Require
@Override
default TargetObject obtainTarget() throws Throwable {
TargetAttacher attacher = getTest().findAttacher();
TargetObject container = getTest().findProcessContainer();
DebuggerTestSpecimen specimen = getAttachSpecimen();
waitAcc(attacher);
DummyProc dummy = specimen.runDummy();
setDummy(dummy);
attacher.attach(dummy.pid);
return retryForProcessRunning(container, specimen, getTest());
return retryForProcessRunning(specimen, getTest());
}
}

View file

@ -15,7 +15,7 @@
*/
package ghidra.dbg.test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import ghidra.dbg.target.TargetLauncher;
import ghidra.dbg.target.TargetObject;
@ -34,11 +34,9 @@ public interface ProvidesTargetViaLaunchSpecimen extends RequiresTarget, Require
default TargetObject obtainTarget() throws Throwable {
TargetLauncher launcher = getTest().findLauncher();
assertNotNull("No launcher found", launcher);
TargetObject container = getTest().findProcessContainer();
assertNotNull("No process container found", container);
DebuggerTestSpecimen specimen = getLaunchSpecimen();
waitAcc(launcher);
launcher.launch(specimen.getLauncherArgs());
return retryForProcessRunning(container, specimen, getTest());
return retryForProcessRunning(specimen, getTest());
}
}

View file

@ -31,6 +31,7 @@ import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetSteppable.TargetStepKind;
import ghidra.dbg.test.AbstractDebuggerModelTest;
import ghidra.dbg.test.AbstractDebuggerModelTest.DebuggerTestSpecimen;
import ghidra.dbg.util.PathUtils;
import ghidra.util.NumericUtilities;
public interface DebuggerModelTestUtils extends AsyncTestUtils {
@ -164,10 +165,9 @@ public interface DebuggerModelTestUtils extends AsyncTestUtils {
}).findFirst().orElse(null);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
default Collection<TargetProcess> fetchProcesses(TargetObject container)
default Collection<TargetProcess> fetchProcesses(AbstractDebuggerModelTest test)
throws Throwable {
return (Collection) waitOn(container.fetchElements(true)).values();
return test.m.findAll(TargetProcess.class, PathUtils.parse(""), false).values();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@ -176,32 +176,30 @@ public interface DebuggerModelTestUtils extends AsyncTestUtils {
return (Collection) waitOn(container.fetchElements(true)).values();
}
default TargetProcess getProcessRunning(TargetObject container,
DebuggerTestSpecimen specimen, AbstractDebuggerModelTest test) throws Throwable {
return getProcessRunning(container, specimen, test, p -> true);
default TargetProcess getProcessRunning(DebuggerTestSpecimen specimen,
AbstractDebuggerModelTest test) throws Throwable {
return getProcessRunning(specimen, test, p -> true);
}
default TargetProcess getProcessRunning(TargetObject container,
DebuggerTestSpecimen specimen, AbstractDebuggerModelTest test,
Predicate<TargetProcess> predicate) throws Throwable {
return getProcessRunning(fetchProcesses(container), specimen, test, predicate);
default TargetProcess getProcessRunning(DebuggerTestSpecimen specimen,
AbstractDebuggerModelTest test, Predicate<TargetProcess> predicate) throws Throwable {
return getProcessRunning(fetchProcesses(test), specimen, test, predicate);
}
default TargetProcess retryForProcessRunning(TargetObject container,
default TargetProcess retryForProcessRunning(
DebuggerTestSpecimen specimen, AbstractDebuggerModelTest test) throws Throwable {
return retry(() -> {
TargetProcess process = getProcessRunning(container, specimen, test);
TargetProcess process = getProcessRunning(specimen, test);
assertNotNull(process);
return process;
}, List.of(AssertionError.class));
}
default TargetProcess retryForOtherProcessRunning(TargetObject container,
DebuggerTestSpecimen specimen, AbstractDebuggerModelTest test,
Predicate<TargetProcess> predicate, long timeoutMs)
default TargetProcess retryForOtherProcessRunning(DebuggerTestSpecimen specimen,
AbstractDebuggerModelTest test, Predicate<TargetProcess> predicate, long timeoutMs)
throws Throwable {
return retry(timeoutMs, () -> {
TargetProcess process = getProcessRunning(container, specimen, test, predicate);
TargetProcess process = getProcessRunning(specimen, test, predicate);
assertNotNull(process);
return process;
}, List.of(AssertionError.class));

View file

@ -73,8 +73,8 @@ public interface TestDebuggerModelProvider {
<T extends TargetObject> T findAny(Class<T> cls, List<String> seedPath) throws Throwable;
<T extends TargetObject> Map<List<String>, T> findAll(Class<T> cls, List<String> seedPath)
throws Throwable;
<T extends TargetObject> Map<List<String>, T> findAll(Class<T> cls, List<String> seedPath,
boolean atLeastOne) throws Throwable;
TargetObject findContainer(Class<? extends TargetObject> cls, List<String> seedPath)
throws Throwable;