Skip to content

Commit 5c4f5a5

Browse files
committed
Reduce OpenCloseTest iterations and dump threads on hang
OpenCloseTest occasionally deadlocks on macOS in testOpenClosePerspective and then produces no output until the 1200 second bundle timeout kills the whole JVM, so the run fails with no usable diagnostic. Add a per method watchdog that dumps all thread stacks and aborts once a method exceeds 200 seconds, so a hang reports a stacktrace instead of being killed silently. A plain JUnit timeout cannot be used because these tests run on the UI thread. Also reduce the iteration count from 10 to 4 to keep the automated build fast; it can be raised locally for real stress testing. #4101
1 parent a6b77cc commit 5c4f5a5

1 file changed

Lines changed: 62 additions & 1 deletion

File tree

tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/stress/OpenCloseTest.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package org.eclipse.ui.tests.stress;
1515

1616
import static org.junit.Assert.assertNotNull;
17+
import static org.junit.Assert.fail;
1718

1819
import java.util.HashMap;
1920

@@ -42,6 +43,7 @@
4243
import org.eclipse.ui.part.FileEditorInput;
4344
import org.eclipse.ui.tests.harness.util.CloseTestWindowsRule;
4445
import org.eclipse.ui.tests.harness.util.FileUtil;
46+
import org.junit.After;
4547
import org.junit.Before;
4648
import org.junit.Rule;
4749
import org.junit.Test;
@@ -52,17 +54,27 @@
5254
public class OpenCloseTest {
5355
private static final String ORG_ECLIPSE_RESOURCE_PERSPECTIVE = "org.eclipse.ui.resourcePerspective";
5456

55-
private static final int numIterations = 10;
57+
// Low iteration count keeps the automated build fast; raise it locally for real stress testing.
58+
private static final int numIterations = 4;
59+
60+
// Per-method deadline; on expiry the watchdog dumps all threads and aborts.
61+
private static final long TEST_TIMEOUT_MS = 200_000;
62+
63+
private static final long WATCHDOG_GRACE_MS = 20_000;
5664

5765
private IWorkbenchWindow workbenchWindow;
5866
private IWorkbench workbench;
5967
private IWorkbenchPage page;
6068

69+
private Thread watchdog;
70+
private volatile boolean deadlineExceeded;
71+
6172
@Rule
6273
public CloseTestWindowsRule closeTestWindows = new CloseTestWindowsRule();
6374

6475
@Before
6576
public void setup() {
77+
armWatchdog();
6678
workbench = PlatformUI.getWorkbench();
6779
workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
6880
IIntroPart intro = PlatformUI.getWorkbench().getIntroManager().getIntro();
@@ -80,6 +92,55 @@ public void setup() {
8092
assertNotNull(page);
8193
}
8294

95+
@After
96+
public void disarmWatchdog() {
97+
if (watchdog != null) {
98+
watchdog.interrupt();
99+
watchdog = null;
100+
}
101+
// Fail any method that exceeded the deadline, even if it recovered after the interrupt, so a
102+
// late run is never silently reported as passing.
103+
if (deadlineExceeded) {
104+
fail("Test exceeded " + TEST_TIMEOUT_MS + " ms; see the thread dump above.");
105+
}
106+
}
107+
108+
private void armWatchdog() {
109+
deadlineExceeded = false;
110+
Thread testThread = Thread.currentThread();
111+
watchdog = new Thread(() -> {
112+
try {
113+
Thread.sleep(TEST_TIMEOUT_MS);
114+
} catch (InterruptedException e) {
115+
return; // test finished in time and disarmed the watchdog
116+
}
117+
deadlineExceeded = true;
118+
dumpAllThreads();
119+
testThread.interrupt(); // best effort: unblock an interruptible wait
120+
try {
121+
Thread.sleep(WATCHDOG_GRACE_MS);
122+
} catch (InterruptedException e) {
123+
return; // test recovered after the interrupt and disarmed the watchdog
124+
}
125+
// Still stuck: halt rather than wait for the bundle timeout. halt() avoids shutdown
126+
// hooks deadlocking again on the wedged UI thread.
127+
System.err.println("OpenCloseTest did not recover after interrupt; aborting JVM.");
128+
Runtime.getRuntime().halt(143);
129+
}, "OpenCloseTest-watchdog");
130+
watchdog.setDaemon(true);
131+
watchdog.start();
132+
}
133+
134+
private static void dumpAllThreads() {
135+
System.err.println("OpenCloseTest exceeded " + TEST_TIMEOUT_MS + " ms; dumping all thread stacks:");
136+
for (var entry : Thread.getAllStackTraces().entrySet()) {
137+
System.err.println(entry.getKey());
138+
for (StackTraceElement element : entry.getValue()) {
139+
System.err.println("\tat " + element);
140+
}
141+
}
142+
}
143+
83144

84145
/**
85146
* Test the opening and closing of a file.

0 commit comments

Comments
 (0)