Skip to content

Commit

Permalink
Make completion proposal calculation test time-independent #906 #907
Browse files Browse the repository at this point in the history
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.

Contributes to
#906 and
#907
  • Loading branch information
HeikoKlare committed Jul 26, 2023
1 parent 494178f commit 286908a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,19 @@ public void testCompletionUsingViewerSelection() throws Exception {
editor.selectAndReveal(0, 3);
this.completionShell= openConentAssist();
final Table completionProposalList = findCompletionSelectionControl(completionShell);
waitForProposalRelatedCondition("Proposal list did not contain expected item: ABC", completionProposalList,
waitForProposalRelatedCondition("Proposal list did not contain expected item 'ABC'", completionProposalList,
() -> Arrays.stream(completionProposalList.getItems()).map(TableItem::getText).anyMatch("ABC"::equals), 5_000);
}

private static void waitForProposalRelatedCondition(String errorMessage, Table completionProposalList, BooleanSupplier condition, int timeoutInMsec) {
assertTrue(errorMessage, new DisplayHelper() {
private static void waitForProposalRelatedCondition(String expectedListContentDescription, Table completionProposalList, BooleanSupplier condition, int timeoutInMsec) {
boolean result = new DisplayHelper() {
@Override
protected boolean condition() {
assertFalse("Completion proposal list was unexpectedly disposed", completionProposalList.isDisposed());
return condition.getAsBoolean();
}
}.waitForCondition(completionProposalList.getDisplay(), timeoutInMsec));
}.waitForCondition(completionProposalList.getDisplay(), timeoutInMsec);
assertTrue(expectedListContentDescription + " but contained: " + Arrays.toString(completionProposalList.getItems()), result);
}

@Test
Expand Down Expand Up @@ -177,7 +178,7 @@ private Shell openConentAssist(boolean expectShell) {
*/
private void checkCompletionContent(final Table completionProposalList) {
// should be instantaneous, but happens to go asynchronous on CI so let's allow a wait
waitForProposalRelatedCondition("Proposal list did not show two initial items", completionProposalList,
waitForProposalRelatedCondition("Proposal list should show two initial items", completionProposalList,
() -> completionProposalList.getItemCount() == 2, 200);
assertTrue("Missing computing info entry", isComputingInfoEntry(completionProposalList.getItem(0)));
assertTrue("Missing computing info entry in proposal list", isComputingInfoEntry(completionProposalList.getItem(0)));
Expand All @@ -186,16 +187,17 @@ private void checkCompletionContent(final Table completionProposalList) {
assertThat("Unexpected initial proposal item",
BarContentAssistProcessor.PROPOSAL, endsWith(initialProposalString));
completionProposalList.setSelection(initialProposalItem);

LongRunningBarContentAssistProcessor.finishComputation();
// asynchronous
waitForProposalRelatedCondition("Proposal list did not show two items after finishing computing", completionProposalList,
() -> !isComputingInfoEntry(completionProposalList.getItem(0)) && completionProposalList.getItemCount() == 2,
LongRunningBarContentAssistProcessor.DELAY + 200);
waitForProposalRelatedCondition("Proposal list should contain two items", completionProposalList,
() -> !isComputingInfoEntry(completionProposalList.getItem(0)) && completionProposalList.getItemCount() == 2, 5000);
final TableItem firstCompletionProposalItem = completionProposalList.getItem(0);
final TableItem secondCompletionProposalItem = completionProposalList.getItem(1);
String firstCompletionProposalText = ((ICompletionProposal)firstCompletionProposalItem.getData()).getDisplayString();
String secondCOmpletionProposalText = ((ICompletionProposal)secondCompletionProposalItem.getData()).getDisplayString();
String secondCompletionProposalText = ((ICompletionProposal)secondCompletionProposalItem.getData()).getDisplayString();
assertThat("Unexpected first proposal item", BarContentAssistProcessor.PROPOSAL, endsWith(firstCompletionProposalText));
assertThat("Unexpected second proposal item", LongRunningBarContentAssistProcessor.PROPOSAL, endsWith(secondCOmpletionProposalText));
assertThat("Unexpected second proposal item", LongRunningBarContentAssistProcessor.PROPOSAL, endsWith(secondCompletionProposalText));
String selectedProposalString = ((ICompletionProposal)completionProposalList.getSelection()[0].getData()).getDisplayString();
assertEquals("Addition of completion proposal should keep selection", initialProposalString, selectedProposalString);
}
Expand All @@ -221,7 +223,7 @@ public void testCompletionFreeze_bug521484() throws Exception {
this.completionShell=openConentAssist();
final Table completionProposalList = findCompletionSelectionControl(this.completionShell);
// should be instantaneous, but happens to go asynchronous on CI so let's allow a wait
waitForProposalRelatedCondition("Proposal list did not show two items", completionProposalList,
waitForProposalRelatedCondition("Proposal list should show two items", completionProposalList,
() -> completionProposalList.getItemCount() == 2, 200);
assertTrue("Missing computing info entry", isComputingInfoEntry(completionProposalList.getItem(0)));
// Some processors are long running, moving cursor can cause freeze (bug 521484)
Expand All @@ -230,7 +232,7 @@ public void testCompletionFreeze_bug521484() throws Exception {
emulatePressLeftArrowKey();
DisplayHelper.sleep(editor.getSite().getShell().getDisplay(), 200); //give time to process events
long processingDuration = System.currentTimeMillis() - timestamp;
assertTrue("UI Thread frozen for " + processingDuration + "ms", processingDuration < LongRunningBarContentAssistProcessor.DELAY);
assertTrue("UI Thread frozen for " + processingDuration + "ms", processingDuration < LongRunningBarContentAssistProcessor.TIMEOUT_MSEC);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,38 @@
*******************************************************************************/
package org.eclipse.ui.genericeditor.tests.contributions;

import static org.junit.Assert.assertFalse;

import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;

public class LongRunningBarContentAssistProcessor extends BarContentAssistProcessor {

public static final String PROPOSAL = "bars are also good for soft drink cocktails.";
public static final int DELAY = 2000;

public static final int TIMEOUT_MSEC = 10_000;
private static boolean shouldComputationFinish = false;

public LongRunningBarContentAssistProcessor() {
super(PROPOSAL);
}

@Override
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
shouldComputationFinish = false;
try {
Thread.sleep(DELAY);
long startExecutionTime = System.currentTimeMillis();
while (!shouldComputationFinish && (System.currentTimeMillis() - startExecutionTime) < TIMEOUT_MSEC) {
Thread.sleep(20);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// Just finish on unexpected interrupt
}
return super.computeCompletionProposals(viewer, offset);
}

public static void finishComputation() {
assertFalse("Concurrent requests for finishing computation of long running content assist processor", shouldComputationFinish);
shouldComputationFinish = true;
}

}

0 comments on commit 286908a

Please sign in to comment.