Move Actuator infrastructure for WebMvc to spring-boot-webmvc
This commit is contained in:
committed by
Phillip Webb
parent
272eca17e5
commit
46a5ea0ee7
@@ -20,18 +20,20 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.Access;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
|
||||
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -45,7 +47,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class WebMvcEndpointManagementContextConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withUserConfiguration(TestConfig.class);
|
||||
.withUserConfiguration(TestConfig.class)
|
||||
.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void contextShouldContainServletEndpointRegistrar() {
|
||||
@@ -63,8 +67,7 @@ class WebMvcEndpointManagementContextConfigurationTests {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(WebMvcEndpointManagementContextConfiguration.class)
|
||||
@EnableConfigurationProperties(WebEndpointProperties.class)
|
||||
@ImportAutoConfiguration(WebMvcEndpointManagementContextConfiguration.class)
|
||||
static class TestConfig {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.webmvc.actuate.autoconfigure.health;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTestEndpointOutcomeExposureContributor;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.webmvc.actuate.endpoint.web.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WebMvcHealthEndpointExtensionAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class WebMvcHealthEndpointExtensionAutoConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,
|
||||
HealthEndpointAutoConfiguration.class, WebMvcHealthEndpointExtensionAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
@WithTestEndpointOutcomeExposureContributor
|
||||
void additionalHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {
|
||||
this.contextRunner
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))
|
||||
.withBean(DispatcherServlet.class)
|
||||
.withPropertyValues("management.endpoints.web.exposure.exclude=*",
|
||||
"management.endpoints.test.exposure.include=*")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasNotFailed();
|
||||
assertThat(context).hasSingleBean(HealthEndpoint.class);
|
||||
assertThat(context).hasSingleBean(HealthEndpointWebExtension.class);
|
||||
assertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();
|
||||
assertThat(context).hasSingleBean(AdditionalHealthEndpointPathsWebMvcHandlerMapping.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class HealthIndicatorsConfiguration {
|
||||
|
||||
@Bean
|
||||
HealthIndicator simpleHealthIndicator() {
|
||||
return () -> Health.up().withDetail("counter", 42).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
HealthIndicator additionalHealthIndicator() {
|
||||
return () -> Health.up().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.webmvc.actuate.autoconfigure.web;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CompositeHandlerExceptionResolver}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class CompositeHandlerExceptionResolverTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
private final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
private final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
@Test
|
||||
void resolverShouldDelegateToOtherResolversInContext() {
|
||||
load(TestConfiguration.class);
|
||||
CompositeHandlerExceptionResolver resolver = (CompositeHandlerExceptionResolver) this.context
|
||||
.getBean(DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME);
|
||||
ModelAndView resolved = resolver.resolveException(this.request, this.response, null,
|
||||
new HttpRequestMethodNotSupportedException("POST"));
|
||||
assertThat(resolved.getViewName()).isEqualTo("test-view");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolverShouldAddDefaultResolverIfNonePresent() {
|
||||
load(BaseConfiguration.class);
|
||||
CompositeHandlerExceptionResolver resolver = (CompositeHandlerExceptionResolver) this.context
|
||||
.getBean(DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME);
|
||||
HttpRequestMethodNotSupportedException exception = new HttpRequestMethodNotSupportedException("POST");
|
||||
ModelAndView resolved = resolver.resolveException(this.request, this.response, null, exception);
|
||||
assertThat(resolved).isNotNull();
|
||||
assertThat(resolved.isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
private void load(Class<?>... configs) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(configs);
|
||||
context.refresh();
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class BaseConfiguration {
|
||||
|
||||
@Bean(name = DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME)
|
||||
CompositeHandlerExceptionResolver compositeHandlerExceptionResolver() {
|
||||
return new CompositeHandlerExceptionResolver();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
HandlerExceptionResolver testResolver() {
|
||||
return new TestHandlerExceptionResolver();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestHandlerExceptionResolver implements HandlerExceptionResolver {
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) {
|
||||
return new ModelAndView("test-view");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.webmvc.actuate.autoconfigure.web;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ErrorProperties;
|
||||
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||
import org.springframework.boot.webmvc.error.DefaultErrorAttributes;
|
||||
import org.springframework.boot.webmvc.error.ErrorAttributes;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Tests for {@link ManagementErrorEndpoint}.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class ManagementErrorEndpointTests {
|
||||
|
||||
private final ErrorAttributes errorAttributes = new DefaultErrorAttributes();
|
||||
|
||||
private final ErrorProperties errorProperties = new ErrorProperties();
|
||||
|
||||
private final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.request.setAttribute("jakarta.servlet.error.exception", new RuntimeException("test exception"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseNeverDetails() {
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));
|
||||
assertThat(response).doesNotContainKey("message");
|
||||
assertThat(response).doesNotContainKey("trace");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseAlwaysDetails() {
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeAttribute.ALWAYS);
|
||||
this.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ALWAYS);
|
||||
this.request.addParameter("trace", "false");
|
||||
this.request.addParameter("message", "false");
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(this.request));
|
||||
assertThat(response).containsEntry("message", "test exception");
|
||||
assertThat(response).hasEntrySatisfying("trace",
|
||||
(value) -> assertThat(value).asString().startsWith("java.lang.RuntimeException: test exception"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseParamsAbsent() {
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
this.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(this.request));
|
||||
assertThat(response).doesNotContainKey("message");
|
||||
assertThat(response).doesNotContainKey("trace");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseParamsTrue() {
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
this.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
this.request.addParameter("trace", "true");
|
||||
this.request.addParameter("message", "true");
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(this.request));
|
||||
assertThat(response).containsEntry("message", "test exception");
|
||||
assertThat(response).hasEntrySatisfying("trace",
|
||||
(value) -> assertThat(value).asString().startsWith("java.lang.RuntimeException: test exception"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseParamsFalse() {
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
this.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
this.request.addParameter("trace", "false");
|
||||
this.request.addParameter("message", "false");
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(this.request));
|
||||
assertThat(response).doesNotContainKey("message");
|
||||
assertThat(response).doesNotContainKey("trace");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseWithCustomErrorAttributesUsingDeprecatedApi() {
|
||||
ErrorAttributes attributes = new ErrorAttributes() {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
|
||||
return Collections.singletonMap("message", "An error occurred");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getError(WebRequest webRequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(attributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));
|
||||
assertThat(response).containsExactly(entry("message", "An error occurred"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseWithDefaultErrorAttributesSubclassUsingDelegation() {
|
||||
ErrorAttributes attributes = new DefaultErrorAttributes() {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
|
||||
Map<String, Object> response = super.getErrorAttributes(webRequest, options);
|
||||
response.put("error", "custom error");
|
||||
response.put("custom", "value");
|
||||
response.remove("path");
|
||||
return response;
|
||||
}
|
||||
|
||||
};
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(attributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));
|
||||
assertThat(response).containsEntry("error", "custom error");
|
||||
assertThat(response).containsEntry("custom", "value");
|
||||
assertThat(response).doesNotContainKey("path");
|
||||
assertThat(response).containsKey("timestamp");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseWithDefaultErrorAttributesSubclassWithoutDelegation() {
|
||||
ErrorAttributes attributes = new DefaultErrorAttributes() {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
|
||||
return Collections.singletonMap("error", "custom error");
|
||||
}
|
||||
|
||||
};
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(attributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));
|
||||
assertThat(response).containsExactly(entry("error", "custom error"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.webmvc.actuate.autoconfigure.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.convert.ApplicationConversionService;
|
||||
import org.springframework.boot.env.ConfigTreePropertySource;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.tomcat.actuate.autoconfigure.web.TomcatServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
|
||||
import org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;
|
||||
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.error.ErrorMvcAutoConfiguration;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestClient.RequestHeadersSpec.ExchangeFunction;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link WebMvcEndpointChildContextConfiguration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class WebMvcEndpointChildContextConfigurationIntegrationTests {
|
||||
|
||||
private final WebApplicationContextRunner runner = new WebApplicationContextRunner(
|
||||
AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class,
|
||||
TomcatServletWebServerAutoConfiguration.class, TomcatServletManagementContextAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class))
|
||||
.withUserConfiguration(SucceedingEndpoint.class, FailingEndpoint.class, FailingControllerEndpoint.class)
|
||||
.withInitializer(new ServerPortInfoApplicationContextInitializer())
|
||||
.withPropertyValues("server.port=0", "management.server.port=0", "management.endpoints.web.exposure.include=*",
|
||||
"server.error.include-exception=true", "server.error.include-message=always",
|
||||
"server.error.include-binding-errors=always");
|
||||
|
||||
@TempDir
|
||||
Path temp;
|
||||
|
||||
@Test // gh-17938
|
||||
void errorEndpointIsUsedWithEndpoint() {
|
||||
this.runner.run(withRestClient((client) -> {
|
||||
Map<String, ?> body = client.get()
|
||||
.uri("actuator/fail")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange(toResponseBody());
|
||||
assertThat(body).hasEntrySatisfying("exception",
|
||||
(value) -> assertThat(value).asString().contains("IllegalStateException"));
|
||||
assertThat(body).hasEntrySatisfying("message",
|
||||
(value) -> assertThat(value).asString().contains("Epic Fail"));
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorPageAndErrorControllerIncludeDetails() {
|
||||
this.runner.withPropertyValues("server.error.include-stacktrace=always", "server.error.include-message=always")
|
||||
.run(withRestClient((client) -> {
|
||||
Map<String, ?> body = client.get()
|
||||
.uri("actuator/fail")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange(toResponseBody());
|
||||
assertThat(body).hasEntrySatisfying("message",
|
||||
(value) -> assertThat(value).asString().contains("Epic Fail"));
|
||||
assertThat(body).hasEntrySatisfying("trace",
|
||||
(value) -> assertThat(value).asString().contains("java.lang.IllegalStateException: Epic Fail"));
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorEndpointIsUsedWithRestControllerEndpoint() {
|
||||
this.runner.run(withRestClient((client) -> {
|
||||
Map<String, ?> body = client.get()
|
||||
.uri("actuator/failController")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange(toResponseBody());
|
||||
assertThat(body).hasEntrySatisfying("exception",
|
||||
(value) -> assertThat(value).asString().contains("IllegalStateException"));
|
||||
assertThat(body).hasEntrySatisfying("message",
|
||||
(value) -> assertThat(value).asString().contains("Epic Fail"));
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorEndpointIsUsedWithRestControllerEndpointOnBindingError() {
|
||||
this.runner.run(withRestClient((client) -> {
|
||||
Map<String, ?> body = client.post()
|
||||
.uri("actuator/failController")
|
||||
.body(Collections.singletonMap("content", ""))
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange(toResponseBody());
|
||||
assertThat(body).hasEntrySatisfying("exception",
|
||||
(value) -> assertThat(value).asString().contains("MethodArgumentNotValidException"));
|
||||
assertThat(body).hasEntrySatisfying("message",
|
||||
(value) -> assertThat(value).asString().contains("Validation failed"));
|
||||
assertThat(body).hasEntrySatisfying("errors",
|
||||
(value) -> assertThat(value).asInstanceOf(InstanceOfAssertFactories.LIST).isNotEmpty());
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenManagementServerBasePathIsConfiguredThenEndpointsAreBeneathThatPath() {
|
||||
this.runner.withPropertyValues("management.server.base-path:/manage").run(withRestClient((client) -> {
|
||||
String body = client.get()
|
||||
.uri("manage/actuator/success")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.body(String.class);
|
||||
assertThat(body).isEqualTo("Success");
|
||||
}));
|
||||
}
|
||||
|
||||
@Test // gh-32941
|
||||
void whenManagementServerPortLoadedFromConfigTree() {
|
||||
this.runner.withInitializer(this::addConfigTreePropertySource)
|
||||
.run((context) -> assertThat(context).hasNotFailed());
|
||||
}
|
||||
|
||||
private void addConfigTreePropertySource(ConfigurableApplicationContext applicationContext) {
|
||||
try {
|
||||
applicationContext.getEnvironment()
|
||||
.setConversionService((ConfigurableConversionService) ApplicationConversionService.getSharedInstance());
|
||||
Path configtree = this.temp.resolve("configtree");
|
||||
Path file = configtree.resolve("management/server/port");
|
||||
file.toFile().getParentFile().mkdirs();
|
||||
FileCopyUtils.copy("0".getBytes(StandardCharsets.UTF_8), file.toFile());
|
||||
ConfigTreePropertySource source = new ConfigTreePropertySource("configtree", configtree);
|
||||
applicationContext.getEnvironment().getPropertySources().addFirst(source);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableWebApplicationContext> withRestClient(Consumer<RestClient> restClient) {
|
||||
return (context) -> {
|
||||
String port = context.getEnvironment().getProperty("local.management.port");
|
||||
RestClient client = RestClient.create("http://localhost:" + port);
|
||||
restClient.accept(client);
|
||||
};
|
||||
}
|
||||
|
||||
private ExchangeFunction<Map<String, ?>> toResponseBody() {
|
||||
return ((request, response) -> response.bodyTo(new ParameterizedTypeReference<Map<String, ?>>() {
|
||||
}));
|
||||
}
|
||||
|
||||
@Endpoint(id = "fail")
|
||||
static class FailingEndpoint {
|
||||
|
||||
@ReadOperation
|
||||
String fail() {
|
||||
throw new IllegalStateException("Epic Fail");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Endpoint(id = "success")
|
||||
static class SucceedingEndpoint {
|
||||
|
||||
@ReadOperation
|
||||
String fail() {
|
||||
return "Success";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = "failController")
|
||||
@SuppressWarnings("removal")
|
||||
static class FailingControllerEndpoint {
|
||||
|
||||
@GetMapping
|
||||
String fail() {
|
||||
throw new IllegalStateException("Epic Fail");
|
||||
}
|
||||
|
||||
@PostMapping(produces = "application/json")
|
||||
@ResponseBody
|
||||
String bodyValidation(@Valid @RequestBody TestBody body) {
|
||||
return body.getContent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestBody {
|
||||
|
||||
@NotEmpty
|
||||
private String content;
|
||||
|
||||
public String getContent() {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.webmvc.actuate.autoconfigure.web;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.context.request.RequestContextListener;
|
||||
import org.springframework.web.filter.RequestContextFilter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WebMvcEndpointChildContextConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class WebMvcEndpointChildContextConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withAllowBeanDefinitionOverriding(true);
|
||||
|
||||
@Test
|
||||
void contextShouldConfigureRequestContextFilter() {
|
||||
this.contextRunner.withUserConfiguration(WebMvcEndpointChildContextConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(OrderedRequestContextFilter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextShouldNotConfigureRequestContextFilterWhenPresent() {
|
||||
this.contextRunner.withUserConfiguration(ExistingConfig.class, WebMvcEndpointChildContextConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(RequestContextFilter.class);
|
||||
assertThat(context).hasBean("testRequestContextFilter");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextShouldNotConfigureRequestContextFilterWhenRequestContextListenerPresent() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(RequestContextListenerConfig.class, WebMvcEndpointChildContextConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(RequestContextListener.class);
|
||||
assertThat(context).doesNotHaveBean(OrderedRequestContextFilter.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextShouldConfigureDispatcherServletPathWithRootPath() {
|
||||
this.contextRunner.withUserConfiguration(WebMvcEndpointChildContextConfiguration.class)
|
||||
.run((context) -> assertThat(context.getBean(DispatcherServletPath.class).getPath()).isEqualTo("/"));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ExistingConfig {
|
||||
|
||||
@Bean
|
||||
RequestContextFilter testRequestContextFilter() {
|
||||
return new RequestContextFilter();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class RequestContextListenerConfig {
|
||||
|
||||
@Bean
|
||||
RequestContextListener testRequestContextListener() {
|
||||
return new RequestContextListener();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.webmvc.actuate.endpoint.web;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link AbstractWebMvcEndpointHandlerMapping}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class AbstractWebMvcEndpointHandlerMappingTests {
|
||||
|
||||
@Test
|
||||
void shouldRegisterHints() {
|
||||
RuntimeHints runtimeHints = new RuntimeHints();
|
||||
new AbstractWebMvcEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
|
||||
assertThat(RuntimeHintsPredicates.reflection()
|
||||
.onType(TypeReference
|
||||
.of("org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.OperationHandler")))
|
||||
.accepts(runtimeHints);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.webmvc.actuate.endpoint.web;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Access;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointId;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ControllerEndpointHandlerMapping}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @deprecated since 3.3.5 in favor of {@code @Endpoint} and {@code @WebEndpoint} support
|
||||
*/
|
||||
@Deprecated(since = "3.3.5", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
class ControllerEndpointHandlerMappingTests {
|
||||
|
||||
private final StaticApplicationContext context = new StaticApplicationContext();
|
||||
|
||||
@Test
|
||||
void mappingWithNoPrefix() throws Exception {
|
||||
ExposableControllerEndpoint first = firstEndpoint();
|
||||
ExposableControllerEndpoint second = secondEndpoint();
|
||||
ControllerEndpointHandlerMapping mapping = createMapping("", first, second);
|
||||
assertThat(mapping.getHandler(request("GET", "/first")).getHandler())
|
||||
.isEqualTo(handlerOf(first.getController(), "get"));
|
||||
assertThat(mapping.getHandler(request("POST", "/second")).getHandler())
|
||||
.isEqualTo(handlerOf(second.getController(), "save"));
|
||||
assertThat(mapping.getHandler(request("GET", "/third"))).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void mappingWithPrefix() throws Exception {
|
||||
ExposableControllerEndpoint first = firstEndpoint();
|
||||
ExposableControllerEndpoint second = secondEndpoint();
|
||||
ControllerEndpointHandlerMapping mapping = createMapping("actuator", first, second);
|
||||
assertThat(mapping.getHandler(request("GET", "/actuator/first")).getHandler())
|
||||
.isEqualTo(handlerOf(first.getController(), "get"));
|
||||
assertThat(mapping.getHandler(request("POST", "/actuator/second")).getHandler())
|
||||
.isEqualTo(handlerOf(second.getController(), "save"));
|
||||
assertThat(mapping.getHandler(request("GET", "/first"))).isNull();
|
||||
assertThat(mapping.getHandler(request("GET", "/second"))).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void mappingNarrowedToMethod() {
|
||||
ExposableControllerEndpoint first = firstEndpoint();
|
||||
ControllerEndpointHandlerMapping mapping = createMapping("actuator", first);
|
||||
assertThatExceptionOfType(HttpRequestMethodNotSupportedException.class)
|
||||
.isThrownBy(() -> mapping.getHandler(request("POST", "/actuator/first")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mappingWithNoPath() throws Exception {
|
||||
ExposableControllerEndpoint pathless = pathlessEndpoint();
|
||||
ControllerEndpointHandlerMapping mapping = createMapping("actuator", pathless);
|
||||
assertThat(mapping.getHandler(request("GET", "/actuator/pathless")).getHandler())
|
||||
.isEqualTo(handlerOf(pathless.getController(), "get"));
|
||||
assertThat(mapping.getHandler(request("GET", "/pathless"))).isNull();
|
||||
assertThat(mapping.getHandler(request("GET", "/"))).isNull();
|
||||
}
|
||||
|
||||
private ControllerEndpointHandlerMapping createMapping(String prefix, ExposableControllerEndpoint... endpoints) {
|
||||
ControllerEndpointHandlerMapping mapping = new ControllerEndpointHandlerMapping(new EndpointMapping(prefix),
|
||||
Arrays.asList(endpoints), null, (endpointId, defaultAccess) -> Access.UNRESTRICTED);
|
||||
mapping.setApplicationContext(this.context);
|
||||
mapping.afterPropertiesSet();
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private HandlerMethod handlerOf(Object source, String methodName) {
|
||||
return new HandlerMethod(source, ReflectionUtils.findMethod(source.getClass(), methodName));
|
||||
}
|
||||
|
||||
private MockHttpServletRequest request(String method, String requestURI) {
|
||||
return new MockHttpServletRequest(method, requestURI);
|
||||
}
|
||||
|
||||
private ExposableControllerEndpoint firstEndpoint() {
|
||||
return mockEndpoint(EndpointId.of("first"), new FirstTestMvcEndpoint());
|
||||
}
|
||||
|
||||
private ExposableControllerEndpoint secondEndpoint() {
|
||||
return mockEndpoint(EndpointId.of("second"), new SecondTestMvcEndpoint());
|
||||
}
|
||||
|
||||
private ExposableControllerEndpoint pathlessEndpoint() {
|
||||
return mockEndpoint(EndpointId.of("pathless"), new PathlessControllerEndpoint());
|
||||
}
|
||||
|
||||
private ExposableControllerEndpoint mockEndpoint(EndpointId id, Object controller) {
|
||||
ExposableControllerEndpoint endpoint = mock(ExposableControllerEndpoint.class);
|
||||
given(endpoint.getEndpointId()).willReturn(id);
|
||||
given(endpoint.getController()).willReturn(controller);
|
||||
given(endpoint.getRootPath()).willReturn(id.toString());
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@ControllerEndpoint(id = "first")
|
||||
static class FirstTestMvcEndpoint {
|
||||
|
||||
@GetMapping("/")
|
||||
String get() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ControllerEndpoint(id = "second")
|
||||
static class SecondTestMvcEndpoint {
|
||||
|
||||
@PostMapping("/")
|
||||
void save() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ControllerEndpoint(id = "pathless")
|
||||
static class PathlessControllerEndpoint {
|
||||
|
||||
@GetMapping
|
||||
String get() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.webmvc.actuate.endpoint.web;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.boot.actuate.endpoint.web.Link;
|
||||
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints;
|
||||
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping.WebMvcLinksHandler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WebMvcEndpointHandlerMapping}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class WebMvcEndpointHandlerMappingTests {
|
||||
|
||||
@Test
|
||||
void shouldRegisterHints() {
|
||||
RuntimeHints runtimeHints = new RuntimeHints();
|
||||
new WebMvcEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
|
||||
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(WebMvcLinksHandler.class, "links"))
|
||||
.accepts(runtimeHints);
|
||||
assertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user