Skip to content

Commit ffe4d84

Browse files
HeikoKlarefedejeanne
authored andcommitted
Make completion proposal calculation test time-independent #906
The test cases for completion proposals in CompletionTest depend on specific timing behavior of a test proposal processor. On one hand, this is prone to errors if proper timing is not given on the test environment. On the other hand, the tests run unnecessarily long because of waiting long enough. This change replaces the fixed-time waiting of the LongRunningBarContentAssistProcessor with an explicit trigger that finalizes the content calculation as soon as some barrier is reached within the tests. In addition, the long-running processor is only enabled on demand and will be finalized whenever a test case was executed to avoid that the processor thread is leaking to the next test case. Contributes to #906
1 parent 05c67f7 commit ffe4d84

File tree

3 files changed

+77
-42
lines changed

3 files changed

+77
-42
lines changed

tests/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/CompletionTest.java

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ public class CompletionTest extends AbstratGenericEditorTest {
8383
@Test
8484
public void testCompletion() throws Exception {
8585
editor.selectAndReveal(3, 0);
86-
this.completionShell= openConentAssist();
87-
final Table completionProposalList = findCompletionSelectionControl(completionShell);
86+
Shell shell = openContentAssistWithLongRunningProposalComputation();
87+
final Table completionProposalList = findCompletionSelectionControl(shell);
8888
checkCompletionContent(completionProposalList);
8989
// TODO find a way to actually trigger completion and verify result against Editor content
9090
// Assert.assertEquals("Completion didn't complete", "bars are good for a beer.", ((StyledText)editor.getAdapter(Control.class)).getText());
@@ -96,7 +96,7 @@ public void testDefaultContentAssistBug570488() throws Exception {
9696
TestLogListener listener= new TestLogListener();
9797
log.addLogListener(listener);
9898
createAndOpenFile("Bug570488.txt", "bar 'bar'");
99-
openConentAssist(false);
99+
assertNull("No shell is expected to open", openContentAssist());
100100
DisplayHelper.driveEventQueue(Display.getCurrent());
101101
assertFalse("There are errors in the log", listener.messages.stream().anyMatch(s -> s.matches(IStatus.ERROR)));
102102
log.removeLogListener(listener);
@@ -113,8 +113,8 @@ public void testCompletionService() throws Exception {
113113
new Hashtable<>(Collections.singletonMap("contentType", "org.eclipse.ui.genericeditor.tests.content-type")));
114114
DisplayHelper.driveEventQueue(Display.getCurrent());
115115
editor.selectAndReveal(3, 0);
116-
this.completionShell= openConentAssist();
117-
final Table completionProposalList= findCompletionSelectionControl(completionShell);
116+
Shell shell = openContentAssistWithLongRunningProposalComputation();
117+
final Table completionProposalList = findCompletionSelectionControl(shell);
118118
checkCompletionContent(completionProposalList);
119119
assertTrue("Service was not called!", service.called);
120120
registration.unregister();
@@ -124,48 +124,57 @@ public void testCompletionService() throws Exception {
124124
public void testCompletionUsingViewerSelection() throws Exception {
125125
editor.getDocumentProvider().getDocument(editor.getEditorInput()).set("abc");
126126
editor.selectAndReveal(0, 3);
127-
this.completionShell= openConentAssist();
128-
final Table completionProposalList = findCompletionSelectionControl(completionShell);
129-
waitForProposalRelatedCondition("Proposal list did not contain expected item: ABC", completionProposalList,
127+
final Shell shell = openContentAssist();
128+
assertNotNull("Shell is expected to open for completion proposals", shell);
129+
final Table completionProposalList = findCompletionSelectionControl(shell);
130+
waitForProposalRelatedCondition("Proposal list did not contain expected item 'ABC'", completionProposalList,
130131
() -> Arrays.stream(completionProposalList.getItems()).map(TableItem::getText).anyMatch("ABC"::equals), 5_000);
131132
}
132133

133-
private static void waitForProposalRelatedCondition(String errorMessage, Table completionProposalList, BooleanSupplier condition, int timeoutInMsec) {
134-
assertTrue(errorMessage, new DisplayHelper() {
134+
private static void waitForProposalRelatedCondition(String expectedListContentDescription, Table completionProposalList, BooleanSupplier condition, int timeoutInMsec) {
135+
boolean result = new DisplayHelper() {
135136
@Override
136137
protected boolean condition() {
137138
assertFalse("Completion proposal list was unexpectedly disposed", completionProposalList.isDisposed());
138139
return condition.getAsBoolean();
139140
}
140-
}.waitForCondition(completionProposalList.getDisplay(), timeoutInMsec));
141+
}.waitForCondition(completionProposalList.getDisplay(), timeoutInMsec);
142+
assertTrue(expectedListContentDescription + " but contained: " + Arrays.toString(completionProposalList.getItems()), result);
141143
}
142144

143145
@Test
144146
public void testEnabledWhenCompletion() throws Exception {
145-
// Confirm that when disabled, a completion shell is present
147+
// Confirm that when disabled, a completion shell is not present
146148
EnabledPropertyTester.setEnabled(false);
147149
createAndOpenFile("enabledWhen.txt", "bar 'bar'");
148150
editor.selectAndReveal(3, 0);
149-
assertNull("A new shell was found", openConentAssist(false));
151+
assertNull("No shell is expected to open", openContentAssist());
150152
cleanFileAndEditor();
151153

152154
// Confirm that when enabled, a completion shell is present
153155
EnabledPropertyTester.setEnabled(true);
154156
createAndOpenFile("enabledWhen.txt", "bar 'bar'");
155-
editor.selectAndReveal(3, 0);
156-
assertNotNull(openConentAssist());
157+
editor.selectAndReveal(3, 0);
158+
assertNotNull("Shell is expected to open for completion proposals", openContentAssist());
157159
}
158160

159-
private Shell openConentAssist() {
160-
return openConentAssist(true);
161+
private Shell openContentAssistWithLongRunningProposalComputation() {
162+
LongRunningBarContentAssistProcessor.enable();
163+
Shell shell = openContentAssist();
164+
assertNotNull("Shell is expected to open for completion proposals", shell);
165+
return shell;
161166
}
162-
private Shell openConentAssist(boolean expectShell) {
167+
168+
private Shell openContentAssist() {
163169
ContentAssistAction action = (ContentAssistAction) editor.getAction(ITextEditorActionConstants.CONTENT_ASSIST);
164170
action.update();
165171
final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet());
166172
action.run(); //opens shell
167-
Shell shell= findNewShell(beforeShells, editor.getSite().getShell().getDisplay(),expectShell);
173+
Shell shell = findNewShell(beforeShells, editor.getSite().getShell().getDisplay());
168174
waitAndDispatch(100); // can dispose shell when focus lost during debugging
175+
if (shell != null) {
176+
this.completionShell = shell;
177+
}
169178
return shell;
170179
}
171180

@@ -178,19 +187,19 @@ private Shell openConentAssist(boolean expectShell) {
178187
*/
179188
private void checkCompletionContent(final Table completionProposalList) {
180189
// should be instantaneous, but happens to go asynchronous on CI so let's allow a wait
181-
waitForProposalRelatedCondition("Proposal list did not show two initial items", completionProposalList,
190+
waitForProposalRelatedCondition("Proposal list should show two initial items", completionProposalList,
182191
() -> completionProposalList.getItemCount() == 2, 200);
183192
assertTrue("Missing computing info entry", isComputingInfoEntry(completionProposalList.getItem(0)));
184-
assertTrue("Missing computing info entry in proposal list", isComputingInfoEntry(completionProposalList.getItem(0)));
185193
final TableItem initialProposalItem = completionProposalList.getItem(1);
186194
final String initialProposalString = ((ICompletionProposal)initialProposalItem.getData()).getDisplayString();
187195
assertThat("Unexpected initial proposal item",
188196
BAR_CONTENT_ASSIST_PROPOSAL, endsWith(initialProposalString));
189197
completionProposalList.setSelection(initialProposalItem);
198+
199+
LongRunningBarContentAssistProcessor.finish();
190200
// asynchronous
191-
waitForProposalRelatedCondition("Proposal list did not show two items after finishing computing", completionProposalList,
192-
() -> !isComputingInfoEntry(completionProposalList.getItem(0)) && completionProposalList.getItemCount() == 2,
193-
LongRunningBarContentAssistProcessor.DELAY + 200);
201+
waitForProposalRelatedCondition("Proposal list should contain two items", completionProposalList,
202+
() -> !isComputingInfoEntry(completionProposalList.getItem(0)) && completionProposalList.getItemCount() == 2, 5000);
194203
final TableItem firstCompletionProposalItem = completionProposalList.getItem(0);
195204
final TableItem secondCompletionProposalItem = completionProposalList.getItem(1);
196205
String firstCompletionProposalText = ((ICompletionProposal)firstCompletionProposalItem.getData()).getDisplayString();
@@ -205,24 +214,23 @@ private static boolean isComputingInfoEntry(TableItem item) {
205214
return item.getText().contains("Computing");
206215
}
207216

208-
public static Shell findNewShell(Set<Shell> beforeShells, Display display, boolean expectShell) {
217+
public static Shell findNewShell(Set<Shell> beforeShells, Display display) {
209218
Shell[] afterShells = Arrays.stream(display.getShells())
210219
.filter(Shell::isVisible)
211220
.filter(shell -> !beforeShells.contains(shell))
212221
.toArray(Shell[]::new);
213-
if (expectShell) {
214-
assertEquals("No new shell found", 1, afterShells.length);
215-
}
222+
assertTrue("More than one new shell was found", afterShells.length <= 1);
216223
return afterShells.length > 0 ? afterShells[0] : null;
217224
}
218225

219226
@Test
220227
public void testCompletionFreeze_bug521484() throws Exception {
221228
editor.selectAndReveal(3, 0);
222-
this.completionShell=openConentAssist();
223-
final Table completionProposalList = findCompletionSelectionControl(this.completionShell);
229+
final Shell shell = openContentAssistWithLongRunningProposalComputation();
230+
assertNotNull("Shell is expected to open for completion proposals", shell);
231+
final Table completionProposalList = findCompletionSelectionControl(shell);
224232
// should be instantaneous, but happens to go asynchronous on CI so let's allow a wait
225-
waitForProposalRelatedCondition("Proposal list did not show two items", completionProposalList,
233+
waitForProposalRelatedCondition("Proposal list should show two items", completionProposalList,
226234
() -> completionProposalList.getItemCount() == 2, 200);
227235
assertTrue("Missing computing info entry", isComputingInfoEntry(completionProposalList.getItem(0)));
228236
// Some processors are long running, moving cursor can cause freeze (bug 521484)
@@ -231,18 +239,24 @@ public void testCompletionFreeze_bug521484() throws Exception {
231239
emulatePressLeftArrowKey();
232240
DisplayHelper.sleep(editor.getSite().getShell().getDisplay(), 200); //give time to process events
233241
long processingDuration = System.currentTimeMillis() - timestamp;
234-
assertTrue("UI Thread frozen for " + processingDuration + "ms", processingDuration < LongRunningBarContentAssistProcessor.DELAY);
242+
assertTrue("UI Thread frozen for " + processingDuration + "ms", processingDuration < LongRunningBarContentAssistProcessor.TIMEOUT_MSEC);
235243
}
236244

237245
@Test
238246
public void testMoveCaretBackUsesAllProcessors_bug522255() throws Exception {
239-
testCompletion();
247+
editor.selectAndReveal(3, 0);
248+
Shell shell = openContentAssistWithLongRunningProposalComputation();
249+
final Table completionProposalList = findCompletionSelectionControl(shell);
250+
checkCompletionContent(completionProposalList);
251+
LongRunningBarContentAssistProcessor.enable();
240252
emulatePressLeftArrowKey();
241253
final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet());
242254
DisplayHelper.sleep(editor.getSite().getShell().getDisplay(), 200);
243-
this.completionShell= findNewShell(beforeShells, editor.getSite().getShell().getDisplay(), true);
244-
final Table completionProposalList = findCompletionSelectionControl(this.completionShell);
245-
checkCompletionContent(completionProposalList);
255+
assertTrue("Completion proposal shell should be disposed after moving the cusor", shell.isDisposed());
256+
this.completionShell = findNewShell(beforeShells, editor.getSite().getShell().getDisplay());
257+
assertNotNull("Shell is expected to open for completion proposals", completionShell);
258+
final Table newCompletionProposalList = findCompletionSelectionControl(completionShell);
259+
checkCompletionContent(newCompletionProposalList);
246260
}
247261

248262
private void emulatePressLeftArrowKey() {
@@ -277,6 +291,11 @@ public void closeShell() {
277291
completionShell.close();
278292
}
279293
}
294+
295+
@After
296+
public void stopLongRunningCompletionProposalProcessor() {
297+
LongRunningBarContentAssistProcessor.finish();
298+
}
280299

281300
private static final class TestLogListener implements ILogListener {
282301

tests/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/TestQuickAssist.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package org.eclipse.ui.genericeditor.tests;
1616

1717
import static org.junit.Assert.assertEquals;
18+
import static org.junit.Assert.assertNotNull;
1819
import static org.junit.Assert.assertTrue;
1920

2021
import java.util.Arrays;
@@ -103,7 +104,8 @@ private Shell openQuickAssist() {
103104
action.update();
104105
final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet());
105106
action.run();
106-
Shell shell= CompletionTest.findNewShell(beforeShells, editor.getSite().getShell().getDisplay(), true);
107+
Shell shell= CompletionTest.findNewShell(beforeShells, editor.getSite().getShell().getDisplay());
108+
assertNotNull("Shell is expected to open for quick assist", shell);
107109
waitAndDispatch(100);
108110
return shell;
109111
}

tests/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/LongRunningBarContentAssistProcessor.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,40 @@
1313
*******************************************************************************/
1414
package org.eclipse.ui.genericeditor.tests.contributions;
1515

16+
import java.util.concurrent.atomic.AtomicBoolean;
17+
1618
import org.eclipse.jface.text.ITextViewer;
1719
import org.eclipse.jface.text.contentassist.ICompletionProposal;
1820

1921
public class LongRunningBarContentAssistProcessor extends BarContentAssistProcessor {
2022

2123
public static final String LONG_RUNNING_BAR_CONTENT_ASSIST_PROPOSAL = "bars are also good for soft drink cocktails.";
22-
public static final int DELAY = 2000;
23-
24+
public static final int TIMEOUT_MSEC = 10_000;
25+
private static final AtomicBoolean running = new AtomicBoolean();
26+
2427
public LongRunningBarContentAssistProcessor() {
2528
super(LONG_RUNNING_BAR_CONTENT_ASSIST_PROPOSAL);
2629
}
2730

2831
@Override
2932
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
3033
try {
31-
Thread.sleep(DELAY);
34+
long startExecutionTime = System.currentTimeMillis();
35+
while (running.get() && (System.currentTimeMillis() - startExecutionTime) < TIMEOUT_MSEC) {
36+
Thread.sleep(20);
37+
}
3238
} catch (InterruptedException e) {
33-
// TODO Auto-generated catch block
34-
e.printStackTrace();
39+
// Just finish on unexpected interrupt
3540
}
3641
return super.computeCompletionProposals(viewer, offset);
3742
}
43+
44+
public static void enable() {
45+
running.set(true);
46+
}
47+
48+
public static void finish() {
49+
running.set(false);
50+
}
51+
3852
}

0 commit comments

Comments
 (0)