Browse Source

Start a reactive web application if necessary

This commit makes sure that `@SpringBootTest` with a reactive setup
starts a web application if necessary.

If both a servlet and a reactive environment are available, a servlet
environment is bootstraped. This commit also adds a way to force a
reactive environment by specifying the `spring.main.web-application-type`
property of the test (e.g. `@TestPropertySource`).

Closes gh-8383
pull/8410/head
Stephane Nicoll 9 years ago committed by Brian Clozel
parent
commit
54939e8e3c
  1. 5
      spring-boot-test/pom.xml
  2. 33
      spring-boot-test/src/main/java/org/springframework/boot/test/context/ReactiveWebMergedContextConfiguration.java
  3. 3
      spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java
  4. 45
      spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java
  5. 101
      spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests.java
  6. 4
      spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedServletWebEnvironmentTests.java
  7. 48
      spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestReactiveWebEnvironmentDefinedPortTests.java
  8. 48
      spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestReactiveWebEnvironmentRandomPortTests.java
  9. 4
      spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestTestRestTemplateDefinedByUser.java
  10. 4
      spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentDefinedPortTests.java
  11. 4
      spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentRandomPortCustomPortTests.java
  12. 4
      spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentRandomPortTests.java

5
spring-boot-test/pom.xml

@ -148,6 +148,11 @@ @@ -148,6 +148,11 @@
<artifactId>spring-webmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

33
spring-boot-test/src/main/java/org/springframework/boot/test/context/ReactiveWebMergedContextConfiguration.java

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
/*
* Copyright 2012-2017 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.boot.test.context;
import org.springframework.test.context.MergedContextConfiguration;
/**
* Encapsulates the <em>merged</em> context configuration declared on a test class and
* all of its superclasses for a reactive web application.
*
* @author Stephane Nicoll
*/
class ReactiveWebMergedContextConfiguration extends MergedContextConfiguration {
ReactiveWebMergedContextConfiguration(
MergedContextConfiguration mergedConfig) {
super(mergedConfig);
}
}

3
spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java

@ -114,6 +114,9 @@ public class SpringBootContextLoader extends AbstractContextLoader { @@ -114,6 +114,9 @@ public class SpringBootContextLoader extends AbstractContextLoader {
new WebConfigurer().configure(config, application, initializers);
}
}
else if (config instanceof ReactiveWebMergedContextConfiguration) {
application.setWebApplicationType(WebApplicationType.REACTIVE);
}
else {
application.setWebApplicationType(WebApplicationType.NONE);
}

45
spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@ -20,6 +20,7 @@ import java.lang.annotation.Annotation; @@ -20,6 +20,7 @@ import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
@ -27,9 +28,14 @@ import org.apache.commons.logging.LogFactory; @@ -27,9 +28,14 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySources;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextLoader;
@ -38,6 +44,7 @@ import org.springframework.test.context.TestContext; @@ -38,6 +44,7 @@ import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestContextBootstrapper;
import org.springframework.test.context.TestExecutionListener;
import org.springframework.test.context.support.DefaultTestContextBootstrapper;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.context.web.WebMergedContextConfiguration;
import org.springframework.util.Assert;
@ -146,7 +153,8 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr @@ -146,7 +153,8 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
.toArray(new String[propertySourceProperties.size()]));
WebEnvironment webEnvironment = getWebEnvironment(mergedConfig.getTestClass());
if (webEnvironment != null) {
if (deduceWebApplication() == WebApplicationType.SERVLET &&
WebApplicationType webApplicationType = getWebApplicationType(mergedConfig);
if (webApplicationType == WebApplicationType.SERVLET &&
(webEnvironment.isEmbedded() || webEnvironment == WebEnvironment.MOCK)) {
WebAppConfiguration webAppConfiguration = AnnotatedElementUtils
.findMergedAnnotation(mergedConfig.getTestClass(),
@ -156,10 +164,24 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr @@ -156,10 +164,24 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
mergedConfig = new WebMergedContextConfiguration(mergedConfig,
resourceBasePath);
}
else if (webApplicationType == WebApplicationType.REACTIVE
&& webEnvironment.isEmbedded()) {
return new ReactiveWebMergedContextConfiguration(mergedConfig);
}
}
return mergedConfig;
}
private WebApplicationType getWebApplicationType(
MergedContextConfiguration configuration) {
WebApplicationType webApplicationType =
getConfiguredWebApplicationType(configuration);
if (webApplicationType != null) {
return webApplicationType;
}
return deduceWebApplication();
}
private WebApplicationType deduceWebApplication() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
@ -173,6 +195,25 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr @@ -173,6 +195,25 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
return WebApplicationType.SERVLET;
}
private WebApplicationType getConfiguredWebApplicationType(
MergedContextConfiguration configuration) {
PropertySources sources = convertToPropertySources(
configuration.getPropertySourceProperties());
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
new PropertySourcesPropertyResolver(sources), "spring.main.");
String property = resolver.getProperty("web-application-type");
return (property != null ? WebApplicationType.valueOf(property.toUpperCase())
: null);
}
private PropertySources convertToPropertySources(String[] properties) {
Map<String, Object> source = TestPropertySourceUtils
.convertInlinedPropertiesToMap(properties);
MutablePropertySources sources = new MutablePropertySources();
sources.addFirst(new MapPropertySource("inline", source));
return sources;
}
protected Class<?>[] getOrFindConfigurationClasses(
MergedContextConfiguration mergedConfig) {
Class<?>[] classes = mergedConfig.getClasses();

101
spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests.java

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
/*
* Copyright 2012-2017 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.boot.test.context;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.context.embedded.ReactiveWebApplicationContext;
import org.springframework.boot.context.embedded.ReactiveWebServerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Base class for {@link SpringBootTest} tests configured to start an embedded reactive
* container.
*
* @author Stephane Nicoll
*/
public abstract class AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests {
@LocalServerPort
private int port = 0;
@Value("${value}")
private int value = 0;
@Autowired
private ReactiveWebApplicationContext context;
public ReactiveWebApplicationContext getContext() {
return this.context;
}
@Test
public void runAndTestHttpEndpoint() {
assertThat(this.port).isNotEqualTo(8080).isNotEqualTo(0);
String body = new RestTemplate()
.getForObject("http://localhost:" + this.port + "/", String.class);
assertThat(body).isEqualTo("Hello World");
}
@Test
public void annotationAttributesOverridePropertiesFile() throws Exception {
assertThat(this.value).isEqualTo(123);
}
protected static class AbstractConfig {
@Value("${server.port:8080}")
private int port = 8080;
@Bean
public HttpHandler httpHandler(ApplicationContext applicationContext) {
return WebHttpHandlerBuilder.applicationContext(applicationContext).build();
}
@Bean
public ReactiveWebServerFactory embeddedReactiveContainer() {
TomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();
factory.setPort(this.port);
return factory;
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholder() {
return new PropertySourcesPlaceholderConfigurer();
}
@RequestMapping("/")
public Mono<String> home() {
return Mono.just("Hello World");
}
}
}

4
spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedWebEnvironmentTests.java → spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedServletWebEnvironmentTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@ -43,7 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -43,7 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Phillip Webb
* @author Andy Wilkinson
*/
public abstract class AbstractSpringBootTestEmbeddedWebEnvironmentTests {
public abstract class AbstractSpringBootTestEmbeddedServletWebEnvironmentTests {
@LocalServerPort
private int port = 0;

48
spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestReactiveWebEnvironmentDefinedPortTests.java

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
/*
* Copyright 2012-2017 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.boot.test.context;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.config.EnableWebFlux;
/**
* Tests for {@link SpringBootTest} in a reactive environment configured
* with {@link WebEnvironment#DEFINED_PORT}.
*
* @author Stephane Nicoll
*/
@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, properties = {
"spring.main.web-application-type=reactive", "server.port=0", "value=123" })
public class SpringBootTestReactiveWebEnvironmentDefinedPortTests
extends AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests {
@Configuration
@EnableWebFlux
@RestController
protected static class Config extends AbstractConfig {
}
}

48
spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestReactiveWebEnvironmentRandomPortTests.java

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
/*
* Copyright 2012-2017 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.boot.test.context;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.config.EnableWebFlux;
/**
* Tests for {@link SpringBootTest} in a reactive environment configured
* with {@link WebEnvironment#RANDOM_PORT}.
*
* @author Stephane Nicoll
*/
@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
"spring.main.webApplicationType=reactive", "value=123" })
public class SpringBootTestReactiveWebEnvironmentRandomPortTests
extends AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests {
@Configuration
@EnableWebFlux
@RestController
protected static class Config extends AbstractConfig {
}
}

4
spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestTestRestTemplateDefinedByUser.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@DirtiesContext
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "value=123" })
public class SpringBootTestTestRestTemplateDefinedByUser
extends AbstractSpringBootTestEmbeddedWebEnvironmentTests {
extends AbstractSpringBootTestEmbeddedServletWebEnvironmentTests {
@Test
public void restTemplateIsUserDefined() throws Exception {

4
spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentDefinedPortTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@ -36,7 +36,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -36,7 +36,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, properties = {
"server.port=0", "value=123" })
public class SpringBootTestWebEnvironmentDefinedPortTests
extends AbstractSpringBootTestEmbeddedWebEnvironmentTests {
extends AbstractSpringBootTestEmbeddedServletWebEnvironmentTests {
@Configuration
@EnableWebMvc

4
spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentRandomPortCustomPortTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@ -20,7 +20,7 @@ import org.junit.Test; @@ -20,7 +20,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.AbstractSpringBootTestEmbeddedWebEnvironmentTests.AbstractConfig;
import org.springframework.boot.test.context.AbstractSpringBootTestEmbeddedServletWebEnvironmentTests.AbstractConfig;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

4
spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentRandomPortTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@DirtiesContext
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "value=123" })
public class SpringBootTestWebEnvironmentRandomPortTests
extends AbstractSpringBootTestEmbeddedWebEnvironmentTests {
extends AbstractSpringBootTestEmbeddedServletWebEnvironmentTests {
@Test
public void testRestTemplateShouldUseBuilder() throws Exception {

Loading…
Cancel
Save