Fix error message in CA on services when not logged in

This commit is contained in:
Kris De Volder
2017-01-27 16:19:07 -08:00
parent 0d001d79ff
commit f53cf422ea
10 changed files with 120 additions and 43 deletions

View File

@@ -24,7 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Provides existing Cloud Foundry client params, like target and credentials,
* from the CLI config.json in the file system.
*
*
*
*/
public class CfCliParamsProvider implements ClientParamsProvider {
@@ -39,7 +39,7 @@ public class CfCliParamsProvider implements ClientParamsProvider {
/*
* (non-Javadoc)
*
*
* @see org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.
* ClientParamsProvider#getParams()
*/

View File

@@ -30,5 +30,6 @@ public interface ICompletionProposal {
String getDetail();
Renderable getDocumentation();
default String getFilterText() { return getLabel(); }
}

View File

@@ -105,7 +105,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
item.setLabel(completion.getLabel());
item.setKind(completion.getKind());
item.setSortText(sortkeys.next());
item.setFilterText(completion.getLabel());
item.setFilterText(completion.getFilterText());
item.setDetail(completion.getDetail());
item.setDocumentation(toMarkdown(completion.getDocumentation()));
adaptEdits(item, doc, completion.getTextEdit());

View File

@@ -24,16 +24,13 @@ public interface CompletionFactory {
ICompletionProposal beanProperty(IDocument doc, String contextProperty, YType contextType, String query, YTypedProperty p, double score, DocumentEdits edits, YTypeUtil typeUtil);
ICompletionProposal valueProposal(String value, String query, String label, YType type, double score, DocumentEdits edits, YTypeUtil typeUtil);
/**
* Creates a completion with an EMPTY value and a display message indicating some error condition. The purpose of this is
* to show the user a completion with some meaningful information on why completion values were not fetched.
*
* @param message the error message to display to the user in the completion
* @param query
* @param type
* @param edits
* @return non-null proposal
* Create a fake completion proposal that represents an error message. Such a proposal, when applied does nothing. Its main purpose is to
* show a (possibly lengthy) error message to the user.
* <p>
* If the error message is long you can include a ": " to divide the string into a 'short message' and a longer explanation. The longer explanation
* will be chopped-off from the message and displayed as a 'doc string'.
*/
ICompletionProposal errorMessage(String message, String query, YType type, DocumentEdits edits, YTypeUtil typeUtil);
ICompletionProposal errorMessage(String query, String message);
}

View File

@@ -16,6 +16,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.Document
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.yaml.hover.YPropertyInfoTemplates;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
@@ -23,7 +24,7 @@ import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
public class DefaultCompletionFactory implements CompletionFactory {
private static final int ERROR_COMPLETION_SCORE = -10000000;
public static class BeanPropertyProposal extends ScoreableProposal {
@@ -48,7 +49,7 @@ public class DefaultCompletionFactory implements CompletionFactory {
this.edits = edits;
this.typeUtil = typeUtil;
}
@Override
public double getBaseScore() {
return baseScore;
@@ -79,7 +80,7 @@ public class DefaultCompletionFactory implements CompletionFactory {
return YPropertyInfoTemplates.createCompletionDocumentation(contextProperty, contextType, p);
}
}
public class ValueProposal extends ScoreableProposal {
private String value;
@@ -119,7 +120,7 @@ public class DefaultCompletionFactory implements CompletionFactory {
public DocumentEdits getTextEdit() {
return edits;
}
@Override
public String toString() {
return "ValueProposal("+value+")";
@@ -135,38 +136,42 @@ public class DefaultCompletionFactory implements CompletionFactory {
return null;
}
}
public static final class ErrorProposal extends ScoreableProposal {
private final String label;
private DocumentEdits edits;
private YTypeUtil typeUtil;
private YType type;
public ErrorProposal(String label, YType type, DocumentEdits edits, YTypeUtil typeUtil) {
this.label = label;
this.edits = edits;
this.typeUtil = typeUtil;
this.type = type;
public static final class ErrorProposal extends ScoreableProposal {
private final String longMessage;
private String shortMessage;
private String filterText;
public ErrorProposal(String query, String longMessage) {
this.filterText = query;
int split = longMessage.indexOf(": ");
if (split>0) {
this.shortMessage = longMessage.substring(0, split);
this.longMessage = longMessage.substring(split+2);
} else {
this.longMessage = longMessage;
this.shortMessage = longMessage;
}
}
@Override
public DocumentEdits getTextEdit() {
return edits;
return new DocumentEdits(null);
}
@Override
public String getLabel() {
return label;
return shortMessage;
}
@Override
public CompletionItemKind getKind() {
return CompletionItemKind.Value;
return CompletionItemKind.Text;
}
@Override
public Renderable getDocumentation() {
return null;
return Renderables.text(longMessage);
}
@Override
@@ -181,7 +186,12 @@ public class DefaultCompletionFactory implements CompletionFactory {
@Override
public String getDetail() {
return typeUtil.niceTypeName(type);
return "Error";
}
@Override
public String getFilterText() {
return filterText;
}
}
@@ -196,8 +206,7 @@ public class DefaultCompletionFactory implements CompletionFactory {
}
@Override
public ICompletionProposal errorMessage(String message, String query, YType type, DocumentEdits edits, YTypeUtil typeUtil) {
final String label = message;
return new ErrorProposal(label, type, edits, typeUtil);
public ICompletionProposal errorMessage(String query, String longMessage) {
return new ErrorProposal(query, longMessage);
}
}

View File

@@ -158,8 +158,7 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
try {
values = typeUtil.getHintValues(type, getSchemaContext());
} catch (Exception e) {
DocumentEdits edits = new DocumentEdits(doc.getDocument());
return ImmutableList.of(completionFactory().errorMessage(getMessage(e), query, type, edits, typeUtil));
return ImmutableList.of(completionFactory().errorMessage(query, getMessage(e)));
}
if (values!=null) {
ArrayList<ICompletionProposal> completions = new ArrayList<>();

View File

@@ -444,7 +444,7 @@ public class Editor {
assertEquals(expectedHover, hover.getContents().toString());
}
public void assertCompletionDetails(String expectLabel, String expectDetail, String expectDocSnippet) throws Exception {
public CompletionItem assertCompletionDetails(String expectLabel, String expectDetail, String expectDocSnippet) throws Exception {
CompletionItem it = harness.resolveCompletionItem(assertCompletionWithLabel(expectLabel));
if (expectDetail!=null) {
assertEquals(expectDetail, it.getDetail());
@@ -452,6 +452,7 @@ public class Editor {
if (expectDocSnippet!=null) {
assertContains(expectDocSnippet, it.getDocumentation());
}
return it;
}
protected CompletionItem assertCompletionWithLabel(String expectLabel) throws Exception {

View File

@@ -11,8 +11,11 @@
package org.springframework.ide.vscode.languageserver.testharness;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Collection;
public class TestAsserts {
public static void assertContains(String needle, String haystack) {
@@ -26,4 +29,14 @@ public class TestAsserts {
fail("Found: "+needle+"\n in \n"+haystack);
}
}
public static <T> T assertOneElement(Collection<T> collection) {
assertEquals("Wrong number of elements in "+ collection, 1, collection.size());
for (T t : collection) {
return t;
}
throw new AssertionError("No elements found");
}
}

View File

@@ -39,10 +39,10 @@ public abstract class AbstractCFHintsProvider implements Callable<Collection<YVa
@Override
public Collection<YValueHint> call() throws Exception {
try {
List<CFTarget> targets = targetCache.getOrCreate();
// Do NOT wrap the results in another list. Allow null values to return
// as the reconcile framework expects null if hints failed to be resolved
return getHints(targets);
@@ -59,7 +59,7 @@ public abstract class AbstractCFHintsProvider implements Callable<Collection<YVa
// Do not log the no-targets exception as it may be encountered
// frequently
// if a user does not have a CF client installed
throw new ValueParseException(ExceptionUtil.getMessageNoAppendedInformation(noTargetsError));
throw new ValueParseException("No Cloudfoundry Targets: "+ExceptionUtil.getMessageNoAppendedInformation(noTargetsError));
} else {
// Log any other error
logger.log(Level.SEVERE, ExceptionUtil.getMessage(e), e);
@@ -77,7 +77,7 @@ public abstract class AbstractCFHintsProvider implements Callable<Collection<YVa
}
/**
*
*
* @return non-null list of hints. Return empty if no hints available
*/
abstract protected Collection<YValueHint> getHints(List<CFTarget> targets) throws Exception;

View File

@@ -15,7 +15,9 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.util.List;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.junit.Before;
@@ -27,9 +29,13 @@ import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientRequests
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFClientParams;
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFCredentials;
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.ClientParamsProvider;
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.NoTargetsException;
import org.springframework.ide.vscode.commons.util.CollectionUtil;
import org.springframework.ide.vscode.languageserver.testharness.Editor;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.*;
import com.google.common.collect.ImmutableList;
public class ManifestYamlEditorTest {
@@ -844,6 +850,57 @@ public class ManifestYamlEditorTest {
assertEquals(DiagnosticSeverity.Warning, problem.getSeverity());
}
@Test
public void servicesContentAssistShowErrorMessageWhenNotLoggedIn() throws Exception {
reset(cloudfoundry.paramsProvider);
String exceptionMessage = "Please login to cf";
when(cloudfoundry.paramsProvider.getParams()).thenThrow(new NoTargetsException(exceptionMessage));
String textBefore =
"applications:\n" +
"- name: foo\n" +
" services:\n" +
" - <*>";
Editor editor = harness.newEditor(
textBefore
);
//Applying the single completion should do nothing in the editor:
editor.assertCompletions(textBefore);
//The message from the exception should appear in the 'doc string':
editor.assertCompletionDetails("No Cloudfoundry Targets", "Error", exceptionMessage);
}
@Test
public void servicesContentAssistShowErrorMessageWhenNotLoggedIn_nonEmptyQueryString() throws Exception {
reset(cloudfoundry.paramsProvider);
String exceptionMessage = "Please login to cf";
when(cloudfoundry.paramsProvider.getParams()).thenThrow(new NoTargetsException(exceptionMessage));
String textBefore =
"applications:\n" +
"- name: foo\n" +
" services:\n" +
" - something<*>";
Editor editor = harness.newEditor(
textBefore
);
//Applying the single completion should do nothing in the editor:
editor.assertCompletions(textBefore);
//The message from the exception should appear in the 'doc string':
CompletionItem completion = editor.assertCompletionDetails("No Cloudfoundry Targets", "Error", exceptionMessage);
//query string should match the 'filter text' otherwise vscode will filter the item and it will be gone!
assertEquals("something", completion.getFilterText());
}
//////////////////////////////////////////////////////////////////////////////
private void assertCompletions(String textBefore, String... textAfter) throws Exception {