Use local app for tests by default.

Rather than relying on external httpbin to be up.
This commit is contained in:
Spencer Gibb
2017-03-06 17:31:28 -07:00
parent 0094b5927c
commit 118b263e31
15 changed files with 216 additions and 30 deletions

View File

@@ -74,6 +74,12 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.synchronoss.cloud</groupId>
<artifactId>nio-multipart-parser</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>

View File

@@ -24,8 +24,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -62,7 +62,7 @@ public class AddRequestHeaderRouteFilterIntegrationTests extends BaseWebClientTe
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -24,8 +24,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -71,7 +71,7 @@ public class AddRequestParameterRouteFilterIntegrationTests extends BaseWebClien
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -22,8 +22,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;
@@ -63,7 +63,7 @@ public class RedirectToRouteFilterIntegrationTests extends BaseWebClientTests {
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -24,8 +24,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -63,7 +63,7 @@ public class RemoveRequestHeaderRouteFilterIntegrationTests extends BaseWebClien
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -22,8 +22,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -58,7 +58,7 @@ public class RewritePathRouteFilterIntegrationTests extends BaseWebClientTests {
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -22,8 +22,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;
@@ -79,7 +79,7 @@ public class SecureHeadersRouteFilterIntegrationTests extends BaseWebClientTests
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -22,8 +22,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -58,7 +58,7 @@ public class SetPathRouteFilterIntegrationTests extends BaseWebClientTests {
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -22,8 +22,8 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpHeaders;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -60,7 +60,7 @@ public class SetResponseRouteFilterIntegrationTests extends BaseWebClientTests {
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -22,15 +22,13 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.http.HttpHeaders;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.reactive.function.client.ClientResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import static org.springframework.cloud.gateway.test.TestUtils.assertStatus;
@@ -69,7 +67,7 @@ public class SetStatusRouteFilterIntegrationTests extends BaseWebClientTests {
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -17,22 +17,43 @@
package org.springframework.cloud.gateway.test;
import java.io.IOException;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.api.Route;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.route.RouteFilter;
import org.springframework.cloud.gateway.model.Route;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
import static org.springframework.cloud.gateway.test.TestUtils.parseMultipart;
import reactor.core.publisher.Mono;
/**
* @author Spencer Gibb
@@ -56,12 +77,109 @@ public class BaseWebClientTests {
this.webClient = WebClient.create(baseUri);
}
@RestController
@RequestMapping("/httpbin")
@Configuration
@RibbonClients({
@RibbonClient(name = "testservice", configuration = TestRibbonConfig.class),
@RibbonClient(name = "myservice", configuration = TestRibbonConfig.class)
})
@EnableGateway
protected static class DefaultTestConfig {
private static final Log log = LogFactory.getLog(DefaultTestConfig.class);
@RequestMapping("/")
public String home(ServerWebExchange exchange) {
return "httpbin compatible home";
}
@RequestMapping("/headers")
public Map<String, Object> headers(ServerWebExchange exchange) {
HashMap<String, Object> map = new HashMap<>();
addHeaders(exchange, map);
return map;
}
private void addHeaders(ServerWebExchange exchange, HashMap<String, Object> map) {
HashMap<String, String> headers = new HashMap<>();
exchange.getRequest().getHeaders().forEach((name, values) -> {
headers.put(name, values.get(0));
});
map.put("headers", headers);
}
@RequestMapping("/delay/{sec}")
public Map<String, Object> get(ServerWebExchange exchange, @PathVariable int sec) throws InterruptedException {
int delay = Math.min(sec, 10);
Thread.sleep(delay * 1000);
return get(exchange);
}
@RequestMapping("/get")
public Map<String, Object> get(ServerWebExchange exchange) {
HashMap<String, Object> map = new HashMap<>();
addHeaders(exchange, map);
HashMap<String, String> params = new HashMap<>();
exchange.getRequest().getQueryParams().forEach((name, values) -> {
params.put(name, values.get(0));
});
map.put("args", params);
return map;
}
@RequestMapping(value = "/post", consumes = "multipart/form-data")
public Mono<Map<String, Object>> postFormData(ServerWebExchange exchange,
@RequestBody(required = false) String body) {
HashMap<String, Object> ret = new HashMap<>();
HashMap<String, Object> files = parseMultipart(exchange, body);
ret.put("files", files);
return Mono.just(ret);
}
@RequestMapping("/post")
public Mono<Map<String, Object>> post(ServerWebExchange exchange,
@RequestBody(required = false) String body) throws IOException {
HashMap<String, Object> ret = new HashMap<>();
ret.put("data", body);
HashMap<String, Object> form = new HashMap<>();
ret.put("form", form);
return exchange.getFormData().then(map -> {
for (Map.Entry<String, List<String>> entry: map.entrySet()) {
for (String value : entry.getValue()) {
form.put(entry.getKey(), value);
}
}
return Mono.just(ret);
});
}
@Bean(name="PrefixPathRouteFilter")
public RouteFilter prefixPathRouteFilter() {
return new RouteFilter() {
@Override
public WebFilter apply(String... args) {
validate(1, args);
final String prefix = args[0];
return (exchange, chain) -> {
ServerHttpRequest req = exchange.getRequest();
String newPath = prefix + req.getURI().getPath();
ServerHttpRequest request = req.mutate()
.path(newPath)
.build();
return chain.filter(exchange.mutate().request(request).build());
};
}
};
}
@Bean
@Order(500)
public GlobalFilter modifyResponseFilter() {
@@ -78,4 +196,15 @@ public class BaseWebClientTests {
}
}
protected static class TestRibbonConfig {
@LocalServerPort
protected int port = 0;
@Bean
public ServerList<Server> ribbonServerList() {
return new StaticServerList<>(new Server("localhost", this.port));
}
}
}

View File

@@ -25,7 +25,7 @@ import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -99,8 +99,7 @@ public class FormIntegrationTests extends BaseWebClientTests {
@EnableAutoConfiguration
@SpringBootConfiguration
@EnableGateway
//@Import(DefaultTestConfig.class)
@Import(DefaultTestConfig.class)
public static class TestConfig { }
}

View File

@@ -22,7 +22,8 @@ import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.api.RouteLocator;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.model.RouteLocator;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.config.PropertiesRouteLocator;
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteLocator;
@@ -36,6 +37,7 @@ import org.springframework.context.annotation.Profile;
import reactor.core.publisher.Flux;
@EnableGateway
@SpringBootConfiguration
@EnableAutoConfiguration
public class GatewayTestApplication {

View File

@@ -17,9 +17,27 @@
package org.springframework.cloud.gateway.test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Base64Utils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.server.ServerWebExchange;
import org.synchronoss.cloud.nio.multipart.AbstractNioMultipartListener;
import org.synchronoss.cloud.nio.multipart.Multipart;
import org.synchronoss.cloud.nio.multipart.MultipartContext;
import org.synchronoss.cloud.nio.multipart.NioMultipartParser;
import org.synchronoss.cloud.nio.stream.storage.StreamStorage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@@ -28,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Spencer Gibb
*/
public class TestUtils {
@SuppressWarnings("unchecked")
public static Map<String, Object> getMap(Map response, String key) {
assertThat(response).containsKey(key).isInstanceOf(Map.class);
return (Map<String, Object>) response.get(key);
@@ -37,4 +56,35 @@ public class TestUtils {
HttpStatus statusCode = response.statusCode();
assertThat(statusCode).isEqualTo(status);
}
public static HashMap<String, Object> parseMultipart(ServerWebExchange exchange, @RequestBody(required = false) String body) {
HashMap<String, Object> files = new HashMap<>();
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
MediaType contentType = headers.getContentType();
String charSet = (contentType.getCharset() == null) ? null : contentType.getCharset().toString();
MultipartContext context = new MultipartContext(contentType.toString(),
(int)headers.getContentLength(), charSet);
AbstractNioMultipartListener listener = new AbstractNioMultipartListener() {
@Override
public void onPartFinished(StreamStorage streamStorage, Map<String, List<String>> headersFromPart) {
String contentDisposition = headersFromPart.get("content-disposition").get(0);
String[] tokens = StringUtils.tokenizeToStringArray(contentDisposition, ";");
String[] nameTokens = StringUtils.tokenizeToStringArray(tokens[1], "=");
String name = StringUtils.deleteAny(nameTokens[1], "\"");
String contentType = headersFromPart.get("content-type").get(0);
ByteArrayInputStream in = (ByteArrayInputStream) streamStorage.getInputStream();
try {
String data = Base64Utils.encodeToString(StreamUtils.copyToByteArray(in));
files.put(name, "data:"+contentType+";base64,"+data);
} catch (IOException e) {
ReflectionUtils.rethrowRuntimeException(e);
}
}
};
NioMultipartParser parser = Multipart.multipart(context).forNIO(listener);
parser.write(body.getBytes(), 0, body.getBytes().length);
return files;
}
}

View File

@@ -1,13 +1,15 @@
test:
hostport: httpbin.org:80
# hostport: localhost:5000
uri: http://${test.hostport}
# uri: http://${test.hostport}
uri: lb://testservice
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
- PrefixPath=/httpbin
# TODO: breakup configuration for individual tests (though some are reused)
routes:
@@ -172,10 +174,10 @@ spring:
- name: Path
args: /**
myservice:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
listOfServers: ${test.hostport}
#myservice:
# ribbon:
# NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
# listOfServers: ${test.hostport}
#hystrix.command.failcmd.execution.isolation.thread.timeoutInMilliseconds: 1000