Move remaining integration tests out of actuator-autoconfigure-all
This commit is contained in:
committed by
Phillip Webb
parent
18da9e1343
commit
bf385649ec
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.endpoint.web;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
|
||||
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.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.servlet.actuate.autoconfigure.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.web.servlet.assertj.MockMvcTester;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for the Actuator's MVC
|
||||
* {@link org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint
|
||||
* controller endpoints}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ControllerEndpointWebMvcIntegrationTests {
|
||||
|
||||
private AnnotationConfigServletWebApplicationContext context;
|
||||
|
||||
@AfterEach
|
||||
void close() {
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void endpointsCanBeAccessed() {
|
||||
this.context = new AnnotationConfigServletWebApplicationContext();
|
||||
this.context.register(DefaultConfiguration.class, ExampleController.class);
|
||||
TestPropertyValues
|
||||
.of("management.endpoints.web.base-path:/management", "management.endpoints.web.exposure.include=*")
|
||||
.applyTo(this.context);
|
||||
MockMvcTester mvc = createMockMvcTester();
|
||||
assertThat(mvc.get().uri("/management/example")).hasStatusOk();
|
||||
}
|
||||
|
||||
private MockMvcTester createMockMvcTester() {
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.refresh();
|
||||
return MockMvcTester.from(this.context);
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class, AuditAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ManagementContextAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
|
||||
BeansEndpointAutoConfiguration.class })
|
||||
static class DefaultConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = "example")
|
||||
@SuppressWarnings("removal")
|
||||
static class ExampleController {
|
||||
|
||||
@GetMapping("/")
|
||||
String example() {
|
||||
return "Example";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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.endpoint.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.servlet.actuate.autoconfigure.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
|
||||
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for controlling access to endpoints exposed by Spring MVC.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class WebMvcEndpointAccessIntegrationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(
|
||||
AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(TomcatServletWebServerAutoConfiguration.class,
|
||||
TomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
ManagementContextAutoConfiguration.class, ServletManagementContextAutoConfiguration.class,
|
||||
HealthContributorAutoConfiguration.class, BeansEndpointAutoConfiguration.class))
|
||||
.withUserConfiguration(CustomMvcEndpoint.class, CustomServletEndpoint.class)
|
||||
.withPropertyValues("server.port:0");
|
||||
|
||||
@Test
|
||||
void accessIsUnrestrictedByDefault() {
|
||||
this.contextRunner.withPropertyValues("management.endpoints.web.exposure.include=*").run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "custommvc")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "custommvc")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void accessCanBeReadOnlyByDefault() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=*",
|
||||
"management.endpoints.access.default=READ_ONLY")
|
||||
.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "custommvc")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "custommvc")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void accessCanBeNoneByDefault() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=*",
|
||||
"management.endpoints.access.default=NONE")
|
||||
.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "custommvc")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "custommvc")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void accessForOneEndpointCanOverrideTheDefaultAccess() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=*",
|
||||
"management.endpoints.access.default=READ_ONLY",
|
||||
"management.endpoint.customservlet.access=UNRESTRICTED")
|
||||
.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "custommvc")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "custommvc")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void accessCanBeCappedAtReadOnly() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=*",
|
||||
"management.endpoints.access.default=UNRESTRICTED",
|
||||
"management.endpoints.access.max-permitted=READ_ONLY")
|
||||
.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "custommvc")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "custommvc")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isTrue();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void accessCanBeCappedAtNone() {
|
||||
this.contextRunner.withPropertyValues("management.endpoints.web.exposure.include=*",
|
||||
"management.endpoints.access.default=UNRESTRICTED", "management.endpoints.access.max-permitted=NONE")
|
||||
.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "custommvc")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "custommvc")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isFalse();
|
||||
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
private RestClient createClient(AssertableWebApplicationContext context) {
|
||||
int port = context.getSourceApplicationContext(ServletWebServerApplicationContext.class)
|
||||
.getWebServer()
|
||||
.getPort();
|
||||
return RestClient.builder().defaultStatusHandler((status) -> true, (request, response) -> {
|
||||
}).baseUrl("http://localhost:" + port).build();
|
||||
}
|
||||
|
||||
private boolean isAccessible(RestClient client, HttpMethod method, String path) {
|
||||
path = "/actuator/" + path;
|
||||
ResponseEntity<byte[]> result = client.method(method).uri(path).retrieve().toEntity(byte[].class);
|
||||
if (result.getStatusCode() == HttpStatus.OK) {
|
||||
return true;
|
||||
}
|
||||
if (result.getStatusCode() == HttpStatus.NOT_FOUND || result.getStatusCode() == HttpStatus.METHOD_NOT_ALLOWED) {
|
||||
return false;
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
String.format("Unexpected %s HTTP status for endpoint %s", result.getStatusCode(), path));
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = "custommvc")
|
||||
@SuppressWarnings("removal")
|
||||
static class CustomMvcEndpoint {
|
||||
|
||||
@GetMapping("/")
|
||||
String get() {
|
||||
return "get";
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
String post() {
|
||||
return "post";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = "customservlet")
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
static class CustomServletEndpoint
|
||||
implements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {
|
||||
|
||||
@Override
|
||||
public org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {
|
||||
return new org.springframework.boot.actuate.endpoint.web.EndpointServlet(new HttpServlet() {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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.endpoint.web;
|
||||
|
||||
import org.assertj.core.api.ThrowingConsumer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
|
||||
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.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.servlet.actuate.autoconfigure.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.web.servlet.assertj.MockMvcTester;
|
||||
import org.springframework.test.web.servlet.assertj.MvcTestResult;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for the MVC actuator endpoints' CORS support
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @see WebMvcEndpointManagementContextConfiguration
|
||||
*/
|
||||
class WebMvcEndpointCorsIntegrationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class))
|
||||
.withPropertyValues("management.endpoints.web.exposure.include:*");
|
||||
|
||||
@Test
|
||||
void corsIsDisabledByDefault() {
|
||||
this.contextRunner.run(withMockMvc((mvc) -> assertThat(mvc.options()
|
||||
.uri("/actuator/beans")
|
||||
.header("Origin", "foo.example.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET"))
|
||||
.doesNotContainHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingAllowedOriginsEnablesCors() {
|
||||
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com")
|
||||
.run(withMockMvc((mvc) -> {
|
||||
assertThat(mvc.options()
|
||||
.uri("/actuator/beans")
|
||||
.header("Origin", "bar.example.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET")).hasStatus(HttpStatus.FORBIDDEN);
|
||||
performAcceptedCorsRequest(mvc);
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingAllowedOriginPatternsEnablesCors() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.cors.allowed-origin-patterns:*.example.com",
|
||||
"management.endpoints.web.cors.allow-credentials:true")
|
||||
.run(withMockMvc((mvc) -> {
|
||||
assertThat(mvc.options()
|
||||
.uri("/actuator/beans")
|
||||
.header("Origin", "bar.example.org")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET")).hasStatus(HttpStatus.FORBIDDEN);
|
||||
performAcceptedCorsRequest(mvc);
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void maxAgeDefaultsTo30Minutes() {
|
||||
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com")
|
||||
.run(withMockMvc((mvc) -> {
|
||||
MvcTestResult result = performAcceptedCorsRequest(mvc);
|
||||
assertThat(result).hasHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800");
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void maxAgeCanBeConfigured() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.web.cors.max-age: 2400")
|
||||
.run(withMockMvc((mvc) -> {
|
||||
MvcTestResult result = performAcceptedCorsRequest(mvc);
|
||||
assertThat(result).hasHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "2400");
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestsWithDisallowedHeadersAreRejected() {
|
||||
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com")
|
||||
.run(withMockMvc((mvc) -> assertThat(mvc.options()
|
||||
.uri("/actuator/beans")
|
||||
.header("Origin", "foo.example.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "Alpha")).hasStatus(HttpStatus.FORBIDDEN)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowedHeadersCanBeConfigured() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.web.cors.allowed-headers:Alpha,Bravo")
|
||||
.run(withMockMvc((mvc) -> assertThat(mvc.options()
|
||||
.uri("/actuator/beans")
|
||||
.header("Origin", "foo.example.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "Alpha")).hasStatusOk()
|
||||
.headers()
|
||||
.hasValue(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Alpha")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestsWithDisallowedMethodsAreRejected() {
|
||||
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com")
|
||||
.run(withMockMvc((mvc) -> assertThat(mvc.options()
|
||||
.uri("/actuator/beans")
|
||||
.header(HttpHeaders.ORIGIN, "foo.example.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "PATCH")).hasStatus(HttpStatus.FORBIDDEN)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowedMethodsCanBeConfigured() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.web.cors.allowed-methods:GET,HEAD")
|
||||
.run(withMockMvc((mvc) -> assertThat(mvc.options()
|
||||
.uri("/actuator/beans")
|
||||
.header(HttpHeaders.ORIGIN, "foo.example.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "HEAD")).hasStatusOk()
|
||||
.headers()
|
||||
.hasValue(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,HEAD")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void credentialsCanBeAllowed() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.web.cors.allow-credentials:true")
|
||||
.run(withMockMvc((mvc) -> {
|
||||
MvcTestResult result = performAcceptedCorsRequest(mvc);
|
||||
assertThat(result).hasHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void credentialsCanBeDisabled() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.web.cors.allow-credentials:false")
|
||||
.run(withMockMvc((mvc) -> {
|
||||
MvcTestResult result = performAcceptedCorsRequest(mvc);
|
||||
assertThat(result).doesNotContainHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS);
|
||||
}));
|
||||
}
|
||||
|
||||
private ContextConsumer<WebApplicationContext> withMockMvc(ThrowingConsumer<MockMvcTester> mvc) {
|
||||
return (context) -> mvc.accept(MockMvcTester.from(context));
|
||||
}
|
||||
|
||||
private MvcTestResult performAcceptedCorsRequest(MockMvcTester mvc) {
|
||||
return performAcceptedCorsRequest(mvc, "/actuator/beans");
|
||||
}
|
||||
|
||||
private MvcTestResult performAcceptedCorsRequest(MockMvcTester mvc, String url) {
|
||||
MvcTestResult result = mvc.options()
|
||||
.uri(url)
|
||||
.header(HttpHeaders.ORIGIN, "foo.example.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET")
|
||||
.exchange();
|
||||
assertThat(result).hasStatusOk().hasHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "foo.example.com");
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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.endpoint.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;
|
||||
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
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.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.servlet.actuate.autoconfigure.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.servlet.actuate.autoconfigure.exchanges.ServletHttpExchangesAutoConfiguration;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
|
||||
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for Endpoints over Spring MVC.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class WebMvcEndpointExposureIntegrationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(
|
||||
AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(TomcatServletWebServerAutoConfiguration.class,
|
||||
TomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
ManagementContextAutoConfiguration.class, ManagementContextAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class, ServletHttpExchangesAutoConfiguration.class,
|
||||
HealthContributorAutoConfiguration.class, BeansEndpointAutoConfiguration.class,
|
||||
HealthEndpointAutoConfiguration.class, ShutdownEndpointAutoConfiguration.class))
|
||||
.withUserConfiguration(CustomMvcEndpoint.class, CustomServletEndpoint.class,
|
||||
HttpExchangeRepositoryConfiguration.class, AuditEventRepositoryConfiguration.class)
|
||||
.withPropertyValues("server.port:0");
|
||||
|
||||
@Test
|
||||
void webEndpointsExceptHealthAreDisabledByDefault() {
|
||||
this.contextRunner.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isExposed(client, HttpMethod.GET, "beans")).isFalse();
|
||||
assertThat(isExposed(client, HttpMethod.GET, "health")).isTrue();
|
||||
assertThat(isExposed(client, HttpMethod.POST, "shutdown")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void webEndpointsCanBeExposed() {
|
||||
WebApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=*");
|
||||
contextRunner.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isExposed(client, HttpMethod.GET, "beans")).isTrue();
|
||||
assertThat(isExposed(client, HttpMethod.GET, "health")).isTrue();
|
||||
assertThat(isExposed(client, HttpMethod.POST, "shutdown")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleWebEndpointCanBeExposed() {
|
||||
WebApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=beans");
|
||||
contextRunner.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isExposed(client, HttpMethod.GET, "beans")).isTrue();
|
||||
assertThat(isExposed(client, HttpMethod.GET, "health")).isFalse();
|
||||
assertThat(isExposed(client, HttpMethod.POST, "shutdown")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleWebEndpointCanBeExcluded() {
|
||||
WebApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues(
|
||||
"management.endpoints.web.exposure.include=*", "management.endpoints.web.exposure.exclude=beans");
|
||||
contextRunner.run((context) -> {
|
||||
RestClient client = createClient(context);
|
||||
assertThat(isExposed(client, HttpMethod.GET, "beans")).isFalse();
|
||||
assertThat(isExposed(client, HttpMethod.GET, "health")).isTrue();
|
||||
assertThat(isExposed(client, HttpMethod.POST, "shutdown")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
private RestClient createClient(AssertableWebApplicationContext context) {
|
||||
int port = context.getSourceApplicationContext(ServletWebServerApplicationContext.class)
|
||||
.getWebServer()
|
||||
.getPort();
|
||||
return RestClient.builder().defaultStatusHandler((status) -> true, (request, response) -> {
|
||||
}).baseUrl("http://localhost:" + port).build();
|
||||
}
|
||||
|
||||
private boolean isExposed(RestClient client, HttpMethod method, String path) {
|
||||
path = "/actuator/" + path;
|
||||
ResponseEntity<byte[]> result = client.method(method).uri(path).retrieve().toEntity(byte[].class);
|
||||
if (result.getStatusCode() == HttpStatus.OK) {
|
||||
return true;
|
||||
}
|
||||
if (result.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return false;
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
String.format("Unexpected %s HTTP status for endpoint %s", result.getStatusCode(), path));
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = "custommvc")
|
||||
@SuppressWarnings("removal")
|
||||
static class CustomMvcEndpoint {
|
||||
|
||||
@GetMapping("/")
|
||||
String main() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = "customservlet")
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
static class CustomServletEndpoint
|
||||
implements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {
|
||||
|
||||
@Override
|
||||
public org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {
|
||||
return new org.springframework.boot.actuate.endpoint.web.EndpointServlet(new HttpServlet() {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class HttpExchangeRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
InMemoryHttpExchangeRepository httpExchangeRepository() {
|
||||
return new InMemoryHttpExchangeRepository();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class AuditEventRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
InMemoryAuditEventRepository auditEventRepository() {
|
||||
return new InMemoryAuditEventRepository();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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.endpoint.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
|
||||
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.endpoint.jackson.EndpointObjectMapper;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.servlet.actuate.autoconfigure.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;
|
||||
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.web.servlet.assertj.MockMvcTester;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for the Actuator's MVC endpoints.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class WebMvcEndpointIntegrationTests {
|
||||
|
||||
private AnnotationConfigServletWebApplicationContext context;
|
||||
|
||||
@Test
|
||||
void webMvcEndpointHandlerMappingIsConfiguredWithPathPatternParser() {
|
||||
this.context = new AnnotationConfigServletWebApplicationContext();
|
||||
this.context.register(DefaultConfiguration.class);
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.refresh();
|
||||
WebMvcEndpointHandlerMapping handlerMapping = this.context.getBean(WebMvcEndpointHandlerMapping.class);
|
||||
assertThat(handlerMapping.getPatternParser()).isInstanceOf(PathPatternParser.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void linksAreProvidedToAllEndpointTypes() {
|
||||
this.context = new AnnotationConfigServletWebApplicationContext();
|
||||
this.context.register(DefaultConfiguration.class, EndpointsConfiguration.class);
|
||||
TestPropertyValues.of("management.endpoints.web.exposure.include=*").applyTo(this.context);
|
||||
MockMvcTester mvc = doCreateMockMvcTester();
|
||||
assertThat(mvc.get().uri("/actuator").accept("*/*")).hasStatusOk()
|
||||
.bodyJson()
|
||||
.extractingPath("_links")
|
||||
.asMap()
|
||||
.containsKeys("beans", "servlet", "restcontroller", "controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void linksPageIsNotAvailableWhenDisabled() {
|
||||
this.context = new AnnotationConfigServletWebApplicationContext();
|
||||
this.context.register(DefaultConfiguration.class, EndpointsConfiguration.class);
|
||||
TestPropertyValues.of("management.endpoints.web.discovery.enabled=false").applyTo(this.context);
|
||||
MockMvcTester mvc = doCreateMockMvcTester();
|
||||
assertThat(mvc.get().uri("/actuator").accept("*/*")).hasStatus(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
void endpointObjectMapperCanBeApplied() {
|
||||
this.context = new AnnotationConfigServletWebApplicationContext();
|
||||
this.context.register(EndpointObjectMapperConfiguration.class, DefaultConfiguration.class);
|
||||
TestPropertyValues.of("management.endpoints.web.exposure.include=*").applyTo(this.context);
|
||||
MockMvcTester mvc = doCreateMockMvcTester();
|
||||
assertThat(mvc.get().uri("/actuator/beans")).hasStatusOk().bodyText().contains("\"scope\":\"notelgnis\"");
|
||||
}
|
||||
|
||||
private MockMvcTester doCreateMockMvcTester() {
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.refresh();
|
||||
return MockMvcTester.from(this.context);
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class, AuditAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ManagementContextAutoConfiguration.class, AuditAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, BeansEndpointAutoConfiguration.class })
|
||||
static class DefaultConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = "servlet")
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
static class TestServletEndpoint
|
||||
implements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {
|
||||
|
||||
@Override
|
||||
public org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {
|
||||
return new org.springframework.boot.actuate.endpoint.web.EndpointServlet(new HttpServlet() {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint(id = "controller")
|
||||
@SuppressWarnings("removal")
|
||||
static class TestControllerEndpoint {
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = "restcontroller")
|
||||
@SuppressWarnings("removal")
|
||||
static class TestRestControllerEndpoint {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class EndpointsConfiguration {
|
||||
|
||||
@Bean
|
||||
TestServletEndpoint testServletEndpoint() {
|
||||
return new TestServletEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestControllerEndpoint testControllerEndpoint() {
|
||||
return new TestControllerEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestRestControllerEndpoint testRestControllerEndpoint() {
|
||||
return new TestRestControllerEndpoint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
static class EndpointObjectMapperConfiguration {
|
||||
|
||||
@Bean
|
||||
EndpointObjectMapper endpointObjectMapper() {
|
||||
SimpleModule module = new SimpleModule();
|
||||
module.addSerializer(String.class, new ReverseStringSerializer());
|
||||
ObjectMapper objectMapper = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json()
|
||||
.modules(module)
|
||||
.build();
|
||||
return () -> objectMapper;
|
||||
}
|
||||
|
||||
static class ReverseStringSerializer extends StdScalarSerializer<Object> {
|
||||
|
||||
ReverseStringSerializer() {
|
||||
super(String.class, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty(SerializerProvider prov, Object value) {
|
||||
return ((String) value).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
|
||||
serialize(value, gen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider,
|
||||
TypeSerializer typeSer) throws IOException {
|
||||
serialize(value, gen);
|
||||
}
|
||||
|
||||
private void serialize(Object value, JsonGenerator gen) throws IOException {
|
||||
StringBuilder builder = new StringBuilder((String) value);
|
||||
gen.writeString(builder.reverse().toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.endpoint.web;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.integrationtest.AbstractHealthEndpointAdditionalPathIntegrationTests;
|
||||
import org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.servlet.actuate.autoconfigure.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
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.actuate.autoconfigure.health.WebMvcHealthEndpointExtensionAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
|
||||
/**
|
||||
* Integration tests for MVC health groups on an additional path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class WebMvcHealthEndpointAdditionalPathIntegrationTests extends
|
||||
AbstractHealthEndpointAdditionalPathIntegrationTests<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {
|
||||
|
||||
WebMvcHealthEndpointAdditionalPathIntegrationTests() {
|
||||
super(new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ManagementContextAutoConfiguration.class,
|
||||
TomcatServletWebServerAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,
|
||||
TomcatServletManagementContextAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
|
||||
HealthEndpointAutoConfiguration.class, WebMvcHealthEndpointExtensionAutoConfiguration.class,
|
||||
DiskSpaceHealthContributorAutoConfiguration.class))
|
||||
.withInitializer(new ServerPortInfoApplicationContextInitializer())
|
||||
.withPropertyValues("server.port=0"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user