From 866302cac5a8e22eeeb34e821898be31580d3789 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Tue, 21 Jan 2025 14:46:49 -0500 Subject: [PATCH] Add some extra info when terminate fails in tests On GitHub I see fails in resume[gdb] (org.eclipse.cdt.tests.dsf.gdb.tests.MIRunControlTest) with this output: ``` Terminate failed org.eclipse.debug.core.DebugException: Terminate failed at org.eclipse.debug.core.Launch.terminate(Launch.java:300) at org.eclipse.cdt.dsf.gdb.launching.GdbLaunch.terminate(GdbLaunch.java:313) at org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase.doAfterTest(BaseTestCase.java:662) at org.eclipse.cdt.tests.dsf.gdb.tests.MIRunControlTest.doAfterTest(MIRunControlTest.java:133) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) at org.junit.internal.runners.statements.RunAfters.invokeMethod(RunAfters.java:46) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33) at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61) at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:299) at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:293) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) at java.base/java.lang.Thread.run(Thread.java:1583) Contains: Terminate failed Contains: Terminate failed 790,475 "resume[gdb]" requesting gdb. Launched gdb 15.0.50.20240403. ``` which is insufficient to diagnose what is happening. Part of #816 --- .../tests/dsf/gdb/framework/BaseTestCase.java | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/BaseTestCase.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/BaseTestCase.java index c7b0f1b403d..8e6d8602bec 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/BaseTestCase.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/BaseTestCase.java @@ -20,10 +20,13 @@ import static org.junit.Assert.assertTrue; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; +import java.io.PrintStream; import java.io.Reader; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -54,10 +57,12 @@ import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants; import org.eclipse.cdt.utils.spawner.ProcessFactory; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; 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.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IBreakpointManager; import org.eclipse.debug.core.ILaunch; @@ -66,6 +71,8 @@ import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.RuntimeProcess; import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; import org.junit.After; import org.junit.AfterClass; @@ -659,7 +666,49 @@ protected void assertLaunchTerminates(GdbLaunch launch, boolean terminate) throw @After public void doAfterTest() throws Exception { if (fLaunch != null) { - fLaunch.terminate(); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(byteArrayOutputStream, true, "UTF-8"); + IProcess[] processes = fLaunch.getProcesses(); + + out.println("Processes: " + Arrays.toString(processes)); + for (IProcess process : processes) { + out.println("Process: " + process); + if (process instanceof RuntimeProcess runtimeProcess) { + Field field = RuntimeProcess.class.getDeclaredField("fProcess"); + field.trySetAccessible(); + Process javaProcess = (Process) field.get(runtimeProcess); + out.println("javaProcess: " + javaProcess); + if (javaProcess != null) { + try { + List descendants = javaProcess.descendants().collect(Collectors.toList()); + out.println("descendants: " + descendants); + } catch (UnsupportedOperationException e) { + out.println("descendants unsupported"); + } + } + } else { + out.println("Class: " + process.getClass()); + } + if (process.isTerminated()) { + out.println("isTerminated: true"); + out.println("exitValue: " + process.getExitValue()); + } else { + out.println("isTerminated: false"); + } + } + String info = byteArrayOutputStream.toString("UTF-8"); + try { + fLaunch.terminate(); + } catch (DebugException e) { + IStatus status = e.getStatus(); + if (status != null) { + String statusString = status.toString(); + throw new RuntimeException("Received debug exception with: " + statusString + "\ninfo:\n" + info, + e); + } else { + throw new RuntimeException("Received debug with no status\ninfo:\n" + info, e); + } + } assertLaunchTerminates(); fLaunch = null; }