Attempt to fix race condition boot ls tests
See: https://www.pivotaltracker.com/story/show/175339205
This commit is contained in:
@@ -11,9 +11,9 @@
|
|||||||
package org.springframework.ide.vscode.languageserver.testharness;
|
package org.springframework.ide.vscode.languageserver.testharness;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness.HIGHLIGHTS_TIMEOUT;
|
||||||
import static org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness.getDocString;
|
import static org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness.getDocString;
|
||||||
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertContains;
|
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertContains;
|
||||||
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertDoesNotContain;
|
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertDoesNotContain;
|
||||||
@@ -27,6 +27,8 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -137,6 +139,7 @@ public class Editor {
|
|||||||
private int selectionStart;
|
private int selectionStart;
|
||||||
private Set<String> ignoredTypes;
|
private Set<String> ignoredTypes;
|
||||||
private LanguageId languageId;
|
private LanguageId languageId;
|
||||||
|
private Future<HighlightParams> highlightsFuture;
|
||||||
|
|
||||||
public Editor(LanguageServerHarness harness, String contents, LanguageId languageId) throws Exception {
|
public Editor(LanguageServerHarness harness, String contents, LanguageId languageId) throws Exception {
|
||||||
this(harness, contents, languageId, null);
|
this(harness, contents, languageId, null);
|
||||||
@@ -150,6 +153,7 @@ public class Editor {
|
|||||||
this.selectionStart = state.selectionStart;
|
this.selectionStart = state.selectionStart;
|
||||||
this.selectionEnd = state.selectionEnd;
|
this.selectionEnd = state.selectionEnd;
|
||||||
this.ignoredTypes = new HashSet<>();
|
this.ignoredTypes = new HashSet<>();
|
||||||
|
this.highlightsFuture = harness.getHighlightsFuture(doc);
|
||||||
}
|
}
|
||||||
public Editor(LanguageServerHarness harness, TextDocumentInfo doc, String contents, LanguageId languageId) throws Exception {
|
public Editor(LanguageServerHarness harness, TextDocumentInfo doc, String contents, LanguageId languageId) throws Exception {
|
||||||
this.harness = harness;
|
this.harness = harness;
|
||||||
@@ -159,6 +163,7 @@ public class Editor {
|
|||||||
this.selectionStart = state.selectionStart;
|
this.selectionStart = state.selectionStart;
|
||||||
this.selectionEnd = state.selectionEnd;
|
this.selectionEnd = state.selectionEnd;
|
||||||
this.ignoredTypes = new HashSet<>();
|
this.ignoredTypes = new HashSet<>();
|
||||||
|
this.highlightsFuture = harness.getHighlightsFuture(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,7 +220,7 @@ public class Editor {
|
|||||||
|
|
||||||
|
|
||||||
public List<Range> assertHighlights(String... expectedHighlights) throws Exception {
|
public List<Range> assertHighlights(String... expectedHighlights) throws Exception {
|
||||||
HighlightParams highlights = harness.getHighlights(doc);
|
HighlightParams highlights = this.highlightsFuture.get(HIGHLIGHTS_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
|
||||||
List<Range> ranges = highlights != null ? highlights.getCodeLenses().stream().map(CodeLens::getRange).collect(Collectors.toList()) : ImmutableList.of();
|
List<Range> ranges = highlights != null ? highlights.getCodeLenses().stream().map(CodeLens::getRange).collect(Collectors.toList()) : ImmutableList.of();
|
||||||
Collections.sort(ranges, RANGE_COMPARATOR);
|
Collections.sort(ranges, RANGE_COMPARATOR);
|
||||||
List<String> actualHighlights = ranges.stream()
|
List<String> actualHighlights = ranges.stream()
|
||||||
@@ -225,11 +230,6 @@ public class Editor {
|
|||||||
return ranges;
|
return ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertNoHighlights() throws Exception {
|
|
||||||
HighlightParams highlights = harness.getHighlights(false, doc);
|
|
||||||
assertNull(highlights);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the editor text, with cursor markers inserted (for easy textual comparison
|
* Get the editor text, with cursor markers inserted (for easy textual comparison
|
||||||
* after applying a proposal)
|
* after applying a proposal)
|
||||||
|
|||||||
@@ -104,10 +104,13 @@ import org.eclipse.lsp4j.WorkspaceEditCapabilities;
|
|||||||
import org.eclipse.lsp4j.WorkspaceSymbolParams;
|
import org.eclipse.lsp4j.WorkspaceSymbolParams;
|
||||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||||
import org.eclipse.lsp4j.services.LanguageClientAware;
|
import org.eclipse.lsp4j.services.LanguageClientAware;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.LanguageServerTestListener;
|
import org.springframework.ide.vscode.commons.languageserver.util.LanguageServerTestListener;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.Settings;
|
import org.springframework.ide.vscode.commons.languageserver.util.Settings;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.SimpleWorkspaceService;
|
||||||
import org.springframework.ide.vscode.commons.protocol.CursorMovement;
|
import org.springframework.ide.vscode.commons.protocol.CursorMovement;
|
||||||
import org.springframework.ide.vscode.commons.protocol.HighlightParams;
|
import org.springframework.ide.vscode.commons.protocol.HighlightParams;
|
||||||
import org.springframework.ide.vscode.commons.protocol.ProgressParams;
|
import org.springframework.ide.vscode.commons.protocol.ProgressParams;
|
||||||
@@ -138,6 +141,8 @@ import reactor.core.publisher.Mono;
|
|||||||
public class LanguageServerHarness {
|
public class LanguageServerHarness {
|
||||||
|
|
||||||
//Warning this 'harness' is incomplete. Growing it as needed.
|
//Warning this 'harness' is incomplete. Growing it as needed.
|
||||||
|
|
||||||
|
private static Logger log = LoggerFactory.getLogger(LanguageServerHarness.class);
|
||||||
|
|
||||||
private Random random = new Random();
|
private Random random = new Random();
|
||||||
|
|
||||||
@@ -161,7 +166,7 @@ public class LanguageServerHarness {
|
|||||||
this.server = server;
|
this.server = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Duration HIGHLIGHTS_TIMEOUT = Duration.ofMillis(10_000L); //Why so long?
|
public static final Duration HIGHLIGHTS_TIMEOUT = Duration.ofMillis(5_000L);
|
||||||
|
|
||||||
// public static LanguageServerHarness<SimpleLanguageServer> create(String extensionId, LanguageServerInitializer initializer) throws Exception {
|
// public static LanguageServerHarness<SimpleLanguageServer> create(String extensionId, LanguageServerInitializer initializer) throws Exception {
|
||||||
// Callable<SimpleLanguageServer> factory = () -> {
|
// Callable<SimpleLanguageServer> factory = () -> {
|
||||||
@@ -224,6 +229,7 @@ public class LanguageServerHarness {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void receiveHighlights(HighlightParams highlights) {
|
private void receiveHighlights(HighlightParams highlights) {
|
||||||
|
log.info("highlights received: {}", highlights);
|
||||||
Collection<CompletableFuture<HighlightParams>>requestors = ImmutableList.of();
|
Collection<CompletableFuture<HighlightParams>>requestors = ImmutableList.of();
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
String uri = highlights.getDoc().getUri();
|
String uri = highlights.getDoc().getUri();
|
||||||
@@ -515,40 +521,12 @@ public class LanguageServerHarness {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Future<HighlightParams> getHighlightsFuture(TextDocumentInfo doc) {
|
public synchronized Future<HighlightParams> getHighlightsFuture(TextDocumentInfo doc) {
|
||||||
|
log.info("highlights requested");
|
||||||
CompletableFuture<HighlightParams> future = new CompletableFuture<HighlightParams>();
|
CompletableFuture<HighlightParams> future = new CompletableFuture<HighlightParams>();
|
||||||
highlights.put(doc.getUri(), future);
|
highlights.put(doc.getUri(), future);
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HighlightParams getHighlights(TextDocumentInfo doc) throws Exception {
|
|
||||||
return getHighlights(true, doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set expectServerHighlights to false if NO highlights are expected from the server (for example, test cases
|
|
||||||
* that test that no highlights are received from the server because there are no running apps).
|
|
||||||
* @param expectServerHighlights false if NOT expecting any highlights from the server
|
|
||||||
* @param doc
|
|
||||||
* @return highlights, if they are expected, or null if they are not expected.
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public HighlightParams getHighlights(boolean expectServerHighlights, TextDocumentInfo doc) throws Exception {
|
|
||||||
try {
|
|
||||||
return getHighlightsFuture(doc).get(HIGHLIGHTS_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
// highlight requestor will timeout if the server does not send any highlights. This
|
|
||||||
// is not always an error. For example, if there are no initial running apps, the server will
|
|
||||||
// NOT send highlights (see PT 156688501), so in this case we expect to time out as part of
|
|
||||||
// the expected behaviour
|
|
||||||
if (!expectServerHighlights) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Condition<Diagnostic> isDiagnosticWithSeverity(DiagnosticSeverity severity) {
|
public static Condition<Diagnostic> isDiagnosticWithSeverity(DiagnosticSeverity severity) {
|
||||||
return new Condition<>(
|
return new Condition<>(
|
||||||
(d) -> d.getSeverity()==severity,
|
(d) -> d.getSeverity()==severity,
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ public class ActiveProfilesHoverTest {
|
|||||||
"\n" +
|
"\n" +
|
||||||
"}"
|
"}"
|
||||||
);
|
);
|
||||||
|
editor.assertHighlights(/*NONE*/);
|
||||||
editor.assertHoverContains("@Profile", "Consider adding `spring-boot-actuator` as a dependency");
|
editor.assertHoverContains("@Profile", "Consider adding `spring-boot-actuator` as a dependency");
|
||||||
editor.assertNoHighlights();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -162,7 +162,7 @@ public class ActiveProfilesHoverTest {
|
|||||||
"\n" +
|
"\n" +
|
||||||
"}"
|
"}"
|
||||||
);
|
);
|
||||||
|
editor.assertHighlights(/*NONE*/);
|
||||||
editor.assertNoHover("@Profile");
|
editor.assertNoHover("@Profile");
|
||||||
editor.assertNoHighlights();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user