diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java index ab33a908bd..fef5777e43 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java @@ -24,7 +24,6 @@ import java.util.stream.Collectors; import javax.net.ssl.SSLException; import org.junit.After; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -41,6 +40,7 @@ import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.WebOperation; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; @@ -48,9 +48,9 @@ import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurity import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.web.reactive.function.client.WebClientCustomizer; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -74,229 +74,233 @@ import static org.mockito.Mockito.mock; */ public class ReactiveCloudFoundryActuatorAutoConfigurationTests { - private AnnotationConfigReactiveWebApplicationContext context; - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before - public void setup() { - this.context = new AnnotationConfigReactiveWebApplicationContext(); - } + private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class, + ReactiveUserDetailsServiceAutoConfiguration.class, + WebFluxAutoConfiguration.class, JacksonAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + WebClientCustomizerConfig.class, WebClientAutoConfiguration.class, + ManagementContextAutoConfiguration.class, EndpointAutoConfiguration.class, + WebEndpointAutoConfiguration.class, HealthEndpointAutoConfiguration.class, + ReactiveCloudFoundryActuatorAutoConfiguration.class)); @After public void close() { HttpResources.reset(); - if (this.context != null) { - this.context.close(); - } } @Test public void cloudFoundryPlatformActive() { - setupContextWithCloudEnabled(); - this.context.refresh(); - CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(); - EndpointMapping endpointMapping = (EndpointMapping) ReflectionTestUtils - .getField(handlerMapping, "endpointMapping"); - assertThat(endpointMapping.getPath()).isEqualTo("/cloudfoundryapplication"); - CorsConfiguration corsConfiguration = (CorsConfiguration) ReflectionTestUtils - .getField(handlerMapping, "corsConfiguration"); - assertThat(corsConfiguration.getAllowedOrigins()).contains("*"); - assertThat(corsConfiguration.getAllowedMethods()).containsAll( - Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name())); - assertThat(corsConfiguration.getAllowedHeaders()).containsAll( - Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type")); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context); + EndpointMapping endpointMapping = (EndpointMapping) ReflectionTestUtils + .getField(handlerMapping, "endpointMapping"); + assertThat(endpointMapping.getPath()).isEqualTo("/cloudfoundryapplication"); + CorsConfiguration corsConfiguration = (CorsConfiguration) ReflectionTestUtils + .getField(handlerMapping, "corsConfiguration"); + assertThat(corsConfiguration.getAllowedOrigins()).contains("*"); + assertThat(corsConfiguration.getAllowedMethods()).containsAll( + Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name())); + assertThat(corsConfiguration.getAllowedHeaders()).containsAll( + Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type")); + }); } @Test public void cloudfoundryapplicationProducesActuatorMediaType() { - setupContextWithCloudEnabled(); - this.context.refresh(); - WebTestClient webTestClient = WebTestClient.bindToApplicationContext(this.context) - .build(); - webTestClient.get().uri("/cloudfoundryapplication").header("Content-Type", - ActuatorMediaType.V2_JSON + ";charset=UTF-8"); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + WebTestClient webTestClient = WebTestClient.bindToApplicationContext(context) + .build(); + webTestClient.get().uri("/cloudfoundryapplication").header("Content-Type", + ActuatorMediaType.V2_JSON + ";charset=UTF-8"); + }); } @Test public void cloudFoundryPlatformActiveSetsApplicationId() { - setupContextWithCloudEnabled(); - this.context.refresh(); - CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(); - Object interceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - String applicationId = (String) ReflectionTestUtils.getField(interceptor, - "applicationId"); - assertThat(applicationId).isEqualTo("my-app-id"); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context); + Object interceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + String applicationId = (String) ReflectionTestUtils.getField(interceptor, + "applicationId"); + assertThat(applicationId).isEqualTo("my-app-id"); + }); } @Test public void cloudFoundryPlatformActiveSetsCloudControllerUrl() { - setupContextWithCloudEnabled(); - this.context.refresh(); - CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(); - Object interceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, - "cloudFoundrySecurityService"); - String cloudControllerUrl = (String) ReflectionTestUtils - .getField(interceptorSecurityService, "cloudControllerUrl"); - assertThat(cloudControllerUrl).isEqualTo("http://my-cloud-controller.com"); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context); + Object interceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, + "cloudFoundrySecurityService"); + String cloudControllerUrl = (String) ReflectionTestUtils + .getField(interceptorSecurityService, "cloudControllerUrl"); + assertThat(cloudControllerUrl).isEqualTo("http://my-cloud-controller.com"); + }); } @Test public void cloudFoundryPlatformActiveAndCloudControllerUrlNotPresent() { - TestPropertyValues - .of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id") - .applyTo(this.context); - setupContext(); - this.context.refresh(); - CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = this.context.getBean( - "cloudFoundryWebFluxEndpointHandlerMapping", - CloudFoundryWebFluxEndpointHandlerMapping.class); - Object securityInterceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - Object interceptorSecurityService = ReflectionTestUtils - .getField(securityInterceptor, "cloudFoundrySecurityService"); - assertThat(interceptorSecurityService).isNull(); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id") + .run(context -> { + CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = context.getBean( + "cloudFoundryWebFluxEndpointHandlerMapping", + CloudFoundryWebFluxEndpointHandlerMapping.class); + Object securityInterceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + Object interceptorSecurityService = ReflectionTestUtils + .getField(securityInterceptor, "cloudFoundrySecurityService"); + assertThat(interceptorSecurityService).isNull(); + }); } @Test @SuppressWarnings("unchecked") public void cloudFoundryPathsIgnoredBySpringSecurity() { - setupContextWithCloudEnabled(); - this.context.refresh(); - WebFilterChainProxy chainProxy = this.context.getBean(WebFilterChainProxy.class); - List filters = (List) ReflectionTestUtils - .getField(chainProxy, "filters"); - Boolean cfRequestMatches = filters.get(0).matches(MockServerWebExchange.from( - MockServerHttpRequest.get("/cloudfoundryapplication/my-path").build())) - .block(); - Boolean otherRequestMatches = filters.get(0) - .matches(MockServerWebExchange - .from(MockServerHttpRequest.get("/some-other-path").build())) - .block(); - assertThat(cfRequestMatches).isTrue(); - assertThat(otherRequestMatches).isFalse(); - otherRequestMatches = filters.get(1) - .matches(MockServerWebExchange - .from(MockServerHttpRequest.get("/some-other-path").build())) - .block(); - assertThat(otherRequestMatches).isTrue(); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + WebFilterChainProxy chainProxy = context.getBean(WebFilterChainProxy.class); + List filters = (List) ReflectionTestUtils + .getField(chainProxy, "filters"); + Boolean cfRequestMatches = filters.get(0).matches(MockServerWebExchange.from( + MockServerHttpRequest.get("/cloudfoundryapplication/my-path").build())) + .block(); + Boolean otherRequestMatches = filters.get(0) + .matches(MockServerWebExchange + .from(MockServerHttpRequest.get("/some-other-path").build())) + .block(); + assertThat(cfRequestMatches).isTrue(); + assertThat(otherRequestMatches).isFalse(); + otherRequestMatches = filters.get(1) + .matches(MockServerWebExchange + .from(MockServerHttpRequest.get("/some-other-path").build())) + .block(); + assertThat(otherRequestMatches).isTrue(); + }); + } @Test public void cloudFoundryPlatformInactive() { - setupContext(); - this.context.refresh(); - assertThat(this.context.containsBean("cloudFoundryWebFluxEndpointHandlerMapping")) - .isFalse(); + this.contextRunner + .run(context -> assertThat( + context.containsBean("cloudFoundryWebFluxEndpointHandlerMapping")) + .isFalse()); } @Test public void cloudFoundryManagementEndpointsDisabled() { - setupContextWithCloudEnabled(); - TestPropertyValues - .of("VCAP_APPLICATION=---", "management.cloudfoundry.enabled:false") - .applyTo(this.context); - this.context.refresh(); - assertThat(this.context.containsBean("cloudFoundryWebFluxEndpointHandlerMapping")) - .isFalse(); + this.contextRunner.withPropertyValues("VCAP_APPLICATION=---", "management.cloudfoundry.enabled:false") + .run(context -> assertThat(context.containsBean("cloudFoundryWebFluxEndpointHandlerMapping")) + .isFalse()); } @Test public void allEndpointsAvailableUnderCloudFoundryWithoutEnablingWebIncludes() { - setupContextWithCloudEnabled(); - this.context.register(TestConfiguration.class); - this.context.refresh(); - CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(); - Collection endpoints = handlerMapping.getEndpoints(); - List endpointIds = endpoints.stream().map(ExposableEndpoint::getId) - .collect(Collectors.toList()); - assertThat(endpointIds).contains("test"); + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context); + Collection endpoints = handlerMapping.getEndpoints(); + List endpointIds = endpoints.stream().map(ExposableEndpoint::getId) + .collect(Collectors.toList()); + assertThat(endpointIds).contains("test"); + }); } @Test public void endpointPathCustomizationIsNotApplied() { - setupContextWithCloudEnabled(); - this.context.register(TestConfiguration.class); - this.context.refresh(); - CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(); - Collection endpoints = handlerMapping.getEndpoints(); - ExposableWebEndpoint endpoint = endpoints.stream() - .filter((candidate) -> "test".equals(candidate.getId())).findFirst() - .get(); - assertThat(endpoint.getOperations()).hasSize(1); - WebOperation operation = endpoint.getOperations().iterator().next(); - assertThat(operation.getRequestPredicate().getPath()).isEqualTo("test"); + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context); + Collection endpoints = handlerMapping.getEndpoints(); + ExposableWebEndpoint endpoint = endpoints.stream() + .filter((candidate) -> "test".equals(candidate.getId())).findFirst() + .get(); + assertThat(endpoint.getOperations()).hasSize(1); + WebOperation operation = endpoint.getOperations().iterator().next(); + assertThat(operation.getRequestPredicate().getPath()).isEqualTo("test"); + }); } @Test public void healthEndpointInvokerShouldBeCloudFoundryWebExtension() { - setupContextWithCloudEnabled(); - this.context.refresh(); - Collection endpoints = getHandlerMapping().getEndpoints(); - ExposableWebEndpoint endpoint = endpoints.iterator().next(); - WebOperation webOperation = endpoint.getOperations().iterator().next(); - Object invoker = ReflectionTestUtils.getField(webOperation, "invoker"); - assertThat(ReflectionTestUtils.getField(invoker, "target")) - .isInstanceOf(CloudFoundryReactiveHealthEndpointWebExtension.class); + this.contextRunner.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class)) + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + Collection endpoints = getHandlerMapping(context).getEndpoints(); + ExposableWebEndpoint endpoint = endpoints.iterator().next(); + WebOperation webOperation = endpoint.getOperations().iterator().next(); + Object invoker = ReflectionTestUtils.getField(webOperation, "invoker"); + assertThat(ReflectionTestUtils.getField(invoker, "target")) + .isInstanceOf(CloudFoundryReactiveHealthEndpointWebExtension.class); + }); } @Test public void skipSslValidation() { - setupContextWithCloudEnabled(); - TestPropertyValues.of("management.cloudfoundry.skip-ssl-validation:true") - .applyTo(this.context); - this.context.refresh(); - CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(); - Object interceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, - "cloudFoundrySecurityService"); - WebClient webClient = (WebClient) ReflectionTestUtils - .getField(interceptorSecurityService, "webClient"); - webClient.get().uri("https://self-signed.badssl.com/").exchange().block(); + this.contextRunner.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class)) + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com", + "management.cloudfoundry.skip-ssl-validation:true") + .run(context -> { + CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context); + Object interceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, + "cloudFoundrySecurityService"); + WebClient webClient = (WebClient) ReflectionTestUtils + .getField(interceptorSecurityService, "webClient"); + webClient.get().uri("https://self-signed.badssl.com/").exchange().block(); + }); } @Test public void sslValidationNotSkippedByDefault() { - setupContextWithCloudEnabled(); - this.context.refresh(); - CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(); - Object interceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, - "cloudFoundrySecurityService"); - WebClient webClient = (WebClient) ReflectionTestUtils - .getField(interceptorSecurityService, "webClient"); - this.thrown.expectCause(instanceOf(SSLException.class)); - webClient.get().uri("https://self-signed.badssl.com/").exchange().block(); - } - - private void setupContextWithCloudEnabled() { - TestPropertyValues - .of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + this.contextRunner.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class)) + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", "vcap.application.cf_api:http://my-cloud-controller.com") - .applyTo(this.context); - setupContext(); + .run(context -> { + CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context); + Object interceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, + "cloudFoundrySecurityService"); + WebClient webClient = (WebClient) ReflectionTestUtils + .getField(interceptorSecurityService, "webClient"); + this.thrown.expectCause(instanceOf(SSLException.class)); + webClient.get().uri("https://self-signed.badssl.com/").exchange().block(); + }); } - private void setupContext() { - this.context.register(ReactiveSecurityAutoConfiguration.class, - ReactiveUserDetailsServiceAutoConfiguration.class, - WebFluxAutoConfiguration.class, JacksonAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - WebClientCustomizerConfig.class, WebClientAutoConfiguration.class, - ManagementContextAutoConfiguration.class, EndpointAutoConfiguration.class, - WebEndpointAutoConfiguration.class, HealthEndpointAutoConfiguration.class, - ReactiveCloudFoundryActuatorAutoConfiguration.class); - } - - private CloudFoundryWebFluxEndpointHandlerMapping getHandlerMapping() { - return this.context.getBean("cloudFoundryWebFluxEndpointHandlerMapping", + private CloudFoundryWebFluxEndpointHandlerMapping getHandlerMapping(ApplicationContext context) { + return context.getBean("cloudFoundryWebFluxEndpointHandlerMapping", CloudFoundryWebFluxEndpointHandlerMapping.class); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java index 9ca0743823..c9100d317a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java @@ -19,8 +19,6 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet; import java.util.Arrays; import java.util.Collection; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; @@ -34,6 +32,7 @@ import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.WebOperation; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; @@ -41,13 +40,12 @@ import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfi import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; -import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockServletContext; import org.springframework.security.config.BeanIds; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; @@ -55,7 +53,6 @@ import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.client.RestTemplate; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.cors.CorsConfiguration; import static org.assertj.core.api.Assertions.assertThat; @@ -69,202 +66,201 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. */ public class CloudFoundryActuatorAutoConfigurationTests { - private AnnotationConfigWebApplicationContext context; - - @Before - public void setup() { - this.context = new AnnotationConfigWebApplicationContext(); - this.context.setServletContext(new MockServletContext()); - this.context.register(SecurityAutoConfiguration.class, - WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class, - DispatcherServletAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - RestTemplateAutoConfiguration.class, - ManagementContextAutoConfiguration.class, - ServletManagementContextAutoConfiguration.class, - EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, - HealthEndpointAutoConfiguration.class, - CloudFoundryActuatorAutoConfiguration.class); - } - - @After - public void close() { - if (this.context != null) { - this.context.close(); - } - } + private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class, + WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class, + DispatcherServletAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + RestTemplateAutoConfiguration.class, + ManagementContextAutoConfiguration.class, + ServletManagementContextAutoConfiguration.class, + EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, + CloudFoundryActuatorAutoConfiguration.class)); @Test public void cloudFoundryPlatformActive() { - CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(); - EndpointMapping endpointMapping = (EndpointMapping) ReflectionTestUtils - .getField(handlerMapping, "endpointMapping"); - assertThat(endpointMapping.getPath()).isEqualTo("/cloudfoundryapplication"); - CorsConfiguration corsConfiguration = (CorsConfiguration) ReflectionTestUtils - .getField(handlerMapping, "corsConfiguration"); - assertThat(corsConfiguration.getAllowedOrigins()).contains("*"); - assertThat(corsConfiguration.getAllowedMethods()).containsAll( - Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name())); - assertThat(corsConfiguration.getAllowedHeaders()).containsAll( - Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type")); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context); + EndpointMapping endpointMapping = (EndpointMapping) ReflectionTestUtils + .getField(handlerMapping, "endpointMapping"); + assertThat(endpointMapping.getPath()).isEqualTo("/cloudfoundryapplication"); + CorsConfiguration corsConfiguration = (CorsConfiguration) ReflectionTestUtils + .getField(handlerMapping, "corsConfiguration"); + assertThat(corsConfiguration.getAllowedOrigins()).contains("*"); + assertThat(corsConfiguration.getAllowedMethods()).containsAll( + Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name())); + assertThat(corsConfiguration.getAllowedHeaders()).containsAll( + Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type")); + }); } @Test public void cloudfoundryapplicationProducesActuatorMediaType() throws Exception { - TestPropertyValues - .of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", "vcap.application.cf_api:http://my-cloud-controller.com") - .applyTo(this.context); - this.context.refresh(); - MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); - mockMvc.perform(get("/cloudfoundryapplication")).andExpect(header() - .string("Content-Type", ActuatorMediaType.V2_JSON + ";charset=UTF-8")); + .run(context -> { + MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); + mockMvc.perform(get("/cloudfoundryapplication")).andExpect(header() + .string("Content-Type", ActuatorMediaType.V2_JSON + ";charset=UTF-8")); + }); } @Test public void cloudFoundryPlatformActiveSetsApplicationId() { - CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(); - Object interceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - String applicationId = (String) ReflectionTestUtils.getField(interceptor, - "applicationId"); - assertThat(applicationId).isEqualTo("my-app-id"); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context); + Object interceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + String applicationId = (String) ReflectionTestUtils.getField(interceptor, + "applicationId"); + assertThat(applicationId).isEqualTo("my-app-id"); + }); } @Test public void cloudFoundryPlatformActiveSetsCloudControllerUrl() { - CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(); - Object interceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, - "cloudFoundrySecurityService"); - String cloudControllerUrl = (String) ReflectionTestUtils - .getField(interceptorSecurityService, "cloudControllerUrl"); - assertThat(cloudControllerUrl).isEqualTo("http://my-cloud-controller.com"); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context); + Object interceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, + "cloudFoundrySecurityService"); + String cloudControllerUrl = (String) ReflectionTestUtils + .getField(interceptorSecurityService, "cloudControllerUrl"); + assertThat(cloudControllerUrl).isEqualTo("http://my-cloud-controller.com"); + }); } @Test public void skipSslValidation() { - TestPropertyValues.of("management.cloudfoundry.skipSslValidation:true") - .applyTo(this.context); - ConfigurationPropertySources.attach(this.context.getEnvironment()); - this.context.refresh(); - CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(); - Object interceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, - "cloudFoundrySecurityService"); - RestTemplate restTemplate = (RestTemplate) ReflectionTestUtils - .getField(interceptorSecurityService, "restTemplate"); - assertThat(restTemplate.getRequestFactory()) - .isInstanceOf(SkipSslVerificationHttpRequestFactory.class); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com", "management.cloudfoundry.skip-ssl-validation:true") + .run(context -> { + CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context); + Object interceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor, + "cloudFoundrySecurityService"); + RestTemplate restTemplate = (RestTemplate) ReflectionTestUtils + .getField(interceptorSecurityService, "restTemplate"); + assertThat(restTemplate.getRequestFactory()) + .isInstanceOf(SkipSslVerificationHttpRequestFactory.class); + }); } @Test public void cloudFoundryPlatformActiveAndCloudControllerUrlNotPresent() { - TestPropertyValues - .of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id") - .applyTo(this.context); - this.context.refresh(); - CloudFoundryWebEndpointServletHandlerMapping handlerMapping = this.context - .getBean("cloudFoundryWebEndpointServletHandlerMapping", - CloudFoundryWebEndpointServletHandlerMapping.class); - Object securityInterceptor = ReflectionTestUtils.getField(handlerMapping, - "securityInterceptor"); - Object interceptorSecurityService = ReflectionTestUtils - .getField(securityInterceptor, "cloudFoundrySecurityService"); - assertThat(interceptorSecurityService).isNull(); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id") + .run(context -> { + CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context); + Object securityInterceptor = ReflectionTestUtils.getField(handlerMapping, + "securityInterceptor"); + Object interceptorSecurityService = ReflectionTestUtils + .getField(securityInterceptor, "cloudFoundrySecurityService"); + assertThat(interceptorSecurityService).isNull(); + }); } @Test public void cloudFoundryPathsIgnoredBySpringSecurity() { - TestPropertyValues - .of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id") - .applyTo(this.context); - this.context.refresh(); - FilterChainProxy securityFilterChain = (FilterChainProxy) this.context - .getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN); - SecurityFilterChain chain = securityFilterChain.getFilterChains().get(0); - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setServletPath("/cloudfoundryapplication/my-path"); - assertThat(chain.getFilters()).isEmpty(); - assertThat(chain.matches(request)).isTrue(); - request.setServletPath("/some-other-path"); - assertThat(chain.matches(request)).isFalse(); + this.contextRunner.withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id") + .run(context -> { + FilterChainProxy securityFilterChain = (FilterChainProxy) context + .getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN); + SecurityFilterChain chain = securityFilterChain.getFilterChains().get(0); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServletPath("/cloudfoundryapplication/my-path"); + assertThat(chain.getFilters()).isEmpty(); + assertThat(chain.matches(request)).isTrue(); + request.setServletPath("/some-other-path"); + assertThat(chain.matches(request)).isFalse(); + }); } @Test public void cloudFoundryPlatformInactive() { - this.context.refresh(); - assertThat( - this.context.containsBean("cloudFoundryWebEndpointServletHandlerMapping")) - .isFalse(); + this.contextRunner.withPropertyValues() + .run(context -> assertThat( + context.containsBean("cloudFoundryWebEndpointServletHandlerMapping")) + .isFalse()); } @Test public void cloudFoundryManagementEndpointsDisabled() { - TestPropertyValues - .of("VCAP_APPLICATION=---", "management.cloudfoundry.enabled:false") - .applyTo(this.context); - this.context.refresh(); - assertThat(this.context.containsBean("cloudFoundryEndpointHandlerMapping")) - .isFalse(); + this.contextRunner.withPropertyValues("VCAP_APPLICATION=---", "management.cloudfoundry.enabled:false") + .run(context -> assertThat(context.containsBean("cloudFoundryEndpointHandlerMapping")) + .isFalse()); } @Test public void allEndpointsAvailableUnderCloudFoundryWithoutExposeAllOnWeb() { - this.context.register(TestConfiguration.class); - this.context.refresh(); - CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(); - Collection endpoints = handlerMapping.getEndpoints(); - assertThat(endpoints.stream() - .filter((candidate) -> "test".equals(candidate.getId())).findFirst()) - .isNotEmpty(); + this.contextRunner + .withUserConfiguration(TestConfiguration.class) + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .run(context -> { + CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context); + Collection endpoints = handlerMapping.getEndpoints(); + assertThat(endpoints.stream() + .filter((candidate) -> "test".equals(candidate.getId())).findFirst()) + .isNotEmpty(); + }); } @Test public void endpointPathCustomizationIsNotApplied() { - TestPropertyValues.of("management.endpoints.web.path-mapping.test=custom") - .applyTo(this.context); - this.context.register(TestConfiguration.class); - this.context.refresh(); - CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(); - Collection endpoints = handlerMapping.getEndpoints(); - ExposableWebEndpoint endpoint = endpoints.stream() - .filter((candidate) -> "test".equals(candidate.getId())).findFirst() - .get(); - Collection operations = endpoint.getOperations(); - assertThat(operations).hasSize(1); - assertThat(operations.iterator().next().getRequestPredicate().getPath()) - .isEqualTo("test"); + this.contextRunner + .withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com", + "management.endpoints.web.path-mapping.test=custom") + .withUserConfiguration(TestConfiguration.class) + .run(context -> { + CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context); + Collection endpoints = handlerMapping.getEndpoints(); + ExposableWebEndpoint endpoint = endpoints.stream() + .filter((candidate) -> "test".equals(candidate.getId())).findFirst() + .get(); + Collection operations = endpoint.getOperations(); + assertThat(operations).hasSize(1); + assertThat(operations.iterator().next().getRequestPredicate().getPath()) + .isEqualTo("test"); + }); } @Test public void healthEndpointInvokerShouldBeCloudFoundryWebExtension() { - TestPropertyValues - .of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", - "vcap.application.cf_api:http://my-cloud-controller.com") - .applyTo(this.context); - this.context.refresh(); - Collection endpoints = this.context - .getBean("cloudFoundryWebEndpointServletHandlerMapping", - CloudFoundryWebEndpointServletHandlerMapping.class) - .getEndpoints(); - ExposableWebEndpoint endpoint = endpoints.iterator().next(); - WebOperation webOperation = endpoint.getOperations().iterator().next(); - Object invoker = ReflectionTestUtils.getField(webOperation, "invoker"); - assertThat(ReflectionTestUtils.getField(invoker, "target")) - .isInstanceOf(CloudFoundryHealthEndpointWebExtension.class); + this.contextRunner.withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", + "vcap.application.cf_api:http://my-cloud-controller.com") + .withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class)) + .run(context -> { + Collection endpoints = context + .getBean("cloudFoundryWebEndpointServletHandlerMapping", + CloudFoundryWebEndpointServletHandlerMapping.class) + .getEndpoints(); + ExposableWebEndpoint endpoint = endpoints.iterator().next(); + WebOperation webOperation = endpoint.getOperations().iterator().next(); + Object invoker = ReflectionTestUtils.getField(webOperation, "invoker"); + assertThat(ReflectionTestUtils.getField(invoker, "target")) + .isInstanceOf(CloudFoundryHealthEndpointWebExtension.class); + }); + } - private CloudFoundryWebEndpointServletHandlerMapping getHandlerMapping() { - TestPropertyValues - .of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id", - "vcap.application.cf_api:http://my-cloud-controller.com") - .applyTo(this.context); - this.context.refresh(); - return this.context.getBean("cloudFoundryWebEndpointServletHandlerMapping", + private CloudFoundryWebEndpointServletHandlerMapping getHandlerMapping(ApplicationContext context) { + return context.getBean("cloudFoundryWebEndpointServletHandlerMapping", CloudFoundryWebEndpointServletHandlerMapping.class); }