Merge branch '1.5.x'
This commit is contained in:
commit
94209e2883
|
@ -26,17 +26,21 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
@ -204,6 +208,11 @@ public abstract class AbstractEndpointHandlerMapping<E extends MvcEndpoint>
|
|||
return addSecurityInterceptor(chain);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void extendInterceptors(List<Object> interceptors) {
|
||||
interceptors.add(new SkipPathExtensionContentNegotiation());
|
||||
}
|
||||
|
||||
private HandlerExecutionChain addSecurityInterceptor(HandlerExecutionChain chain) {
|
||||
List<HandlerInterceptor> interceptors = new ArrayList<>();
|
||||
if (chain.getInterceptors() != null) {
|
||||
|
@ -279,4 +288,22 @@ public abstract class AbstractEndpointHandlerMapping<E extends MvcEndpoint>
|
|||
return this.corsConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link HandlerInterceptorAdapter} to ensure that
|
||||
* {@link PathExtensionContentNegotiationStrategy} is skipped for actuator endpoints.
|
||||
*/
|
||||
private static final class SkipPathExtensionContentNegotiation
|
||||
extends HandlerInterceptorAdapter {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
request.setAttribute(
|
||||
WebMvcAutoConfiguration.SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE,
|
||||
Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
.getBean(ManagementContextResolver.class).getApplicationContext();
|
||||
List<?> interceptors = (List<?>) ReflectionTestUtils.getField(
|
||||
managementContext.getBean(EndpointHandlerMapping.class), "interceptors");
|
||||
assertThat(interceptors).hasSize(1);
|
||||
assertThat(interceptors).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -201,7 +201,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
.getBean(ManagementContextResolver.class).getApplicationContext();
|
||||
List<?> interceptors = (List<?>) ReflectionTestUtils.getField(
|
||||
managementContext.getBean(EndpointHandlerMapping.class), "interceptors");
|
||||
assertThat(interceptors).hasSize(1);
|
||||
assertThat(interceptors).hasSize(2);
|
||||
ServletWebServerFactory parentFactory = this.applicationContext
|
||||
.getBean(ServletWebServerFactory.class);
|
||||
ServletWebServerFactory managementFactory = managementContext
|
||||
|
@ -535,7 +535,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
.getBean(ManagementContextResolver.class).getApplicationContext();
|
||||
List<?> interceptors = (List<?>) ReflectionTestUtils.getField(
|
||||
managementContext.getBean(EndpointHandlerMapping.class), "interceptors");
|
||||
assertThat(interceptors).hasSize(1);
|
||||
assertThat(interceptors).hasSize(2);
|
||||
ManagementServerProperties managementServerProperties = this.applicationContext
|
||||
.getBean(ManagementServerProperties.class);
|
||||
assertThat(managementServerProperties.getSsl()).isNotNull();
|
||||
|
@ -577,7 +577,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
.getBean(ManagementContextResolver.class).getApplicationContext();
|
||||
List<?> interceptors = (List<?>) ReflectionTestUtils.getField(
|
||||
managementContext.getBean(EndpointHandlerMapping.class), "interceptors");
|
||||
assertThat(interceptors).hasSize(1);
|
||||
assertThat(interceptors).hasSize(2);
|
||||
ManagementServerProperties managementServerProperties = this.applicationContext
|
||||
.getBean(ManagementServerProperties.class);
|
||||
assertThat(managementServerProperties.getSsl()).isNotNull();
|
||||
|
|
|
@ -60,7 +60,8 @@ public abstract class AbstractEndpointHandlerMappingTests {
|
|||
Collections.singletonList(endpoint));
|
||||
mapping.setApplicationContext(this.context);
|
||||
mapping.afterPropertiesSet();
|
||||
assertThat(mapping.getHandler(request("POST", "/a")).getInterceptors()).isNull();
|
||||
assertThat(mapping.getHandler(request("POST", "/a")).getInterceptors())
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -75,8 +76,8 @@ public abstract class AbstractEndpointHandlerMappingTests {
|
|||
mapping.afterPropertiesSet();
|
||||
MockHttpServletRequest request = request("POST", "/a");
|
||||
request.addHeader("Origin", "http://example.com");
|
||||
assertThat(mapping.getHandler(request).getInterceptors().length).isEqualTo(2);
|
||||
assertThat(mapping.getHandler(request).getInterceptors()[1])
|
||||
assertThat(mapping.getHandler(request).getInterceptors().length).isEqualTo(3);
|
||||
assertThat(mapping.getHandler(request).getInterceptors()[2])
|
||||
.isEqualTo(securityInterceptor);
|
||||
}
|
||||
|
||||
|
|
|
@ -177,6 +177,16 @@ public class LoggersMvcEndpointTests {
|
|||
verifyZeroInteractions(this.loggingSystem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logLevelForLoggerWithNameThatCouldBeMistakenForAPathExtension()
|
||||
throws Exception {
|
||||
given(this.loggingSystem.getLoggerConfiguration("com.png"))
|
||||
.willReturn(new LoggerConfiguration("com.png", null, LogLevel.DEBUG));
|
||||
this.mvc.perform(get("/loggers/com.png")).andExpect(status().isOk())
|
||||
.andExpect(content().string(equalTo(
|
||||
"{\"configuredLevel\":null," + "\"effectiveLevel\":\"DEBUG\"}")));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
|
|
|
@ -124,20 +124,30 @@ public class MetricsMvcEndpointTests {
|
|||
.andExpect(content().string(equalTo("{\"foo\":1}")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void specificMetricWithNameThatCouldBeMistakenForAPathExtension()
|
||||
throws Exception {
|
||||
this.mvc.perform(get("/metrics/bar.png")).andExpect(status().isOk())
|
||||
.andExpect(content().string(equalTo("{\"bar.png\":1}")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void specificMetricWhenDisabled() throws Exception {
|
||||
this.context.getBean(MetricsEndpoint.class).setEnabled(false);
|
||||
this.mvc.perform(get("/application/metrics/foo")).andExpect(status().isNotFound());
|
||||
this.mvc.perform(get("/application/metrics/foo"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void specificMetricThatDoesNotExist() throws Exception {
|
||||
this.mvc.perform(get("/application/metrics/bar")).andExpect(status().isNotFound());
|
||||
this.mvc.perform(get("/application/metrics/bar"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void regexAll() throws Exception {
|
||||
String expected = "\"foo\":1,\"group1.a\":1,\"group1.b\":1,\"group2.a\":1,\"group2_a\":1";
|
||||
String expected = "\"foo\":1,\"bar.png\":1,\"group1.a\":1,\"group1.b\":1,"
|
||||
+ "\"group2.a\":1,\"group2_a\":1";
|
||||
this.mvc.perform(get("/application/metrics/.*")).andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString(expected)));
|
||||
}
|
||||
|
@ -145,14 +155,16 @@ public class MetricsMvcEndpointTests {
|
|||
@Test
|
||||
public void regexGroupDot() throws Exception {
|
||||
String expected = "\"group1.a\":1,\"group1.b\":1,\"group2.a\":1";
|
||||
this.mvc.perform(get("/application/metrics/group[0-9]+\\..*")).andExpect(status().isOk())
|
||||
this.mvc.perform(get("/application/metrics/group[0-9]+\\..*"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString(expected)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void regexGroup1() throws Exception {
|
||||
String expected = "\"group1.a\":1,\"group1.b\":1";
|
||||
this.mvc.perform(get("/application/metrics/group1\\..*")).andExpect(status().isOk())
|
||||
this.mvc.perform(get("/application/metrics/group1\\..*"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString(expected)));
|
||||
}
|
||||
|
||||
|
@ -176,6 +188,7 @@ public class MetricsMvcEndpointTests {
|
|||
public Collection<Metric<?>> metrics() {
|
||||
ArrayList<Metric<?>> metrics = new ArrayList<>();
|
||||
metrics.add(new Metric<>("foo", 1));
|
||||
metrics.add(new Metric<>("bar.png", 1));
|
||||
metrics.add(new Metric<>("group1.a", 1));
|
||||
metrics.add(new Metric<>("group1.b", 1));
|
||||
metrics.add(new Metric<>("group2.a", 1));
|
||||
|
|
|
@ -102,7 +102,8 @@ public class StatsdMetricWriterTests {
|
|||
public void incrementMetricWithInvalidCharsInName() throws Exception {
|
||||
this.writer.increment(new Delta<Long>("counter.fo:o", 3L));
|
||||
this.server.waitForMessage();
|
||||
assertThat(this.server.messagesReceived().get(0)).isEqualTo("me.counter.fo-o:3|c");
|
||||
assertThat(this.server.messagesReceived().get(0))
|
||||
.isEqualTo("me.counter.fo-o:3|c");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -21,9 +21,6 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
|
@ -68,7 +65,6 @@ import org.springframework.social.connect.support.OAuth2ConnectionFactory;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.ResourceAccessException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
|
@ -83,9 +79,6 @@ import org.springframework.web.client.RestTemplate;
|
|||
@ConditionalOnMissingBean(AuthorizationServerEndpointsConfiguration.class)
|
||||
public class ResourceServerTokenServicesConfiguration {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(ResourceServerTokenServicesConfiguration.class);
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public UserInfoRestTemplateFactory userInfoRestTemplateFactory(
|
||||
|
@ -278,13 +271,7 @@ public class ResourceServerTokenServicesConfiguration {
|
|||
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
|
||||
String keyValue = this.resource.getJwt().getKeyValue();
|
||||
if (!StringUtils.hasText(keyValue)) {
|
||||
try {
|
||||
keyValue = getKeyFromServer();
|
||||
}
|
||||
catch (ResourceAccessException ex) {
|
||||
logger.warn("Failed to fetch token key (you may need to refresh "
|
||||
+ "when the auth server is back)");
|
||||
}
|
||||
keyValue = getKeyFromServer();
|
||||
}
|
||||
if (StringUtils.hasText(keyValue) && !keyValue.startsWith("-----BEGIN")) {
|
||||
converter.setSigningKey(keyValue);
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
@ -72,8 +73,13 @@ import org.springframework.util.StringUtils;
|
|||
import org.springframework.validation.DefaultMessageCodesResolver;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextListener;
|
||||
import org.springframework.web.filter.HiddenHttpMethodFilter;
|
||||
import org.springframework.web.filter.HttpPutFormContentFilter;
|
||||
|
@ -130,9 +136,16 @@ import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
|||
ValidationAutoConfiguration.class })
|
||||
public class WebMvcAutoConfiguration {
|
||||
|
||||
public static String DEFAULT_PREFIX = "";
|
||||
public static final String DEFAULT_PREFIX = "";
|
||||
|
||||
public static String DEFAULT_SUFFIX = "";
|
||||
public static final String DEFAULT_SUFFIX = "";
|
||||
|
||||
/**
|
||||
* Attribute that can be added to the web request when the
|
||||
* {@link PathExtensionContentNegotiationStrategy} should be be skipped.
|
||||
*/
|
||||
public static final String SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class
|
||||
.getName() + ".SKIP";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
|
||||
|
@ -457,6 +470,22 @@ public class WebMvcAutoConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public ContentNegotiationManager mvcContentNegotiationManager() {
|
||||
ContentNegotiationManager manager = super.mvcContentNegotiationManager();
|
||||
List<ContentNegotiationStrategy> strategies = manager.getStrategies();
|
||||
ListIterator<ContentNegotiationStrategy> iterator = strategies.listIterator();
|
||||
while (iterator.hasNext()) {
|
||||
ContentNegotiationStrategy strategy = iterator.next();
|
||||
if (strategy instanceof PathExtensionContentNegotiationStrategy) {
|
||||
iterator.set(new OptionalPathExtensionContentNegotiationStrategy(
|
||||
strategy));
|
||||
}
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -554,4 +583,32 @@ public class WebMvcAutoConfiguration {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorator to make {@link PathExtensionContentNegotiationStrategy} optional
|
||||
* depending on a request attribute.
|
||||
*/
|
||||
static class OptionalPathExtensionContentNegotiationStrategy
|
||||
implements ContentNegotiationStrategy {
|
||||
|
||||
private final ContentNegotiationStrategy delegate;
|
||||
|
||||
OptionalPathExtensionContentNegotiationStrategy(
|
||||
ContentNegotiationStrategy delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest)
|
||||
throws HttpMediaTypeNotAcceptableException {
|
||||
Object skip = webRequest.getAttribute(
|
||||
SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE,
|
||||
RequestAttributes.SCOPE_REQUEST);
|
||||
if (skip != null && Boolean.parseBoolean(skip.toString())) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return this.delegate.resolveMediaTypes(webRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,9 +46,12 @@ import org.springframework.context.annotation.Import;
|
|||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.mock.http.client.MockClientHttpResponse;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
|
@ -61,9 +64,7 @@ import org.springframework.stereotype.Component;
|
|||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link ResourceServerTokenServicesConfiguration}.
|
||||
|
@ -211,7 +212,7 @@ public class ResourceServerTokenServicesConfigurationTests {
|
|||
EnvironmentTestUtils.addEnvironment(this.environment,
|
||||
"security.oauth2.resource.jwk.key-set-uri=http://my-auth-server/token_keys");
|
||||
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
|
||||
.environment(this.environment).web(false).run();
|
||||
.environment(this.environment).web(WebApplicationType.NONE).run();
|
||||
DefaultTokenServices services = this.context.getBean(DefaultTokenServices.class);
|
||||
assertThat(services).isNotNull();
|
||||
this.thrown.expect(NoSuchBeanDefinitionException.class);
|
||||
|
@ -249,23 +250,12 @@ public class ResourceServerTokenServicesConfigurationTests {
|
|||
|
||||
@Test
|
||||
public void jwtAccessTokenConverterIsConfiguredWhenKeyUriIsProvided() {
|
||||
EnvironmentTestUtils.addEnvironment(this.environment,
|
||||
"security.oauth2.resource.jwt.key-uri=http://localhost:12345/banana");
|
||||
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
|
||||
.environment(this.environment).web(WebApplicationType.NONE).run();
|
||||
assertThat(this.context.getBeansOfType(JwtAccessTokenConverter.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jwtAccessTokenConverterRestTemplateCanBeCustomized() {
|
||||
EnvironmentTestUtils.addEnvironment(this.environment,
|
||||
"security.oauth2.resource.jwt.key-uri=http://localhost:12345/banana");
|
||||
this.context = new SpringApplicationBuilder(ResourceConfiguration.class,
|
||||
JwtAccessTokenConverterRestTemplateCustomizerConfiguration.class)
|
||||
.environment(this.environment).web(WebApplicationType.NONE).run();
|
||||
JwtAccessTokenConverterRestTemplateCustomizer customizer = this.context
|
||||
.getBean(JwtAccessTokenConverterRestTemplateCustomizer.class);
|
||||
verify(customizer).customize(any(RestTemplate.class));
|
||||
assertThat(this.context.getBeansOfType(JwtAccessTokenConverter.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -387,7 +377,29 @@ public class ResourceServerTokenServicesConfigurationTests {
|
|||
|
||||
@Bean
|
||||
public JwtAccessTokenConverterRestTemplateCustomizer restTemplateCustomizer() {
|
||||
return mock(JwtAccessTokenConverterRestTemplateCustomizer.class);
|
||||
return new MockRestCallCustomizer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockRestCallCustomizer
|
||||
implements JwtAccessTokenConverterRestTemplateCustomizer {
|
||||
|
||||
@Override
|
||||
public void customize(RestTemplate template) {
|
||||
template.getInterceptors().add(new ClientHttpRequestInterceptor() {
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
String payload = "{\"value\":\"FOO\"}";
|
||||
MockClientHttpResponse response = new MockClientHttpResponse(
|
||||
payload.getBytes(), HttpStatus.OK);
|
||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
return response;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.springframework.boot.test.context;
|
|||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -31,13 +32,16 @@ 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.annotation.AnnotationUtils;
|
||||
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.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.ContextHierarchy;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.TestContext;
|
||||
|
@ -153,7 +157,7 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
|
|||
propertySourceProperties
|
||||
.toArray(new String[propertySourceProperties.size()]));
|
||||
WebEnvironment webEnvironment = getWebEnvironment(mergedConfig.getTestClass());
|
||||
if (webEnvironment != null) {
|
||||
if (webEnvironment != null && isWebEnvironmentSupported(mergedConfig)) {
|
||||
WebApplicationType webApplicationType = getWebApplicationType(mergedConfig);
|
||||
if (webApplicationType == WebApplicationType.SERVLET
|
||||
&& (webEnvironment.isEmbedded()
|
||||
|
@ -198,6 +202,32 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
|
|||
return WebApplicationType.SERVLET;
|
||||
}
|
||||
|
||||
private boolean isWebEnvironmentSupported(MergedContextConfiguration mergedConfig) {
|
||||
Class<?> testClass = mergedConfig.getTestClass();
|
||||
ContextHierarchy hierarchy = AnnotationUtils.getAnnotation(testClass,
|
||||
ContextHierarchy.class);
|
||||
if (hierarchy == null || hierarchy.value().length == 0) {
|
||||
return true;
|
||||
}
|
||||
ContextConfiguration[] configurations = hierarchy.value();
|
||||
return isFromConfiguration(mergedConfig,
|
||||
configurations[configurations.length - 1]);
|
||||
}
|
||||
|
||||
private boolean isFromConfiguration(MergedContextConfiguration candidateConfig,
|
||||
ContextConfiguration configuration) {
|
||||
ContextConfigurationAttributes attributes = new ContextConfigurationAttributes(
|
||||
candidateConfig.getTestClass(), configuration);
|
||||
Set<Class<?>> configurationClasses = new HashSet<Class<?>>(
|
||||
Arrays.asList(attributes.getClasses()));
|
||||
for (Class<?> candidate : candidateConfig.getClasses()) {
|
||||
if (configurationClasses.contains(candidate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private WebApplicationType getConfiguredWebApplicationType(
|
||||
MergedContextConfiguration configuration) {
|
||||
PropertySources sources = convertToPropertySources(
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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 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.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.SpringBootTestWebEnvironmentContextHierarchyTests.ChildConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTestWebEnvironmentContextHierarchyTests.ParentConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextHierarchy;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringBootTest} configured with {@link WebEnvironment#DEFINED_PORT}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@DirtiesContext
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, properties = {
|
||||
"server.port=0", "value=123" })
|
||||
@ContextHierarchy({ @ContextConfiguration(classes = ParentConfiguration.class),
|
||||
@ContextConfiguration(classes = ChildConfiguration.class) })
|
||||
public class SpringBootTestWebEnvironmentContextHierarchyTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void testShouldOnlyStartSingleServer() throws Exception {
|
||||
ApplicationContext parent = this.context.getParent();
|
||||
assertThat(this.context).isInstanceOf(WebApplicationContext.class);
|
||||
assertThat(parent).isNotInstanceOf(WebApplicationContext.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class ParentConfiguration extends AbstractConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@RestController
|
||||
protected static class ChildConfiguration extends AbstractConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue