diff --git a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDeploymentManifestSchema.java b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDeploymentManifestSchema.java index 26d4364cb..3db01e150 100644 --- a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDeploymentManifestSchema.java +++ b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDeploymentManifestSchema.java @@ -104,9 +104,8 @@ public class BoshDeploymentManifestSchema implements YamlSchema { YAtomicType t_ip_address = f.yatomic("IPAddress"); //TODO: some kind of checking? t_ip_address.parseWith(ValueParsers.NE_STRING); - YAtomicType t_url = f.yatomic("URL"); //TODO: some kind of checking? - t_url.parseWith(ValueParsers.NE_STRING); - + YAtomicType t_url = f.yatomic("URL"); + t_url.parseWith(BoshValueParsers.url("http", "https", "file")); YAtomicType t_network_name = f.yatomic("NetworkName"); //TODO: resolve from 'cloud config' https://www.pivotaltracker.com/story/show/148712155 t_network_name.parseWith(ValueParsers.NE_STRING); diff --git a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshValueParsers.java b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshValueParsers.java index e3ba47b77..58eda3b46 100644 --- a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshValueParsers.java +++ b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshValueParsers.java @@ -10,10 +10,44 @@ *******************************************************************************/ package org.springframework.ide.vscode.bosh; +import java.net.URI; + import org.springframework.ide.vscode.commons.util.ValueParseException; import org.springframework.ide.vscode.commons.util.ValueParser; +import com.google.common.collect.ImmutableList; + public class BoshValueParsers { + + public static ValueParser url(String... _schemes) { + return new ValueParser() { + + private final ImmutableList validSchemes = ImmutableList.copyOf(_schemes); + + @Override + public Object parse(String s) throws Exception { + URI uri = new URI(s); + String scheme = uri.getScheme(); + if (scheme==null) { + throw new ValueParseException(message()); + } else if (!validSchemes.contains(scheme.toLowerCase())) { + int start = s.indexOf(scheme); + if (start>=0) { + int end = start + scheme.length(); + throw new ValueParseException(message(), start, end); + } else { + // Trouble finding exact location of underlined region so underline whole url + throw new ValueParseException(message()); + } + } + return uri; + } + + private String message() { + return "Url scheme must be one of "+validSchemes; + } + }; + } public static final ValueParser INTEGER_OR_RANGE = new ValueParser() { diff --git a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshEditorTest.java b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshEditorTest.java index 18d363498..32ac05e00 100644 --- a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshEditorTest.java +++ b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshEditorTest.java @@ -232,22 +232,25 @@ public class BoshEditorTest { ); } - @Test public void releasesBlockSha1RequiredForHttpUrl() throws Exception { + @Test public void releasesAdvancedValidations() throws Exception { Editor editor = harness.newEditor( "releases:\n" + "- name: some-release\n" + " url: https://my.releases.com/funky.tar.gz\n" + "- name: other-relase\n" + " url: file:///root/releases/a-nice-file.tar.gz\n" + + "- name: bad-url\n" + + " url: proto://something.com\n" + "#x" ); editor.assertProblems( "url|'sha1' is required when the 'url' is http(s)", + "proto|Url scheme must be one of [http, https, file]", "x|are required" ); } - @Test public void releasesBlockReconcileAndHovers() throws Exception { + @Test public void releasesBlockPropertyReconcileAndHovers() throws Exception { Editor editor = harness.newEditor( "releases:\n" + "- name: some-release\n" + @@ -407,10 +410,6 @@ public class BoshEditorTest { editor.assertHoverContains("env", "Specifies advanced BOSH Agent configuration"); } - @Test public void complexManifestValidation() throws Exception { - - } - @Test public void instanceGroups_job_hovers() throws Exception { Editor editor = harness.newEditor( "name: foo\n" + diff --git a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshValueParserTest.java b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshValueParserTest.java index 604b1a82b..3c814eae9 100644 --- a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshValueParserTest.java +++ b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshValueParserTest.java @@ -35,6 +35,23 @@ public class BoshValueParserTest { assertProblem(BoshValueParsers.INTEGER_OR_RANGE, "<*>123-122<*>", "123 should be smaller than 122"); } + @Test public void urlOkay() throws Exception { + ValueParser urlParser = BoshValueParsers.url("http", "https", "file"); + urlParser.parse("http://foobar.com/munhings.tar.gz"); + urlParser.parse("https://foobar.com/munhings.tar.gz"); + urlParser.parse("hTTp://foobar.com/munhings.tar.gz"); + urlParser.parse("HTTPS://foobar.com/munhings.tar.gz"); + urlParser.parse("file://local/file"); + urlParser.parse("file:///local/file"); + urlParser.parse("FILE:///local/file"); + } + + @Test public void urlGarbage() throws Exception { + ValueParser urlParser = BoshValueParsers.url("http", "https", "file"); + assertProblem(urlParser, "<*>woot<*>://foobar.com", "Url scheme must be one of [http, https, file]"); + assertProblem(urlParser, "<*>wOOt<*>://foobar.com", "Url scheme must be one of [http, https, file]"); + } + private void assertProblem(ValueParser parser, String input, String expectedMessage) throws Exception { String unmarkedInput = input.replace(MARKER, ""); int firstMarker = input.indexOf(MARKER);