Route validation

Route value validation

Adjust validation

Unit tests
This commit is contained in:
BoykoAlex
2017-04-06 22:40:03 -04:00
parent 0cae62d96a
commit 55f50029e9
15 changed files with 2052 additions and 4 deletions

View File

@@ -0,0 +1,22 @@
package org.springframework.ide.vscode.commons.cloudfoundry.client;
public interface CFRoute {
int NO_PORT = -1;
String EMPTY_ROUTE = "";
public static CFRouteBuilder builder() {
return new CFRouteBuilder();
}
String getDomain();
String getHost();
String getPath();
int getPort();
String getRoute();
}

View File

@@ -0,0 +1,237 @@
package org.springframework.ide.vscode.commons.cloudfoundry.client;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.cloudfoundry.operations.routes.Route;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.StringUtil;
public class CFRouteBuilder {
private String domain;
private String host;
private String path;
private int port = CFRoute.NO_PORT;
private String fullRoute;
public CFRoute build() {
return new CFRouteImpl(this.domain, this.host, this.path, this.port, this.fullRoute);
}
public CFRouteBuilder domain(String domain) {
this.domain = domain;
// may seem like the more ideal place is to build the full route when
// building the route, rather than repeating
// the process each time a domain, host, path or port value is set
// but the "from" option should be allowed to overwrite the full route
// as well since it already
// has the full value. Therefore re-construct the full value if the
// route is being built piece by piece, but not in from
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
public CFRouteBuilder host(String host) {
this.host = host;
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
public CFRouteBuilder path(String path) {
this.path = path;
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
public CFRouteBuilder port(int port) {
this.port = port;
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
public CFRouteBuilder from(Route route) {
// Route doesn't seem to have API to get a port
this.port = CFRoute.NO_PORT;
this.domain = route.getDomain();
this.host = route.getHost();
this.path = route.getPath();
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
/**
* Builds a {@link CFRoute} given a desiredUrl. This does NOT validate, and
* will attempt to build a route the best way it can given the desiredUrl.
* External components, like the CF Java client, can then validate the
* CFRoute.
*
* @param desiredUrl
* @param domains
* @return this builder
*/
public CFRouteBuilder from(String desiredUrl, Collection<String> domains) {
//If it is empty or null, there is nothing to build. However, be sure that the
// full route value is non-null, even if the "components" may be null
if (!StringUtil.hasText(desiredUrl)) {
this.fullRoute = CFRoute.EMPTY_ROUTE;
return this;
} else {
// Be sure to set the full route.
this.fullRoute = desiredUrl;
}
// Based on CLI cf/actors/routes.go and testing CLI directly with
// different "routes" values:
// 1. Paths is not allowed in TCP route (valid TCP route:
// "tcp.spring.io:8888")
// 2. Ports are not allowed in HTTP route (valid HTTP route:
// "myapps.cfapps.io/pathToApp/home")
// 3. Schemes (e.g. "http://") are not allowed in routes values.
// Anything that has a ":" is assumed to be TCP route followed by a port
// 4. Route can just be domain, or host and domain
//
// Therefore, routes values cannot be treated as URIs or URLs, but a
// combination of domain, host, path and port
// NOTE: The validation above doesn't need to take place here. The
// client or CF will validate correct combinations of routes.
// However, We may want to implement similar
// validation to the CF manifest editor though.
String matchedHost = null;
String hostAndDomain = null;
// Split into hostDomain segment, port and path
int slashIndex = desiredUrl.indexOf('/');
if (slashIndex >= 0) {
hostAndDomain = desiredUrl.substring(0, slashIndex);
String tempPath = desiredUrl.substring(slashIndex);
// Do not set empty strings. If there is no path, then it should be
// null
if (StringUtil.hasText(tempPath)) {
this.path = tempPath;
}
} else {
hostAndDomain = desiredUrl;
}
// CF Route builder does not validate, so don't allow exceptions to
// prevent parsing of the route. The builder should attempt to build
// a route the best way it can, even if it may have invalid information.
// This allows external participants, like the CF Java client, to
// perform validation
try {
String[] portSegments = hostAndDomain.split(":");
if (portSegments.length == 2) {
hostAndDomain = portSegments[0];
this.port = Integer.parseInt(portSegments[1]);
}
} catch (NumberFormatException e) {
Log.log(e);
}
this.domain = findDomain(hostAndDomain, domains);
if (this.domain != null) {
matchedHost = hostAndDomain.substring(0, hostAndDomain.length() - this.domain.length());
if (matchedHost.endsWith(".")) {
matchedHost = matchedHost.substring(0, matchedHost.length() - 1);
}
// Don't set empty strings
if (StringUtil.hasText(matchedHost)) {
this.host = matchedHost;
}
} else {
// Do a basic split on '.', where first segment is the host, and the
// rest domain
int firstDotIndex = hostAndDomain.indexOf('.');
if (firstDotIndex >= 0) {
String tempDomain = hostAndDomain.substring(firstDotIndex + 1);
// Don't set empty strings
if (StringUtil.hasText(tempDomain)) {
this.domain = tempDomain;
}
String tempHost = hostAndDomain.substring(0, firstDotIndex);
if (StringUtil.hasText(tempHost)) {
this.host = tempHost;
}
} else {
if (StringUtil.hasText(hostAndDomain)) {
this.host = hostAndDomain;
}
}
}
return this;
}
public static String findDomain(String hostDomain, Collection<String> domains) {
if (hostDomain == null) {
return null;
}
// find exact match
for (String name : domains) {
if (hostDomain.equals(name)) {
return hostDomain;
}
}
// Otherwise split on the first "." and try again
if (hostDomain.indexOf(".") >= 0 && hostDomain.indexOf(".") + 1 < hostDomain.length()) {
String remaining = hostDomain.substring(hostDomain.indexOf(".") + 1, hostDomain.length());
return findDomain(remaining, domains);
} else {
return null;
}
}
/**
* A basic building of a full route value. It performs no validation, just
* builds based on whether the parameter are set
*
* @param host
* @param domain
* @param path
* @param port
* @return Route value build with the given components. Always returns a non-null route. Empty route if no arguments are passed.
*/
public static String buildRouteVal(String host, String domain, String path, int port) {
StringBuilder builder = new StringBuilder();
if (StringUtil.hasText(host)) {
builder.append(host);
}
if (StringUtil.hasText(domain)) {
if (StringUtil.hasText(host)) {
builder.append('.');
}
builder.append(domain);
}
if (port != CFRoute.NO_PORT) {
builder.append(':');
builder.append(Integer.toString(port));
}
if (StringUtil.hasText(path)) {
if (!path.startsWith("/")) {
builder.append('/');
}
builder.append(path);
}
return builder.toString();
}
public CFRouteBuilder from(String desiredUrl, List<CFDomain> cloudDomains) {
List<String> domains = cloudDomains
.stream()
.map(CFDomain::getName)
.collect(Collectors.toList());
return from(desiredUrl, domains);
}
}

View File

@@ -0,0 +1,92 @@
package org.springframework.ide.vscode.commons.cloudfoundry.client;
class CFRouteImpl implements CFRoute {
final private String domain;
final private String host;
final private String path;
final private int port;
final private String fullRoute;
CFRouteImpl(String domain, String host, String path, int port, String fullRoute) {
super();
this.domain = domain;
this.host = host;
this.path = path;
this.port = port;
this.fullRoute = fullRoute;
}
public String getDomain() {
return domain;
}
public String getHost() {
return host;
}
public String getPath() {
return path;
}
public int getPort() {
return port;
}
public String getRoute() {
return fullRoute;
}
@Override
public String toString() {
return "CFRoute [domain=" + domain + ", host=" + host + ", path=" + path + ", port=" + port +"]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((domain == null) ? 0 : domain.hashCode());
result = prime * result + ((fullRoute == null) ? 0 : fullRoute.hashCode());
result = prime * result + ((host == null) ? 0 : host.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result + port;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CFRouteImpl other = (CFRouteImpl) obj;
if (domain == null) {
if (other.domain != null)
return false;
} else if (!domain.equals(other.domain))
return false;
if (fullRoute == null) {
if (other.fullRoute != null)
return false;
} else if (!fullRoute.equals(other.fullRoute))
return false;
if (host == null) {
if (other.host != null)
return false;
} else if (!host.equals(other.host))
return false;
if (path == null) {
if (other.path != null)
return false;
} else if (!path.equals(other.path))
return false;
if (port != other.port)
return false;
return true;
}
}

View File

@@ -0,0 +1,578 @@
package org.springframework.ide.vscode.commons.cloudfoundry.client;
import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
public class CFRouteTest {
public static final List<String> SPRING_CLOUD_DOMAINS = Arrays.<String>asList("springsource.org", "spring.io",
"myowndomain.spring.io", "tcp.spring.io", "spring.framework");
@Test
public void test_domain_host() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.spring.io", route.getRoute());
}
@Test
public void test_domain_only() throws Exception {
CFRoute route = CFRoute.builder().from("spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("spring.io", route.getRoute());
}
@Test
public void test_longer_domain_match() throws Exception {
CFRoute route = CFRoute.builder().from("myowndomain.spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("myowndomain.spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myowndomain.spring.io", route.getRoute());
}
@Test
public void test_longer_domain_nonexisting() throws Exception {
// For domains that do not exist, the first segment is assumed to be the "host"
CFRoute route = CFRoute.builder().from("app.doesnotexist.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("doesnotexist.io", route.getDomain());
Assert.assertEquals("app",route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("app.doesnotexist.io", route.getRoute());
}
@Test
public void test_longer_domain_nonexisting_path() throws Exception {
CFRoute route = CFRoute.builder().from("app.doesnotexist.io/withpath", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("doesnotexist.io", route.getDomain());
Assert.assertEquals("app",route.getHost());
Assert.assertEquals("/withpath",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("app.doesnotexist.io/withpath", route.getRoute());
}
@Test
public void test_longer_domain_nonexisting_path_port() throws Exception {
CFRoute route = CFRoute.builder().from("app.doesnotexist.io:60100/withpath", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("doesnotexist.io", route.getDomain());
Assert.assertEquals("app",route.getHost());
Assert.assertEquals("/withpath",route.getPath());
Assert.assertEquals(60100, route.getPort());
Assert.assertEquals("app.doesnotexist.io:60100/withpath", route.getRoute());
}
@Test
public void test_longer_domain_match_2() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.myowndomain.spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("myowndomain.spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.myowndomain.spring.io", route.getRoute());
}
@Test
public void test_domain_host_path() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io/appPath", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertEquals("/appPath", route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.spring.io/appPath", route.getRoute());
}
@Test
public void test_domain_host_path_2() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io/appPath/additionalSegment", SPRING_CLOUD_DOMAINS)
.build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertEquals("/appPath/additionalSegment", route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.spring.io/appPath/additionalSegment", route.getRoute());
}
@Test
public void test_tcp_port() throws Exception {
CFRoute route = CFRoute.builder().from("tcp.spring.io:9000", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("tcp.spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(9000, route.getPort());
Assert.assertEquals("tcp.spring.io:9000", route.getRoute());
}
@Test
public void test_host_path() throws Exception {
CFRoute route = CFRoute.builder().from("justhost/path", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("justhost",route.getHost());
Assert.assertEquals("/path",route.getPath());
Assert.assertEquals("justhost/path",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
}
@Test
public void test_routes() throws Exception {
// A CFRoute does not validate route values. It can create any CF route even with wrong domains
// ports, hosts.. This tests that the route builder is parsing an invalid route into different
// components that some other external mechanism (like the CF Java client) can the use to validate
CFRoute route = CFRoute.builder().from("", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.EMPTY_ROUTE,route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from(null, SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.EMPTY_ROUTE,route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from(".", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(".",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("justhost", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("justhost",route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals("justhost",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("justhost.", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("justhost",route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals("justhost.",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from(".justdomain", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("justdomain",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(".justdomain",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("..justdomain", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals(".justdomain",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals("..justdomain",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("/justpath/morepath", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/justpath/morepath",route.getPath());
Assert.assertEquals("/justpath/morepath",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("/", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/",route.getPath());
Assert.assertEquals("/",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
}
@Test
public void test_incorrect_ports() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io:notAn1nt3g3r", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals("myapp.spring.io:notAn1nt3g3r",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
// Test parsing around the first encountered ':'
route = CFRoute.builder().from("http://myapp.spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("http://myapp.spring.io",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("tcp.spring.io:8000:9000", SPRING_CLOUD_DOMAINS).build();
// Only one ':' is allowed. it should not be able to parse a port if more than ':' is encountered
Assert.assertEquals("tcp.spring.io:8000:9000",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("myapp.spring.io:8000/", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/",route.getPath());
Assert.assertEquals("myapp.spring.io:8000/",route.getRoute());
Assert.assertEquals(8000, route.getPort());
}
@Test
public void test_incorrect_paths() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io//path", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("//path",route.getPath());
Assert.assertEquals("myapp.spring.io//path",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("myapp.spring.io/", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/",route.getPath());
Assert.assertEquals("myapp.spring.io/",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
}
@Test
public void parse_null_domain() throws Exception {
String domain = CFRouteBuilder.findDomain("", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain(null, SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain(".", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain(".cfapps", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("cfapps.", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("...", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("..cfapps..", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain(".cfapps..", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("..cfapps.", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
}
@Test
public void parse_valid_domain() throws Exception {
// These exist
String domain = CFRouteBuilder.findDomain("spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("spring.io", domain);
domain = CFRouteBuilder.findDomain(".spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("spring.io", domain);
domain = CFRouteBuilder.findDomain("..spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("spring.io", domain);
domain = CFRouteBuilder.findDomain("myapp.spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("spring.io", domain);
domain = CFRouteBuilder.findDomain("myowndomain.spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("myowndomain.spring.io", domain);
domain = CFRouteBuilder.findDomain("myapp.myowndomain.spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("myowndomain.spring.io", domain);
}
@Test
public void parse_invalid_domain() throws Exception {
// These variations of existing domains don't exist
String domain = CFRouteBuilder.findDomain("spring.io.", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("spring.cfapps.io", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("spring.io.cfapps", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("unknown", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("unknown.domain.io", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
}
@Test
public void bug_142279275_parse_hostAndPathSameName() throws Exception {
// Fixes Pivotal Tracker item 142279275
CFRoute route = CFRoute.builder().from("hello-user.myowndomain.spring.io/hello", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("hello-user", route.getHost());
Assert.assertEquals("myowndomain.spring.io", route.getDomain());
Assert.assertEquals("/hello", route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("hello-user.myowndomain.spring.io/hello", route.getRoute());
}
@Test
public void build_route_value_empty() throws Exception {
String val = CFRouteBuilder.buildRouteVal(null, null, null, CFRoute.NO_PORT);
Assert.assertEquals(CFRoute.EMPTY_ROUTE, val);
val = CFRouteBuilder.buildRouteVal("", "", "", CFRoute.NO_PORT);
Assert.assertEquals(CFRoute.EMPTY_ROUTE, val);
}
@Test
public void build_route_value() throws Exception {
String val = CFRouteBuilder.buildRouteVal("appHost", null, null, CFRoute.NO_PORT);
Assert.assertEquals("appHost", val);
val = CFRouteBuilder.buildRouteVal(null, "cfapps.io", "", CFRoute.NO_PORT);
Assert.assertEquals("cfapps.io", val);
val = CFRouteBuilder.buildRouteVal("appHost", "cfapps.io", "", CFRoute.NO_PORT);
Assert.assertEquals("appHost.cfapps.io", val);
val = CFRouteBuilder.buildRouteVal(null, null, "/path/to/app", CFRoute.NO_PORT);
Assert.assertEquals("/path/to/app", val);
val = CFRouteBuilder.buildRouteVal(null, null, "/path/to/app", 8000);
Assert.assertEquals(":8000/path/to/app", val);
val = CFRouteBuilder.buildRouteVal(null, null, null, 60101);
Assert.assertEquals(":60101", val);
val = CFRouteBuilder.buildRouteVal("appHost", "cfapps.io", "/path/to/app", CFRoute.NO_PORT);
Assert.assertEquals("appHost.cfapps.io/path/to/app", val);
val = CFRouteBuilder.buildRouteVal("appHost", "cfapps.io", "/path/to/app", 60101);
Assert.assertEquals("appHost.cfapps.io:60101/path/to/app", val);
}
@Test
public void test_build_route_from_domain() throws Exception {
CFRoute route = CFRoute.builder().domain("spring.io").build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("spring.io", route.getRoute());
}
@Test
public void test_build_route_from_nonexisting_domain() throws Exception {
CFRoute route = CFRoute.builder().domain("not.exist.io").build();
Assert.assertEquals("not.exist.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("not.exist.io", route.getRoute());
}
@Test
public void test_build_route_from_null_domain() throws Exception {
CFRoute route = CFRoute.builder().domain(null).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_build_route_from_empty_domain() throws Exception {
CFRoute route = CFRoute.builder().domain("").build();
Assert.assertEquals("",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE,route.getRoute());
}
@Test
public void test_build_route_from_host() throws Exception {
CFRoute route = CFRoute.builder().host("myapp").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getPath());
Assert.assertEquals("myapp", route.getHost());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp", route.getRoute());
}
@Test
public void test_build_route_from_null_host() throws Exception {
CFRoute route = CFRoute.builder().host(null).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getPath());
Assert.assertNull(route.getHost());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_build_route_from_empty_host() throws Exception {
CFRoute route = CFRoute.builder().host("").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getPath());
Assert.assertEquals("",route.getHost());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_build_route_from_domain_host() throws Exception {
CFRoute route = CFRoute.builder().domain("spring.io").host("myapp").build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.spring.io", route.getRoute());
}
@Test
public void test_build_route_from_path() throws Exception {
CFRoute route = CFRoute.builder().path("/path").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/path",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("/path", route.getRoute());
}
@Test
public void test_build_route_from_path_2() throws Exception {
CFRoute route = CFRoute.builder().path("/path/additional").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/path/additional",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("/path/additional", route.getRoute());
}
@Test
public void test_build_route_from_path_3() throws Exception {
CFRoute route = CFRoute.builder().path("/path/").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/path/",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("/path/", route.getRoute());
}
@Test
public void test_build_route_from_domain_path() throws Exception {
CFRoute route = CFRoute.builder().path("/mypath").domain("spring.io").build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/mypath",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("spring.io/mypath", route.getRoute());
}
@Test
public void test_build_route_from_host_path() throws Exception {
CFRoute route = CFRoute.builder().path("/mypath").host("myapp").build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/mypath",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp/mypath", route.getRoute());
}
@Test
public void test_build_route_from_host_path_samename() throws Exception {
CFRoute route = CFRoute.builder().path("/myapp").host("myapp").build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/myapp",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp/myapp", route.getRoute());
}
@Test
public void test_build_route_from_host_path_port() throws Exception {
CFRoute route = CFRoute.builder().path("/mypath").host("myapp").port(8000).build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/mypath",route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals("myapp:8000/mypath", route.getRoute());
}
@Test
public void test_build_route_from_domain_path_port() throws Exception {
CFRoute route = CFRoute.builder().path("/mypath").domain("spring.io").port(8000).build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/mypath",route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals("spring.io:8000/mypath", route.getRoute());
}
@Test
public void test_build_route_from_port() throws Exception {
CFRoute route = CFRoute.builder().port(8000).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals(":8000", route.getRoute());
}
@Test
public void test_build_route_from_no_port() throws Exception {
CFRoute route = CFRoute.builder().port(CFRoute.NO_PORT).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_build_route_from_no_port_2() throws Exception {
CFRoute route = CFRoute.builder().port(-1).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_tcp_port_building() throws Exception {
CFRoute route = CFRoute.builder().domain("tcp.spring.io").port(8000).build();
Assert.assertEquals("tcp.spring.io",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals("tcp.spring.io:8000", route.getRoute());
}
@Test
public void test_complete() throws Exception {
CFRoute route = CFRoute.builder().domain("spring.io").host("myapp").path("/mypath/additional").port(8000).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertEquals("/mypath/additional", route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals("myapp.spring.io:8000/mypath/additional", route.getRoute());
}
}

View File

@@ -28,6 +28,11 @@ public class ReconcileException extends ValueParseException implements ProblemTy
this.problemType = problemType;
}
public ReconcileException(String message, ProblemType problemType, int start, int end) {
super(message, start, end);
this.problemType = problemType;
}
@Override
public ProblemType getProblemType() {
return problemType;

View File

@@ -18,6 +18,9 @@ package org.springframework.ide.vscode.commons.util;
*/
public class ValueParseException extends Exception {
private int startIndex = -1;
private int endIndex = -1;
/**
*
*/
@@ -26,5 +29,19 @@ public class ValueParseException extends Exception {
public ValueParseException(String message) {
super(message);
}
public ValueParseException(String message, int startIndex, int endIndex) {
this(message);
this.startIndex = startIndex;
this.endIndex = endIndex;
}
public int getStartIndex() {
return startIndex;
}
public int getEndIndex() {
return endIndex;
}
}

View File

@@ -179,8 +179,21 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
}
} catch (Exception e) {
ProblemType problemType = getProblemType(e);
DocumentRegion region = new DocumentRegion(doc, node.getStartMark().getIndex(), node.getEndMark().getIndex());
if (e instanceof ValueParseException) {
ValueParseException parseException = (ValueParseException) e;
int start = parseException.getStartIndex() >= 0
? Math.min(node.getStartMark().getIndex() + parseException.getStartIndex(),
node.getEndMark().getIndex())
: node.getStartMark().getIndex();
int end = parseException.getEndIndex() >= 0
? Math.min(node.getStartMark().getIndex() + parseException.getEndIndex(),
node.getEndMark().getIndex())
: node.getEndMark().getIndex();
region = new DocumentRegion(doc, start, end);
}
String msg = getMessage(e);
valueParseError(type, node, msg, problemType);
valueParseError(type, region, msg, problemType);
}
}
} else {
@@ -192,7 +205,7 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
}
}
}
private String getMessage(Exception _e) {
Throwable e = ExceptionUtil.getDeepestCause(_e);
@@ -328,6 +341,13 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
problem(node, parseErrorMsg, problemType);
}
private void valueParseError(YType type, DocumentRegion region, String parseErrorMsg, ProblemType problemType) {
if (!StringUtil.hasText(parseErrorMsg)) {
parseErrorMsg= "Couldn't parse as '"+describe(type)+"'";
}
problem(region, parseErrorMsg, problemType);
}
private void unknownBeanProperty(Node keyNode, YType type, String name) {
problem(keyNode, "Unknown property '"+name+"' for type '"+typeUtil.niceTypeName(type)+"'");
}
@@ -385,6 +405,10 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
problems.accept(YamlSchemaProblems.problem(problemType, msg, node));
}
private void problem(DocumentRegion region, String msg, ProblemType problemType) {
problems.accept(YamlSchemaProblems.problem(problemType, msg, region));
}
private void problem(DocumentRegion region, String msg) {
problems.accept(YamlSchemaProblems.schemaProblem(msg, region));
}

View File

@@ -0,0 +1,22 @@
package org.springframework.ide.vscode.commons.cloudfoundry.client;
public interface CFRoute {
int NO_PORT = -1;
String EMPTY_ROUTE = "";
static CFRouteBuilder builder() {
return new CFRouteBuilder();
}
String getDomain();
String getHost();
String getPath();
int getPort();
String getRoute();
}

View File

@@ -0,0 +1,238 @@
package org.springframework.ide.vscode.commons.cloudfoundry.client;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.cloudfoundry.operations.routes.Route;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.StringUtil;
public class CFRouteBuilder {
private String domain;
private String host;
private String path;
private int port = CFRoute.NO_PORT;
private String fullRoute;
public CFRoute build() {
return new CFRouteImpl(this.domain, this.host, this.path, this.port, this.fullRoute);
}
public CFRouteBuilder domain(String domain) {
this.domain = domain;
// may seem like the more ideal place is to build the full route when
// building the route, rather than repeating
// the process each time a domain, host, path or port value is set
// but the "from" option should be allowed to overwrite the full route
// as well since it already
// has the full value. Therefore re-construct the full value if the
// route is being built piece by piece, but not in from
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
public CFRouteBuilder host(String host) {
this.host = host;
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
public CFRouteBuilder path(String path) {
this.path = path;
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
public CFRouteBuilder port(int port) {
this.port = port;
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
public CFRouteBuilder from(Route route) {
// Route doesn't seem to have API to get a port
this.port = CFRoute.NO_PORT;
this.domain = route.getDomain();
this.host = route.getHost();
this.path = route.getPath();
this.fullRoute = buildRouteVal(this.host, this.domain, this.path, this.port);
return this;
}
/**
* Builds a {@link CFRoute} given a desiredUrl. This does NOT validate, and
* will attempt to build a route the best way it can given the desiredUrl.
* External components, like the CF Java client, can then validate the
* CFRoute.
*
* @param desiredUrl
* @param domains
* @return this builder
*/
public CFRouteBuilder from(String desiredUrl, Collection<String> domains) {
//If it is empty or null, there is nothing to build. However, be sure that the
// full route value is non-null, even if the "components" may be null
if (!StringUtil.hasText(desiredUrl)) {
this.fullRoute = CFRoute.EMPTY_ROUTE;
return this;
} else {
// Be sure to set the full route.
this.fullRoute = desiredUrl;
}
// Based on CLI cf/actors/routes.go and testing CLI directly with
// different "routes" values:
// 1. Paths is not allowed in TCP route (valid TCP route:
// "tcp.spring.io:8888")
// 2. Ports are not allowed in HTTP route (valid HTTP route:
// "myapps.cfapps.io/pathToApp/home")
// 3. Schemes (e.g. "http://") are not allowed in routes values.
// Anything that has a ":" is assumed to be TCP route followed by a port
// 4. Route can just be domain, or host and domain
//
// Therefore, routes values cannot be treated as URIs or URLs, but a
// combination of domain, host, path and port
// NOTE: The validation above doesn't need to take place here. The
// client or CF will validate correct combinations of routes.
// However, We may want to implement similar
// validation to the CF manifest editor though.
String matchedHost = null;
String hostAndDomain = null;
// Split into hostDomain segment, port and path
int slashIndex = desiredUrl.indexOf('/');
if (slashIndex >= 0) {
hostAndDomain = desiredUrl.substring(0, slashIndex);
String tempPath = desiredUrl.substring(slashIndex);
// Do not set empty strings. If there is no path, then it should be
// null
if (StringUtil.hasText(tempPath)) {
this.path = tempPath;
}
} else {
hostAndDomain = desiredUrl;
}
// CF Route builder does not validate, so don't allow exceptions to
// prevent parsing of the route. The builder should attempt to build
// a route the best way it can, even if it may have invalid information.
// This allows external participants, like the CF Java client, to
// perform validation
try {
String[] portSegments = hostAndDomain.split(":");
if (portSegments.length == 2) {
hostAndDomain = portSegments[0];
this.port = Integer.parseInt(portSegments[1]);
}
} catch (NumberFormatException e) {
Log.log(e);
}
this.domain = findDomain(hostAndDomain, domains);
if (this.domain != null) {
matchedHost = hostAndDomain.substring(0, hostAndDomain.length() - this.domain.length());
if (matchedHost.endsWith(".")) {
matchedHost = matchedHost.substring(0, matchedHost.length() - 1);
}
// Don't set empty strings
if (StringUtil.hasText(matchedHost)) {
this.host = matchedHost;
}
} else {
// Do a basic split on '.', where first segment is the host, and the
// rest domain
int firstDotIndex = hostAndDomain.indexOf('.');
if (firstDotIndex >= 0) {
String tempDomain = hostAndDomain.substring(firstDotIndex + 1);
// Don't set empty strings
if (StringUtil.hasText(tempDomain)) {
this.domain = tempDomain;
}
String tempHost = hostAndDomain.substring(0, firstDotIndex);
if (StringUtil.hasText(tempHost)) {
this.host = tempHost;
}
} else {
if (StringUtil.hasText(hostAndDomain)) {
this.host = hostAndDomain;
}
}
}
return this;
}
public static String findDomain(String hostDomain, Collection<String> domains) {
if (hostDomain == null) {
return null;
}
// find exact match
for (String name : domains) {
if (hostDomain.equals(name)) {
return hostDomain;
}
}
// Otherwise split on the first "." and try again
if (hostDomain.indexOf(".") >= 0 && hostDomain.indexOf(".") + 1 < hostDomain.length()) {
String remaining = hostDomain.substring(hostDomain.indexOf(".") + 1, hostDomain.length());
return findDomain(remaining, domains);
} else {
return null;
}
}
/**
* A basic building of a full route value. It performs no validation, just
* builds based on whether the parameter are set
*
* @param host
* @param domain
* @param path
* @param port
* @return Route value build with the given components. Always returns a non-null route. Empty route if no arguments are passed.
*/
public static String buildRouteVal(String host, String domain, String path, int port) {
StringBuilder builder = new StringBuilder();
if (StringUtil.hasText(host)) {
builder.append(host);
}
if (StringUtil.hasText(domain)) {
if (StringUtil.hasText(host)) {
builder.append('.');
}
builder.append(domain);
}
if (port != CFRoute.NO_PORT) {
builder.append(':');
builder.append(Integer.toString(port));
}
if (StringUtil.hasText(path)) {
if (!path.startsWith("/")) {
builder.append('/');
}
builder.append(path);
}
return builder.toString();
}
public CFRouteBuilder from(String desiredUrl, List<CFDomain> cloudDomains) {
List<String> domains = cloudDomains
.stream()
.map(CFDomain::getName)
.collect(Collectors.toList());
return from(desiredUrl, domains);
}
}

View File

@@ -0,0 +1,92 @@
package org.springframework.ide.vscode.commons.cloudfoundry.client;
class CFRouteImpl implements CFRoute {
final private String domain;
final private String host;
final private String path;
final private int port;
final private String fullRoute;
CFRouteImpl(String domain, String host, String path, int port, String fullRoute) {
super();
this.domain = domain;
this.host = host;
this.path = path;
this.port = port;
this.fullRoute = fullRoute;
}
public String getDomain() {
return domain;
}
public String getHost() {
return host;
}
public String getPath() {
return path;
}
public int getPort() {
return port;
}
public String getRoute() {
return fullRoute;
}
@Override
public String toString() {
return "CFRoute [domain=" + domain + ", host=" + host + ", path=" + path + ", port=" + port +"]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((domain == null) ? 0 : domain.hashCode());
result = prime * result + ((fullRoute == null) ? 0 : fullRoute.hashCode());
result = prime * result + ((host == null) ? 0 : host.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result + port;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CFRouteImpl other = (CFRouteImpl) obj;
if (domain == null) {
if (other.domain != null)
return false;
} else if (!domain.equals(other.domain))
return false;
if (fullRoute == null) {
if (other.fullRoute != null)
return false;
} else if (!fullRoute.equals(other.fullRoute))
return false;
if (host == null) {
if (other.host != null)
return false;
} else if (!host.equals(other.host))
return false;
if (path == null) {
if (other.path != null)
return false;
} else if (!path.equals(other.path))
return false;
if (port != other.port)
return false;
return true;
}
}

View File

@@ -0,0 +1,578 @@
package org.springframework.ide.vscode.commons.cloudfoundry.client;
import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
public class CFRouteTests {
public static final List<String> SPRING_CLOUD_DOMAINS = Arrays.<String>asList("springsource.org", "spring.io",
"myowndomain.spring.io", "tcp.spring.io", "spring.framework");
@Test
public void test_domain_host() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.spring.io", route.getRoute());
}
@Test
public void test_domain_only() throws Exception {
CFRoute route = CFRoute.builder().from("spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("spring.io", route.getRoute());
}
@Test
public void test_longer_domain_match() throws Exception {
CFRoute route = CFRoute.builder().from("myowndomain.spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("myowndomain.spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myowndomain.spring.io", route.getRoute());
}
@Test
public void test_longer_domain_nonexisting() throws Exception {
// For domains that do not exist, the first segment is assumed to be the "host"
CFRoute route = CFRoute.builder().from("app.doesnotexist.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("doesnotexist.io", route.getDomain());
Assert.assertEquals("app",route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("app.doesnotexist.io", route.getRoute());
}
@Test
public void test_longer_domain_nonexisting_path() throws Exception {
CFRoute route = CFRoute.builder().from("app.doesnotexist.io/withpath", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("doesnotexist.io", route.getDomain());
Assert.assertEquals("app",route.getHost());
Assert.assertEquals("/withpath",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("app.doesnotexist.io/withpath", route.getRoute());
}
@Test
public void test_longer_domain_nonexisting_path_port() throws Exception {
CFRoute route = CFRoute.builder().from("app.doesnotexist.io:60100/withpath", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("doesnotexist.io", route.getDomain());
Assert.assertEquals("app",route.getHost());
Assert.assertEquals("/withpath",route.getPath());
Assert.assertEquals(60100, route.getPort());
Assert.assertEquals("app.doesnotexist.io:60100/withpath", route.getRoute());
}
@Test
public void test_longer_domain_match_2() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.myowndomain.spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("myowndomain.spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.myowndomain.spring.io", route.getRoute());
}
@Test
public void test_domain_host_path() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io/appPath", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertEquals("/appPath", route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.spring.io/appPath", route.getRoute());
}
@Test
public void test_domain_host_path_2() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io/appPath/additionalSegment", SPRING_CLOUD_DOMAINS)
.build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertEquals("/appPath/additionalSegment", route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.spring.io/appPath/additionalSegment", route.getRoute());
}
@Test
public void test_tcp_port() throws Exception {
CFRoute route = CFRoute.builder().from("tcp.spring.io:9000", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("tcp.spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(9000, route.getPort());
Assert.assertEquals("tcp.spring.io:9000", route.getRoute());
}
@Test
public void test_host_path() throws Exception {
CFRoute route = CFRoute.builder().from("justhost/path", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("justhost",route.getHost());
Assert.assertEquals("/path",route.getPath());
Assert.assertEquals("justhost/path",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
}
@Test
public void test_routes() throws Exception {
// A CFRoute does not validate route values. It can create any CF route even with wrong domains
// ports, hosts.. This tests that the route builder is parsing an invalid route into different
// components that some other external mechanism (like the CF Java client) can the use to validate
CFRoute route = CFRoute.builder().from("", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.EMPTY_ROUTE,route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from(null, SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.EMPTY_ROUTE,route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from(".", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(".",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("justhost", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("justhost",route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals("justhost",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("justhost.", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("justhost",route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals("justhost.",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from(".justdomain", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("justdomain",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(".justdomain",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("..justdomain", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals(".justdomain",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals("..justdomain",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("/justpath/morepath", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/justpath/morepath",route.getPath());
Assert.assertEquals("/justpath/morepath",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("/", SPRING_CLOUD_DOMAINS).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/",route.getPath());
Assert.assertEquals("/",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
}
@Test
public void test_incorrect_ports() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io:notAn1nt3g3r", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals("myapp.spring.io:notAn1nt3g3r",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
// Test parsing around the first encountered ':'
route = CFRoute.builder().from("http://myapp.spring.io", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("http://myapp.spring.io",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("tcp.spring.io:8000:9000", SPRING_CLOUD_DOMAINS).build();
// Only one ':' is allowed. it should not be able to parse a port if more than ':' is encountered
Assert.assertEquals("tcp.spring.io:8000:9000",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("myapp.spring.io:8000/", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/",route.getPath());
Assert.assertEquals("myapp.spring.io:8000/",route.getRoute());
Assert.assertEquals(8000, route.getPort());
}
@Test
public void test_incorrect_paths() throws Exception {
CFRoute route = CFRoute.builder().from("myapp.spring.io//path", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("//path",route.getPath());
Assert.assertEquals("myapp.spring.io//path",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
route = CFRoute.builder().from("myapp.spring.io/", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/",route.getPath());
Assert.assertEquals("myapp.spring.io/",route.getRoute());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
}
@Test
public void parse_null_domain() throws Exception {
String domain = CFRouteBuilder.findDomain("", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain(null, SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain(".", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain(".cfapps", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("cfapps.", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("...", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("..cfapps..", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain(".cfapps..", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("..cfapps.", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
}
@Test
public void parse_valid_domain() throws Exception {
// These exist
String domain = CFRouteBuilder.findDomain("spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("spring.io", domain);
domain = CFRouteBuilder.findDomain(".spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("spring.io", domain);
domain = CFRouteBuilder.findDomain("..spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("spring.io", domain);
domain = CFRouteBuilder.findDomain("myapp.spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("spring.io", domain);
domain = CFRouteBuilder.findDomain("myowndomain.spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("myowndomain.spring.io", domain);
domain = CFRouteBuilder.findDomain("myapp.myowndomain.spring.io", SPRING_CLOUD_DOMAINS);
Assert.assertEquals("myowndomain.spring.io", domain);
}
@Test
public void parse_invalid_domain() throws Exception {
// These variations of existing domains don't exist
String domain = CFRouteBuilder.findDomain("spring.io.", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("spring.cfapps.io", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("spring.io.cfapps", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("unknown", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
domain = CFRouteBuilder.findDomain("unknown.domain.io", SPRING_CLOUD_DOMAINS);
Assert.assertNull(domain);
}
@Test
public void bug_142279275_parse_hostAndPathSameName() throws Exception {
// Fixes Pivotal Tracker item 142279275
CFRoute route = CFRoute.builder().from("hello-user.myowndomain.spring.io/hello", SPRING_CLOUD_DOMAINS).build();
Assert.assertEquals("hello-user", route.getHost());
Assert.assertEquals("myowndomain.spring.io", route.getDomain());
Assert.assertEquals("/hello", route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("hello-user.myowndomain.spring.io/hello", route.getRoute());
}
@Test
public void build_route_value_empty() throws Exception {
String val = CFRouteBuilder.buildRouteVal(null, null, null, CFRoute.NO_PORT);
Assert.assertEquals(CFRoute.EMPTY_ROUTE, val);
val = CFRouteBuilder.buildRouteVal("", "", "", CFRoute.NO_PORT);
Assert.assertEquals(CFRoute.EMPTY_ROUTE, val);
}
@Test
public void build_route_value() throws Exception {
String val = CFRouteBuilder.buildRouteVal("appHost", null, null, CFRoute.NO_PORT);
Assert.assertEquals("appHost", val);
val = CFRouteBuilder.buildRouteVal(null, "cfapps.io", "", CFRoute.NO_PORT);
Assert.assertEquals("cfapps.io", val);
val = CFRouteBuilder.buildRouteVal("appHost", "cfapps.io", "", CFRoute.NO_PORT);
Assert.assertEquals("appHost.cfapps.io", val);
val = CFRouteBuilder.buildRouteVal(null, null, "/path/to/app", CFRoute.NO_PORT);
Assert.assertEquals("/path/to/app", val);
val = CFRouteBuilder.buildRouteVal(null, null, "/path/to/app", 8000);
Assert.assertEquals(":8000/path/to/app", val);
val = CFRouteBuilder.buildRouteVal(null, null, null, 60101);
Assert.assertEquals(":60101", val);
val = CFRouteBuilder.buildRouteVal("appHost", "cfapps.io", "/path/to/app", CFRoute.NO_PORT);
Assert.assertEquals("appHost.cfapps.io/path/to/app", val);
val = CFRouteBuilder.buildRouteVal("appHost", "cfapps.io", "/path/to/app", 60101);
Assert.assertEquals("appHost.cfapps.io:60101/path/to/app", val);
}
@Test
public void test_build_route_from_domain() throws Exception {
CFRoute route = CFRoute.builder().domain("spring.io").build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("spring.io", route.getRoute());
}
@Test
public void test_build_route_from_nonexisting_domain() throws Exception {
CFRoute route = CFRoute.builder().domain("not.exist.io").build();
Assert.assertEquals("not.exist.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("not.exist.io", route.getRoute());
}
@Test
public void test_build_route_from_null_domain() throws Exception {
CFRoute route = CFRoute.builder().domain(null).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_build_route_from_empty_domain() throws Exception {
CFRoute route = CFRoute.builder().domain("").build();
Assert.assertEquals("",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE,route.getRoute());
}
@Test
public void test_build_route_from_host() throws Exception {
CFRoute route = CFRoute.builder().host("myapp").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getPath());
Assert.assertEquals("myapp", route.getHost());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp", route.getRoute());
}
@Test
public void test_build_route_from_null_host() throws Exception {
CFRoute route = CFRoute.builder().host(null).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getPath());
Assert.assertNull(route.getHost());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_build_route_from_empty_host() throws Exception {
CFRoute route = CFRoute.builder().host("").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getPath());
Assert.assertEquals("",route.getHost());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_build_route_from_domain_host() throws Exception {
CFRoute route = CFRoute.builder().domain("spring.io").host("myapp").build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp.spring.io", route.getRoute());
}
@Test
public void test_build_route_from_path() throws Exception {
CFRoute route = CFRoute.builder().path("/path").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/path",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("/path", route.getRoute());
}
@Test
public void test_build_route_from_path_2() throws Exception {
CFRoute route = CFRoute.builder().path("/path/additional").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/path/additional",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("/path/additional", route.getRoute());
}
@Test
public void test_build_route_from_path_3() throws Exception {
CFRoute route = CFRoute.builder().path("/path/").build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/path/",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("/path/", route.getRoute());
}
@Test
public void test_build_route_from_domain_path() throws Exception {
CFRoute route = CFRoute.builder().path("/mypath").domain("spring.io").build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/mypath",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("spring.io/mypath", route.getRoute());
}
@Test
public void test_build_route_from_host_path() throws Exception {
CFRoute route = CFRoute.builder().path("/mypath").host("myapp").build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/mypath",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp/mypath", route.getRoute());
}
@Test
public void test_build_route_from_host_path_samename() throws Exception {
CFRoute route = CFRoute.builder().path("/myapp").host("myapp").build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/myapp",route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals("myapp/myapp", route.getRoute());
}
@Test
public void test_build_route_from_host_path_port() throws Exception {
CFRoute route = CFRoute.builder().path("/mypath").host("myapp").port(8000).build();
Assert.assertNull(route.getDomain());
Assert.assertEquals("myapp",route.getHost());
Assert.assertEquals("/mypath",route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals("myapp:8000/mypath", route.getRoute());
}
@Test
public void test_build_route_from_domain_path_port() throws Exception {
CFRoute route = CFRoute.builder().path("/mypath").domain("spring.io").port(8000).build();
Assert.assertEquals("spring.io", route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertEquals("/mypath",route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals("spring.io:8000/mypath", route.getRoute());
}
@Test
public void test_build_route_from_port() throws Exception {
CFRoute route = CFRoute.builder().port(8000).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals(":8000", route.getRoute());
}
@Test
public void test_build_route_from_no_port() throws Exception {
CFRoute route = CFRoute.builder().port(CFRoute.NO_PORT).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_build_route_from_no_port_2() throws Exception {
CFRoute route = CFRoute.builder().port(-1).build();
Assert.assertNull(route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(CFRoute.NO_PORT, route.getPort());
Assert.assertEquals(CFRoute.EMPTY_ROUTE, route.getRoute());
}
@Test
public void test_tcp_port_building() throws Exception {
CFRoute route = CFRoute.builder().domain("tcp.spring.io").port(8000).build();
Assert.assertEquals("tcp.spring.io",route.getDomain());
Assert.assertNull(route.getHost());
Assert.assertNull(route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals("tcp.spring.io:8000", route.getRoute());
}
@Test
public void test_complete() throws Exception {
CFRoute route = CFRoute.builder().domain("spring.io").host("myapp").path("/mypath/additional").port(8000).build();
Assert.assertEquals("spring.io",route.getDomain());
Assert.assertEquals("myapp", route.getHost());
Assert.assertEquals("/mypath/additional", route.getPath());
Assert.assertEquals(8000, route.getPort());
Assert.assertEquals("myapp.spring.io:8000/mypath/additional", route.getRoute());
}
}

View File

@@ -23,5 +23,7 @@ public class ManifestYamlSchemaProblemsTypes {
public static final ProblemType UNKNOWN_SERVICES_PROBLEM = problemType("UnknownServicesProblem",
ProblemSeverity.WARNING);
public static final ProblemType UNKNOWN_DOMAIN_PROBLEM = problemType("UnknownDomainProblem",
ProblemSeverity.WARNING);
}

View File

@@ -99,7 +99,9 @@ public class ManifestYmlSchema implements YamlSchema {
// - route: someroute.io
YBeanType route = f.ybean("Route");
route.addProperty(f.yprop("route", t_string).isRequired(true));
YAtomicType t_route_string = f.yatomic("route");
route.addProperty(f.yprop("route", t_route_string).isRequired(true));
t_route_string.parseWith(new RouteValueParser(YTypeFactory.valuesFromHintProvider(domainsProvider)));
YAtomicType t_memory = f.yatomic("Memory");
t_memory.addHints("256M", "512M", "1024M");

View File

@@ -0,0 +1,52 @@
package org.springframework.ide.vscode.manifest.yaml;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import org.springframework.ide.vscode.commons.cloudfoundry.client.CFRoute;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileException;
import org.springframework.ide.vscode.commons.util.RegexpParser;
import org.springframework.ide.vscode.commons.util.ValueParseException;
public class RouteValueParser extends RegexpParser {
private static final String ROUTE_REGEX = "^([\\da-z\\.-]+)(:\\d{1,4})?((\\/[\\dA-Za-z\\.-]+)*\\/?)?$";
private static final String ROUTE_TYPE_NAME = "Route";
private static final String ROUTE_DESCRIPTION = "HTTP or TCP application root route";
private Callable<Collection<String>> domains;
public RouteValueParser(Callable<Collection<String>> domains) {
super(ROUTE_REGEX, ROUTE_TYPE_NAME, ROUTE_DESCRIPTION);
this.domains = domains;
}
@Override
public Object parse(String str) throws Exception {
Matcher matcher = (Matcher) super.parse(str);
if (matcher != null) {
Collection<String> cloudDomains = domains == null ? Collections.emptyList() : domains.call();
// Ensure cloud domains is empty list instead of null
if (cloudDomains == null) {
cloudDomains = Collections.emptyList();
}
CFRoute route = CFRoute.builder().from(str, cloudDomains).build();
if (route.getDomain() == null || route.getDomain().isEmpty()) {
throw new ValueParseException("Domain is missing.");
}
if ((route.getPath() != null && !route.getPath().isEmpty()) && (route.getPort() != CFRoute.NO_PORT)) {
throw new ValueParseException(
"Unable to determine type of route. HTTP port may have a path but no port. TCP route may have port but no path.");
}
if (!cloudDomains.contains(route.getDomain())) {
String hostDomain = matcher.group(1);
throw new ReconcileException("Unknown domain", ManifestYamlSchemaProblemsTypes.UNKNOWN_DOMAIN_PROBLEM, hostDomain.lastIndexOf(route.getDomain()), hostDomain.length());
}
return route;
}
return null;
}
}

View File

@@ -1013,4 +1013,91 @@ public class ManifestYamlEditorTest {
editor.assertContainsCompletions(textAfter);
}
@Test
public void reconcileRouteFormat() throws Exception {
Editor editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" routes:\n" +
" - route: http://springsource.org\n");
editor.assertProblems("http://springsource.org|is not a valid 'Route'");
Diagnostic problem = editor.assertProblem("http://springsource.org");
assertEquals(DiagnosticSeverity.Error, problem.getSeverity());
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" routes:\n" +
" - route: spring source.org\n");
editor.assertProblems("spring source.org|is not a valid 'Route'");
problem = editor.assertProblem("spring source.org");
assertEquals(DiagnosticSeverity.Error, problem.getSeverity());
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" routes:\n" +
" - route: springsource.org:kuku\n");
editor.assertProblems("springsource.org:kuku|is not a valid 'Route'");
problem = editor.assertProblem("springsource.org:kuku");
assertEquals(DiagnosticSeverity.Error, problem.getSeverity());
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" routes:\n" +
" - route: springsource.org/kuku?p=23\n");
editor.assertProblems("springsource.org/kuku?p=23|is not a valid 'Route'");
problem = editor.assertProblem("springsource.org/kuku?p=23");
assertEquals(DiagnosticSeverity.Error, problem.getSeverity());
}
@Test
public void reconcileRoute_Advanced() throws Exception {
Editor editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" routes:\n" +
" - route: springsource.org:8765/path\n");
editor.assertProblems("springsource.org:8765/path|Unable to determine type of route");
Diagnostic problem = editor.assertProblem("springsource.org:8765/path");
assertEquals(DiagnosticSeverity.Error, problem.getSeverity());
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" routes:\n" +
" - route: host.springsource.org\n");
editor.assertProblems("springsource.org|Unknown domain");
problem = editor.assertProblem("springsource.org");
assertEquals(DiagnosticSeverity.Warning, problem.getSeverity());
}
@Test
public void reconcileRouteValidDomain() throws Exception {
ClientRequests cfClient = cloudfoundry.client;
CFDomain domain = Mockito.mock(CFDomain.class);
when(domain.getName()).thenReturn("springsource.org");
when(cfClient.getDomains()).thenReturn(ImmutableList.of(domain));
Editor editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" routes:\n" +
" - route: host.springsource.org\n");
editor.assertProblems();
}
}