Skip to content

Commit 012fb3d

Browse files
committed
Merge branch '2.4.x'
Closes gh-24679
2 parents cb0069f + 920136d commit 012fb3d

File tree

3 files changed

+212
-2
lines changed

3 files changed

+212
-2
lines changed

spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizer.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
3030
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3131
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
3232
import org.springframework.beans.factory.support.RootBeanDefinition;
33+
import org.springframework.boot.WebApplicationType;
3334
import org.springframework.boot.test.context.SpringBootTest;
3435
import org.springframework.boot.web.codec.CodecCustomizer;
3536
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
@@ -42,7 +43,10 @@
4243
import org.springframework.test.context.MergedContextConfiguration;
4344
import org.springframework.test.context.TestContextAnnotationUtils;
4445
import org.springframework.test.web.reactive.server.WebTestClient;
46+
import org.springframework.util.ClassUtils;
4547
import org.springframework.util.CollectionUtils;
48+
import org.springframework.util.StringUtils;
49+
import org.springframework.web.context.WebApplicationContext;
4650
import org.springframework.web.reactive.function.client.ExchangeStrategies;
4751

4852
/**
@@ -129,6 +133,10 @@ public static class WebTestClientFactory implements FactoryBean<WebTestClient>,
129133

130134
private WebTestClient object;
131135

136+
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
137+
138+
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
139+
132140
@Override
133141
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
134142
this.applicationContext = applicationContext;
@@ -155,13 +163,49 @@ public WebTestClient getObject() throws Exception {
155163
private WebTestClient createWebTestClient() {
156164
boolean sslEnabled = isSslEnabled(this.applicationContext);
157165
String port = this.applicationContext.getEnvironment().getProperty("local.server.port", "8080");
158-
String baseUrl = (sslEnabled ? "https" : "http") + "://localhost:" + port;
166+
String baseUrl = getBaseUrl(sslEnabled, port);
159167
WebTestClient.Builder builder = WebTestClient.bindToServer();
160168
customizeWebTestClientBuilder(builder, this.applicationContext);
161169
customizeWebTestClientCodecs(builder, this.applicationContext);
162170
return builder.baseUrl(baseUrl).build();
163171
}
164172

173+
private String getBaseUrl(boolean sslEnabled, String port) {
174+
String basePath = deduceBasePath();
175+
String pathSegment = (StringUtils.hasText(basePath)) ? basePath : "";
176+
return (sslEnabled ? "https" : "http") + "://localhost:" + port + pathSegment;
177+
}
178+
179+
private String deduceBasePath() {
180+
WebApplicationType webApplicationType = deduceFromApplicationContext(this.applicationContext.getClass());
181+
if (webApplicationType == WebApplicationType.REACTIVE) {
182+
return this.applicationContext.getEnvironment().getProperty("spring.webflux.base-path");
183+
}
184+
else if (webApplicationType == WebApplicationType.SERVLET) {
185+
return ((WebApplicationContext) this.applicationContext).getServletContext().getContextPath();
186+
}
187+
return null;
188+
}
189+
190+
static WebApplicationType deduceFromApplicationContext(Class<?> applicationContextClass) {
191+
if (isAssignable(SERVLET_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
192+
return WebApplicationType.SERVLET;
193+
}
194+
if (isAssignable(REACTIVE_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
195+
return WebApplicationType.REACTIVE;
196+
}
197+
return WebApplicationType.NONE;
198+
}
199+
200+
private static boolean isAssignable(String target, Class<?> type) {
201+
try {
202+
return ClassUtils.resolveClassName(target, null).isAssignableFrom(type);
203+
}
204+
catch (Throwable ex) {
205+
return false;
206+
}
207+
}
208+
165209
private boolean isSslEnabled(ApplicationContext context) {
166210
try {
167211
AbstractReactiveWebServerFactory webServerFactory = context
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2012-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.web.reactive.server;
18+
19+
import java.util.Collections;
20+
import java.util.Map;
21+
22+
import org.junit.jupiter.api.Test;
23+
import reactor.core.publisher.Mono;
24+
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.boot.test.context.SpringBootTest;
27+
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
28+
import org.springframework.context.annotation.Bean;
29+
import org.springframework.context.annotation.Configuration;
30+
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
31+
import org.springframework.http.HttpStatus;
32+
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
33+
import org.springframework.http.server.reactive.HttpHandler;
34+
import org.springframework.http.server.reactive.ServerHttpRequest;
35+
import org.springframework.http.server.reactive.ServerHttpResponse;
36+
import org.springframework.test.context.TestPropertySource;
37+
import org.springframework.test.web.reactive.server.WebTestClient;
38+
39+
/**
40+
* Tests for {@link WebTestClientContextCustomizer} with a custom base path for a reactive
41+
* web application.
42+
*
43+
* @author Madhura Bhave
44+
*/
45+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
46+
properties = "spring.main.web-application-type=reactive")
47+
@TestPropertySource(properties = "spring.webflux.base-path=/test")
48+
class WebTestClientContextCustomizerWithCustomBasePathTests {
49+
50+
@Autowired
51+
private WebTestClient webTestClient;
52+
53+
@Test
54+
void test() {
55+
this.webTestClient.get().uri("/hello").exchange().expectBody(String.class).isEqualTo("hello world");
56+
}
57+
58+
@Configuration(proxyBeanMethods = false)
59+
static class TestConfig {
60+
61+
@Bean
62+
TomcatReactiveWebServerFactory webServerFactory() {
63+
return new TomcatReactiveWebServerFactory(0);
64+
}
65+
66+
@Bean
67+
HttpHandler httpHandler() {
68+
TestHandler httpHandler = new TestHandler();
69+
Map<String, HttpHandler> handlersMap = Collections.singletonMap("/test", httpHandler);
70+
return new ContextPathCompositeHandler(handlersMap);
71+
}
72+
73+
}
74+
75+
static class TestHandler implements HttpHandler {
76+
77+
private static final DefaultDataBufferFactory factory = new DefaultDataBufferFactory();
78+
79+
@Override
80+
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
81+
response.setStatusCode(HttpStatus.OK);
82+
return response.writeWith(Mono.just(factory.wrap("hello world".getBytes())));
83+
}
84+
85+
}
86+
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2012-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.web.reactive.server;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.boot.test.context.SpringBootTest;
23+
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.context.annotation.Import;
27+
import org.springframework.test.context.TestPropertySource;
28+
import org.springframework.test.web.reactive.server.WebTestClient;
29+
import org.springframework.web.bind.annotation.GetMapping;
30+
import org.springframework.web.bind.annotation.RestController;
31+
import org.springframework.web.servlet.DispatcherServlet;
32+
33+
/**
34+
* Tests for {@link WebTestClientContextCustomizer} with a custom context path for a
35+
* servlet web application.
36+
*
37+
* @author Madhura Bhave
38+
*/
39+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
40+
@TestPropertySource(properties = "server.servlet.context-path=/test")
41+
class WebTestClientContextCustomizerWithCustomContextPathTests {
42+
43+
@Autowired
44+
private WebTestClient webTestClient;
45+
46+
@Test
47+
void test() {
48+
this.webTestClient.get().uri("/hello").exchange().expectBody(String.class).isEqualTo("hello world");
49+
}
50+
51+
@Configuration(proxyBeanMethods = false)
52+
@Import(TestController.class)
53+
static class TestConfig {
54+
55+
@Bean
56+
TomcatServletWebServerFactory webServerFactory() {
57+
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);
58+
factory.setContextPath("/test");
59+
return factory;
60+
}
61+
62+
@Bean
63+
DispatcherServlet dispatcherServlet() {
64+
return new DispatcherServlet();
65+
}
66+
67+
}
68+
69+
@RestController
70+
static class TestController {
71+
72+
@GetMapping("/hello")
73+
String hello() {
74+
return "hello world";
75+
}
76+
77+
}
78+
79+
}

0 commit comments

Comments
 (0)