From 1ca71510d0b9b2b45d500db42a9883a22219d165 Mon Sep 17 00:00:00 2001 From: Biju Kunjummen Date: Fri, 2 Mar 2018 08:04:39 -0800 Subject: [PATCH] Refactors httpbin controller into its own test class (#219) --- .../gateway/test/BaseWebClientTests.java | 112 +-------------- .../test/HttpBinCompatibleController.java | 130 ++++++++++++++++++ 2 files changed, 135 insertions(+), 107 deletions(-) create mode 100644 spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/test/HttpBinCompatibleController.java diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/test/BaseWebClientTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/test/BaseWebClientTests.java index 59ed30da..7e1b690e 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/test/BaseWebClientTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/test/BaseWebClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2017-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,7 @@ package org.springframework.cloud.gateway.test; -import java.io.IOException; import java.time.Duration; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -40,19 +35,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.Order; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.http.codec.multipart.FilePart; -import org.springframework.http.codec.multipart.Part; import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.util.MultiValueMap; -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.RequestMethod; -import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.server.ServerWebExchange; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; @@ -60,8 +44,6 @@ 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 reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; /** * @author Spencer Gibb @@ -87,8 +69,6 @@ public class BaseWebClientTests { this.testClient = WebTestClient.bindToServer().baseUrl(baseUri).build(); } - @RestController - @RequestMapping("/httpbin") @Configuration @RibbonClients({ @RibbonClient(name = "testservice", configuration = TestRibbonConfig.class), @@ -96,93 +76,11 @@ public class BaseWebClientTests { }) @Import(PermitAllSecurityConfiguration.class) protected static class DefaultTestConfig { - private static final Log log = LogFactory.getLog(DefaultTestConfig.class); - - @RequestMapping("/") - public String home(ServerWebExchange exchange) { - return "httpbin compatible home"; - } - - @RequestMapping(path = "/headers", method = {RequestMethod.GET, RequestMethod.POST}, produces = MediaType.APPLICATION_JSON_VALUE) - public Map headers(ServerWebExchange exchange) { - HashMap map = new HashMap<>(); - addHeaders(exchange, map); - return map; - } - - private void addHeaders(ServerWebExchange exchange, HashMap map) { - HashMap headers = new HashMap<>(); - exchange.getRequest().getHeaders().forEach((name, values) -> { - if (log.isDebugEnabled()) { - log.debug("Header, name: "+name+", "+values); - } - headers.put(name, values.get(0)); - }); - - map.put("headers", headers); - } - - @RequestMapping(path = "/delay/{sec}", produces = MediaType.APPLICATION_JSON_VALUE) - public Map get(ServerWebExchange exchange, @PathVariable int sec) throws InterruptedException { - int delay = Math.min(sec, 10); - Thread.sleep(delay * 1000); - return get(exchange); - } - - @RequestMapping(path = "/get", produces = MediaType.APPLICATION_JSON_VALUE) - public Map get(ServerWebExchange exchange) { - HashMap map = new HashMap<>(); - addHeaders(exchange, map); - HashMap 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 = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public Mono> postFormData(@RequestBody Mono> parts) { - // StringDecoder decoder = StringDecoder.allMimeTypes(true); - return parts.flux().flatMap(map -> Flux.fromIterable(map.values())) - .flatMap(map -> Flux.fromIterable(map)) - .filter(part -> part instanceof FilePart) - .reduce(new HashMap(), (files, part) -> { - MediaType contentType = part.headers().getContentType(); - long contentLength = part.headers().getContentLength(); - files.put(part.name(), "data:"+contentType+";base64,"+contentLength); //TODO: get part data - return files; - }).map(files -> Collections.singletonMap("files", files)); - } - - @RequestMapping(path = "/post", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public Mono> postUrlEncoded(ServerWebExchange exchange) throws IOException { - return post(exchange, null); - } - - @RequestMapping(path = "/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - public Mono> post(ServerWebExchange exchange, - @RequestBody(required = false) String body) throws IOException { - HashMap ret = new HashMap<>(); - ret.put("data", body); - HashMap form = new HashMap<>(); - ret.put("form", form); - - return exchange.getFormData().flatMap(map -> { - for (Map.Entry> entry: map.entrySet()) { - for (String value : entry.getValue()) { - form.put(entry.getKey(), value); - } - } - return Mono.just(ret); - }); - } - - @RequestMapping("/status/{status}") - public ResponseEntity status(@PathVariable int status) { - return ResponseEntity.status(status).body("Failed with "+status); + + @Bean + public HttpBinCompatibleController httpBinController() { + return new HttpBinCompatibleController(); } @Bean diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/test/HttpBinCompatibleController.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/test/HttpBinCompatibleController.java new file mode 100644 index 00000000..80db04d9 --- /dev/null +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/test/HttpBinCompatibleController.java @@ -0,0 +1,130 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.springframework.cloud.gateway.test; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.codec.multipart.FilePart; +import org.springframework.http.codec.multipart.Part; +import org.springframework.util.MultiValueMap; +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.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.time.Duration; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/httpbin") +public class HttpBinCompatibleController { + private static final Log log = LogFactory.getLog(HttpBinCompatibleController.class); + + @RequestMapping("/") + public String home() { + return "httpbin compatible home"; + } + + @RequestMapping(path = "/headers", method = { + RequestMethod.GET, RequestMethod.POST}, produces = MediaType.APPLICATION_JSON_VALUE) + public Mono> headers(ServerWebExchange exchange) { + return getHeaders(exchange); + } + + @RequestMapping(path = "/delay/{sec}", produces = MediaType.APPLICATION_JSON_VALUE) + public Mono> get(ServerWebExchange exchange, @PathVariable int sec) throws InterruptedException { + int delay = Math.min(sec, 10); + return get(exchange).delayElement(Duration.ofSeconds(delay)); + } + + @RequestMapping(path = "/get", produces = MediaType.APPLICATION_JSON_VALUE) + public Mono> get(ServerWebExchange exchange) { + return getHeaders(exchange).map(map -> { + HashMap result = new HashMap<>(map); + HashMap params = new HashMap<>(); + exchange.getRequest().getQueryParams().forEach((name, values) -> { + params.put(name, values.get(0)); + }); + result.put("args", params); + return result; + }); + } + + @RequestMapping(value = "/post", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public Mono> postFormData(@RequestBody Mono> parts) { + // StringDecoder decoder = StringDecoder.allMimeTypes(true); + return parts.flux().flatMap(map -> Flux.fromIterable(map.values())) + .flatMap(map -> Flux.fromIterable(map)) + .filter(part -> part instanceof FilePart) + .reduce(new HashMap(), (files, part) -> { + MediaType contentType = part.headers().getContentType(); + long contentLength = part.headers().getContentLength(); + files.put(part.name(), "data:"+contentType+";base64,"+contentLength); //TODO: get part data + return files; + }).map(files -> Collections.singletonMap("files", files)); + } + + @RequestMapping(path = "/post", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public Mono> postUrlEncoded(ServerWebExchange exchange) throws + IOException { + return post(exchange, null); + } + + @RequestMapping(path = "/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) + public Mono> post(ServerWebExchange exchange, + @RequestBody(required = false) String body) throws IOException { + HashMap ret = new HashMap<>(); + ret.put("data", body); + HashMap form = new HashMap<>(); + ret.put("form", form); + + return exchange.getFormData().flatMap(map -> { + for (Map.Entry> entry: map.entrySet()) { + for (String value : entry.getValue()) { + form.put(entry.getKey(), value); + } + } + return Mono.just(ret); + }); + } + + @RequestMapping("/status/{status}") + public ResponseEntity status(@PathVariable int status) { + return ResponseEntity.status(status).body("Failed with "+status); + } + + private Mono> getHeaders(ServerWebExchange exchange) { + return Flux.fromIterable(exchange.getRequest().getHeaders().entrySet()) + .collectMap(entry -> entry.getKey(), entry -> entry.getValue().get(0)) + .map(map -> { + Map result = new HashMap<>(); + result.put("headers", map); + return result; + }); + } +}