Skip to content

Commit b4b70d7

Browse files
committed
Merge remote-tracking branch 'origin/flacky-test-RCP-test-advisor' into fix-flaky-progress-view-test
2 parents 6dd04b2 + 537a6d4 commit b4b70d7

File tree

2 files changed

+58
-18
lines changed

2 files changed

+58
-18
lines changed

tests/org.eclipse.ui.tests.harness/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
22
Bundle-ManifestVersion: 2
33
Bundle-Name: Harness Plug-in
44
Bundle-SymbolicName: org.eclipse.ui.tests.harness;singleton:=true
5-
Bundle-Version: 1.10.600.qualifier
5+
Bundle-Version: 1.10.700.qualifier
66
Eclipse-BundleShape: dir
77
Require-Bundle: org.eclipse.ui,
88
org.eclipse.core.runtime,

tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/RCPTestWorkbenchAdvisor.java

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
*******************************************************************************/
1414
package org.eclipse.ui.tests.harness.util;
1515

16+
import java.util.concurrent.Phaser;
17+
import java.util.concurrent.TimeUnit;
18+
import java.util.concurrent.TimeoutException;
19+
1620
import org.eclipse.jface.preference.IPreferenceStore;
1721
import org.eclipse.swt.SWTException;
1822
import org.eclipse.swt.widgets.Display;
@@ -44,6 +48,10 @@ public class RCPTestWorkbenchAdvisor extends WorkbenchAdvisor {
4448

4549
private static boolean started = false;
4650

51+
// Use a Phaser to ensure async operations are scheduled before postStartup
52+
// Each thread registers itself and arrives when the operation is scheduled
53+
private static final Phaser asyncPhaser = new Phaser(1); // 1 for the main thread
54+
4755
public static boolean isSTARTED() {
4856
synchronized (RCPTestWorkbenchAdvisor.class) {
4957
return started;
@@ -122,12 +130,10 @@ public void eventLoopIdle(final Display display) {
122130
public void preStartup() {
123131
super.preStartup();
124132
final Display display = Display.getCurrent();
133+
125134
if (display != null) {
126135
display.asyncExec(() -> {
127-
if (isSTARTED())
128-
asyncDuringStartup = Boolean.FALSE;
129-
else
130-
asyncDuringStartup = Boolean.TRUE;
136+
asyncDuringStartup = !isSTARTED();
131137
});
132138
}
133139

@@ -151,24 +157,28 @@ public void preStartup() {
151157
}
152158

153159
private void setupSyncDisplayThread(final boolean callDisplayAccess, final Display display) {
160+
// Register this thread with the phaser
161+
asyncPhaser.register();
154162
Thread syncThread = new Thread() {
155163
@Override
156164
public void run() {
157165
if (callDisplayAccess)
158166
DisplayAccess.accessDisplayDuringStartup();
159167
try {
160168
display.syncExec(() -> {
161-
synchronized (RCPTestWorkbenchAdvisor.class) {
162-
if (callDisplayAccess)
163-
syncWithDisplayAccess = !isSTARTED() ? Boolean.TRUE : Boolean.FALSE;
164-
else
165-
syncWithoutDisplayAccess = !isSTARTED() ? Boolean.TRUE : Boolean.FALSE;
169+
if (callDisplayAccess) {
170+
syncWithDisplayAccess = !isSTARTED();
171+
} else {
172+
syncWithoutDisplayAccess = !isSTARTED();
166173
}
167174
});
168175
} catch (SWTException e) {
169176
// this can happen because we shut down the workbench just
170177
// as soon as we're initialized - ie: when we're trying to
171178
// run this runnable in the deferred case.
179+
} finally {
180+
// Signal that this operation has completed
181+
asyncPhaser.arriveAndDeregister();
172182
}
173183
}
174184
};
@@ -177,19 +187,26 @@ public void run() {
177187
}
178188

179189
private void setupAsyncDisplayThread(final boolean callDisplayAccess, final Display display) {
190+
// Register this thread with the phaser
191+
asyncPhaser.register();
180192
Thread asyncThread = new Thread() {
181193
@Override
182194
public void run() {
183195
if (callDisplayAccess)
184196
DisplayAccess.accessDisplayDuringStartup();
185-
display.asyncExec(() -> {
186-
synchronized (RCPTestWorkbenchAdvisor.class) {
187-
if (callDisplayAccess)
188-
asyncWithDisplayAccess = !isSTARTED() ? Boolean.TRUE : Boolean.FALSE;
189-
else
190-
asyncWithoutDisplayAccess = !isSTARTED() ? Boolean.TRUE : Boolean.FALSE;
191-
}
192-
});
197+
try {
198+
display.asyncExec(() -> {
199+
if (callDisplayAccess) {
200+
asyncWithDisplayAccess = !isSTARTED();
201+
} else {
202+
asyncWithoutDisplayAccess = !isSTARTED();
203+
}
204+
});
205+
} finally {
206+
// Signal that this operation has been scheduled (not necessarily executed yet)
207+
// This avoids deadlock since we're not waiting for execution on the UI thread
208+
asyncPhaser.arriveAndDeregister();
209+
}
193210
}
194211
};
195212
asyncThread.setDaemon(true);
@@ -199,6 +216,29 @@ public void run() {
199216
@Override
200217
public void postStartup() {
201218
super.postStartup();
219+
220+
// Wait for all async/sync operations to be scheduled (not blocking UI thread)
221+
try {
222+
// Wait up to 5 seconds for all operations to be scheduled
223+
// The main thread arrives and deregisters, waiting for all other registered threads
224+
asyncPhaser.awaitAdvanceInterruptibly(asyncPhaser.arrive(), 5, TimeUnit.SECONDS);
225+
} catch (TimeoutException e) {
226+
// Log warning but don't throw - we need to mark as started to avoid breaking subsequent tests
227+
System.err.println("WARNING: Not all async/sync operations were scheduled within timeout");
228+
e.printStackTrace();
229+
} catch (InterruptedException e) {
230+
Thread.currentThread().interrupt();
231+
System.err.println("WARNING: Interrupted while waiting for async/sync operations");
232+
}
233+
234+
// Pump the event loop to ensure async runnables execute before marking as started
235+
// This prevents the original race condition where async variables might not be set yet
236+
// Wait until the variables that should be set during startup are actually set
237+
UITestUtil.processEventsUntil(() -> syncWithDisplayAccess != null && asyncWithDisplayAccess != null, 5000);
238+
// Process any remaining events to allow variables that should NOT be set during startup
239+
// to accidentally execute (to detect regression)
240+
UITestUtil.processEvents();
241+
202242
synchronized (RCPTestWorkbenchAdvisor.class) {
203243
started = true;
204244
}

0 commit comments

Comments
 (0)