Commit 86cd7275 authored by Madhura Bhave's avatar Madhura Bhave

MVC endpoints bean methods are @ConditionalOnMissingBean

Fixes gh-10105
parent beb257f4
...@@ -111,8 +111,9 @@ public class EndpointWebMvcHypermediaManagementContextConfiguration { ...@@ -111,8 +111,9 @@ public class EndpointWebMvcHypermediaManagementContextConfiguration {
}; };
} }
@ConditionalOnEnabledEndpoint("actuator")
@Bean @Bean
@ConditionalOnEnabledEndpoint("actuator")
@ConditionalOnMissingBean
public HalJsonMvcEndpoint halJsonMvcEndpoint( public HalJsonMvcEndpoint halJsonMvcEndpoint(
ManagementServletContext managementServletContext, ManagementServletContext managementServletContext,
ResourceProperties resources, ResourceLoader resourceLoader) { ResourceProperties resources, ResourceLoader resourceLoader) {
...@@ -137,6 +138,7 @@ public class EndpointWebMvcHypermediaManagementContextConfiguration { ...@@ -137,6 +138,7 @@ public class EndpointWebMvcHypermediaManagementContextConfiguration {
static class DocsMvcEndpointConfiguration { static class DocsMvcEndpointConfiguration {
@Bean @Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint("docs") @ConditionalOnEnabledEndpoint("docs")
@ConditionalOnResource(resources = "classpath:/META-INF/resources/spring-boot-actuator/docs/index.html") @ConditionalOnResource(resources = "classpath:/META-INF/resources/spring-boot-actuator/docs/index.html")
public DocsMvcEndpoint docsMvcEndpoint( public DocsMvcEndpoint docsMvcEndpoint(
......
...@@ -143,6 +143,7 @@ public class EndpointWebMvcManagementContextConfiguration { ...@@ -143,6 +143,7 @@ public class EndpointWebMvcManagementContextConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean
@ConditionalOnBean(EnvironmentEndpoint.class) @ConditionalOnBean(EnvironmentEndpoint.class)
@ConditionalOnEnabledEndpoint("env") @ConditionalOnEnabledEndpoint("env")
public EnvironmentMvcEndpoint environmentMvcEndpoint(EnvironmentEndpoint delegate) { public EnvironmentMvcEndpoint environmentMvcEndpoint(EnvironmentEndpoint delegate) {
...@@ -173,6 +174,7 @@ public class EndpointWebMvcManagementContextConfiguration { ...@@ -173,6 +174,7 @@ public class EndpointWebMvcManagementContextConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean
@ConditionalOnBean(LoggersEndpoint.class) @ConditionalOnBean(LoggersEndpoint.class)
@ConditionalOnEnabledEndpoint("loggers") @ConditionalOnEnabledEndpoint("loggers")
public LoggersMvcEndpoint loggersMvcEndpoint(LoggersEndpoint delegate) { public LoggersMvcEndpoint loggersMvcEndpoint(LoggersEndpoint delegate) {
...@@ -180,6 +182,7 @@ public class EndpointWebMvcManagementContextConfiguration { ...@@ -180,6 +182,7 @@ public class EndpointWebMvcManagementContextConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean
@ConditionalOnBean(MetricsEndpoint.class) @ConditionalOnBean(MetricsEndpoint.class)
@ConditionalOnEnabledEndpoint("metrics") @ConditionalOnEnabledEndpoint("metrics")
public MetricsMvcEndpoint metricsMvcEndpoint(MetricsEndpoint delegate) { public MetricsMvcEndpoint metricsMvcEndpoint(MetricsEndpoint delegate) {
...@@ -187,6 +190,7 @@ public class EndpointWebMvcManagementContextConfiguration { ...@@ -187,6 +190,7 @@ public class EndpointWebMvcManagementContextConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint("logfile") @ConditionalOnEnabledEndpoint("logfile")
@Conditional(LogFileCondition.class) @Conditional(LogFileCondition.class)
public LogFileMvcEndpoint logfileMvcEndpoint() { public LogFileMvcEndpoint logfileMvcEndpoint() {
...@@ -194,6 +198,7 @@ public class EndpointWebMvcManagementContextConfiguration { ...@@ -194,6 +198,7 @@ public class EndpointWebMvcManagementContextConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean
@ConditionalOnBean(ShutdownEndpoint.class) @ConditionalOnBean(ShutdownEndpoint.class)
@ConditionalOnEnabledEndpoint(value = "shutdown", enabledByDefault = false) @ConditionalOnEnabledEndpoint(value = "shutdown", enabledByDefault = false)
public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) { public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) {
...@@ -201,6 +206,7 @@ public class EndpointWebMvcManagementContextConfiguration { ...@@ -201,6 +206,7 @@ public class EndpointWebMvcManagementContextConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean
@ConditionalOnBean(AuditEventRepository.class) @ConditionalOnBean(AuditEventRepository.class)
@ConditionalOnEnabledEndpoint("auditevents") @ConditionalOnEnabledEndpoint("auditevents")
public AuditEventsMvcEndpoint auditEventMvcEndpoint( public AuditEventsMvcEndpoint auditEventMvcEndpoint(
......
...@@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link EndpointWebMvcHypermediaManagementContextConfiguration}. * Tests for {@link EndpointWebMvcHypermediaManagementContextConfiguration}.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Madhura Bhave
*/ */
public class EndpointWebMvcHypermediaManagementContextConfigurationTests { public class EndpointWebMvcHypermediaManagementContextConfigurationTests {
...@@ -112,7 +113,38 @@ public class EndpointWebMvcHypermediaManagementContextConfigurationTests { ...@@ -112,7 +113,38 @@ public class EndpointWebMvcHypermediaManagementContextConfigurationTests {
.isEqualTo("http://localhost/docs/#spring_boot_actuator__{rel}"); .isEqualTo("http://localhost/docs/#spring_boot_actuator__{rel}");
} }
@Test
public void halJsonMvcEndpointIsConditionalOnMissingBean() throws Exception {
createContext();
this.context.register(HalJsonConfiguration.class, TestConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcHypermediaManagementContextConfiguration.class);
this.context.refresh();
HalJsonMvcEndpoint bean = this.context.getBean(HalJsonMvcEndpoint.class);
assertThat(bean).isInstanceOf(TestHalJsonMvcEndpoint.class);
}
@Test
public void docsMvcEndpointIsConditionalOnMissingBean() throws Exception {
createContext();
this.context.register(DocsConfiguration.class, TestConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcHypermediaManagementContextConfiguration.class);
this.context.refresh();
DocsMvcEndpoint bean = this.context.getBean(DocsMvcEndpoint.class);
assertThat(bean).isInstanceOf(TestDocsMvcEndpoint.class);
}
private void load(String... properties) { private void load(String... properties) {
createContext();
EnvironmentTestUtils.addEnvironment(this.context, properties);
this.context.register(TestConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcHypermediaManagementContextConfiguration.class);
this.context.refresh();
}
private void createContext() {
this.context = new AnnotationConfigWebApplicationContext(); this.context = new AnnotationConfigWebApplicationContext();
this.context.setClassLoader(new ClassLoader(getClass().getClassLoader()) { this.context.setClassLoader(new ClassLoader(getClass().getClassLoader()) {
...@@ -126,11 +158,6 @@ public class EndpointWebMvcHypermediaManagementContextConfigurationTests { ...@@ -126,11 +158,6 @@ public class EndpointWebMvcHypermediaManagementContextConfigurationTests {
} }
}); });
EnvironmentTestUtils.addEnvironment(this.context, properties);
this.context.register(TestConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcHypermediaManagementContextConfiguration.class);
this.context.refresh();
} }
private String getCurieHref() { private String getCurieHref() {
...@@ -152,4 +179,40 @@ public class EndpointWebMvcHypermediaManagementContextConfigurationTests { ...@@ -152,4 +179,40 @@ public class EndpointWebMvcHypermediaManagementContextConfigurationTests {
} }
@Configuration
static class DocsConfiguration {
@Bean
public DocsMvcEndpoint testDocsMvcEndpoint(ManagementServletContext managementServletContext) {
return new TestDocsMvcEndpoint(managementServletContext);
}
}
@Configuration
static class HalJsonConfiguration {
@Bean
public HalJsonMvcEndpoint testHalJsonMvcEndpoint(ManagementServletContext managementServletContext) {
return new TestHalJsonMvcEndpoint(managementServletContext);
}
}
static class TestDocsMvcEndpoint extends DocsMvcEndpoint {
TestDocsMvcEndpoint(ManagementServletContext managementServletContext) {
super(managementServletContext);
}
}
static class TestHalJsonMvcEndpoint extends HalJsonMvcEndpoint {
TestHalJsonMvcEndpoint(ManagementServletContext managementServletContext) {
super(managementServletContext);
}
}
} }
...@@ -16,21 +16,43 @@ ...@@ -16,21 +16,43 @@
package org.springframework.boot.actuate.autoconfigure; package org.springframework.boot.actuate.autoconfigure;
import java.security.Principal;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.AuditEventsMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.LogFileMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.LoggersMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpointSecurityInterceptor; import org.springframework.boot.actuate.endpoint.mvc.MvcEndpointSecurityInterceptor;
import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockServletContext; import org.springframework.mock.web.MockServletContext;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
...@@ -50,14 +72,6 @@ public class EndpointWebMvcManagementContextConfigurationTests { ...@@ -50,14 +72,6 @@ public class EndpointWebMvcManagementContextConfigurationTests {
public void setup() { public void setup() {
this.context = new AnnotationConfigWebApplicationContext(); this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext()); this.context.setServletContext(new MockServletContext());
this.context.register(SecurityAutoConfiguration.class,
WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
WebClientAutoConfiguration.class,
EndpointWebMvcManagementContextConfiguration.class);
} }
@After @After
...@@ -72,6 +86,7 @@ public class EndpointWebMvcManagementContextConfigurationTests { ...@@ -72,6 +86,7 @@ public class EndpointWebMvcManagementContextConfigurationTests {
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"management.security.enabled=false", "management.security.enabled=false",
"management.security.roles=my-role,your-role"); "management.security.roles=my-role,your-role");
this.context.register(TestEndpointConfiguration.class);
this.context.refresh(); this.context.refresh();
EndpointHandlerMapping mapping = this.context.getBean("endpointHandlerMapping", EndpointHandlerMapping mapping = this.context.getBean("endpointHandlerMapping",
EndpointHandlerMapping.class); EndpointHandlerMapping.class);
...@@ -84,9 +99,237 @@ public class EndpointWebMvcManagementContextConfigurationTests { ...@@ -84,9 +99,237 @@ public class EndpointWebMvcManagementContextConfigurationTests {
assertThat(roles).containsExactly("my-role", "your-role"); assertThat(roles).containsExactly("my-role", "your-role");
} }
@Test
public void healthMvcEndpointIsConditionalOnMissingBean() throws Exception {
this.context.register(HealthConfiguration.class, TestEndpointConfiguration.class);
this.context.refresh();
HealthMvcEndpoint mvcEndpoint = this.context.getBean(HealthMvcEndpoint.class);
assertThat(mvcEndpoint).isInstanceOf(TestHealthMvcEndpoint.class);
}
@Test
public void envMvcEndpointIsConditionalOnMissingBean() throws Exception {
this.context.register(EnvConfiguration.class, TestEndpointConfiguration.class);
this.context.refresh();
EnvironmentMvcEndpoint mvcEndpoint = this.context.getBean(EnvironmentMvcEndpoint.class);
assertThat(mvcEndpoint).isInstanceOf(TestEnvMvcEndpoint.class);
}
@Test
public void metricsMvcEndpointIsConditionalOnMissingBean() throws Exception {
this.context.register(MetricsConfiguration.class, TestEndpointConfiguration.class);
this.context.refresh();
MetricsMvcEndpoint mvcEndpoint = this.context.getBean(MetricsMvcEndpoint.class);
assertThat(mvcEndpoint).isInstanceOf(TestMetricsMvcEndpoint.class);
}
@Test
public void logFileMvcEndpointIsConditionalOnMissingBean() throws Exception {
this.context.register(LogFileConfiguration.class, TestEndpointConfiguration.class);
this.context.refresh();
LogFileMvcEndpoint mvcEndpoint = this.context.getBean(LogFileMvcEndpoint.class);
assertThat(mvcEndpoint).isInstanceOf(TestLogFileMvcEndpoint.class);
}
@Test
public void shutdownEndpointIsConditionalOnMissingBean() throws Exception {
this.context.register(ShutdownConfiguration.class, TestEndpointConfiguration.class);
this.context.refresh();
ShutdownMvcEndpoint mvcEndpoint = this.context.getBean(ShutdownMvcEndpoint.class);
assertThat(mvcEndpoint).isInstanceOf(TestShutdownMvcEndpoint.class);
}
@Test
public void auditEventsMvcEndpointIsConditionalOnMissingBean() throws Exception {
this.context.register(AuditEventsConfiguration.class, TestEndpointConfiguration.class);
this.context.refresh();
AuditEventsMvcEndpoint mvcEndpoint = this.context.getBean(AuditEventsMvcEndpoint.class);
assertThat(mvcEndpoint).isInstanceOf(TestAuditEventsMvcEndpoint.class);
}
@Test
public void loggersMvcEndpointIsConditionalOnMissingBean() throws Exception {
this.context.register(LoggersConfiguration.class, TestEndpointConfiguration.class);
this.context.refresh();
LoggersMvcEndpoint mvcEndpoint = this.context.getBean(LoggersMvcEndpoint.class);
assertThat(mvcEndpoint).isInstanceOf(TestLoggersMvcEndpoint.class);
}
@Test
public void heapdumpMvcEndpointIsConditionalOnMissingBean() throws Exception {
this.context.register(HeapdumpConfiguration.class, TestEndpointConfiguration.class);
this.context.refresh();
HeapdumpMvcEndpoint mvcEndpoint = this.context.getBean(HeapdumpMvcEndpoint.class);
assertThat(mvcEndpoint).isInstanceOf(TestHeapdumpMvcEndpoint.class);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private List<String> getRoles(MvcEndpointSecurityInterceptor securityInterceptor) { private List<String> getRoles(MvcEndpointSecurityInterceptor securityInterceptor) {
return (List<String>) ReflectionTestUtils.getField(securityInterceptor, "roles"); return (List<String>) ReflectionTestUtils.getField(securityInterceptor, "roles");
} }
@Configuration
@ImportAutoConfiguration({ SecurityAutoConfiguration.class,
WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
WebClientAutoConfiguration.class,
EndpointWebMvcManagementContextConfiguration.class })
static class TestEndpointConfiguration {
}
@Configuration
static class HealthConfiguration {
@Bean
public HealthMvcEndpoint testHealthMvcEndpoint(HealthEndpoint endpoint) {
return new TestHealthMvcEndpoint(endpoint);
}
}
static class EnvConfiguration {
@Bean
public EnvironmentMvcEndpoint testEnvironmentMvcEndpoint(EnvironmentEndpoint endpoint) {
return new TestEnvMvcEndpoint(endpoint);
}
}
static class MetricsConfiguration {
@Bean
public MetricsMvcEndpoint testMetricsMvcEndpoint(MetricsEndpoint endpoint) {
return new TestMetricsMvcEndpoint(endpoint);
}
}
static class LoggersConfiguration {
@Bean
public LoggersMvcEndpoint testLoggersMvcEndpoint(LoggersEndpoint endpoint) {
return new TestLoggersMvcEndpoint(endpoint);
}
@Bean
LoggersEndpoint loggersEndpoint() {
return new LoggersEndpoint(new LoggingSystem() {
@Override
public void beforeInitialize() {
}
});
}
}
static class LogFileConfiguration {
@Bean
public LogFileMvcEndpoint testLogFileMvcEndpoint() {
return new TestLogFileMvcEndpoint();
}
}
static class AuditEventsConfiguration {
@Bean
public AuditEventRepository repository() {
return new TestAuditEventRepository();
}
@Bean
public AuditEventsMvcEndpoint testAuditEventsMvcEndpoint(AuditEventRepository repository) {
return new TestAuditEventsMvcEndpoint(repository);
}
}
static class TestAuditEventRepository extends InMemoryAuditEventRepository {
}
static class HeapdumpConfiguration {
@Bean
public HeapdumpMvcEndpoint testHeapdumpMvcEndpoint() {
return new TestHeapdumpMvcEndpoint();
}
}
static class ShutdownConfiguration {
@Bean
public ShutdownMvcEndpoint testShutdownMvcEndpoint(ShutdownEndpoint endpoint) {
return new TestShutdownMvcEndpoint(endpoint);
}
}
static class TestHealthMvcEndpoint extends HealthMvcEndpoint {
TestHealthMvcEndpoint(HealthEndpoint delegate) {
super(delegate);
}
@Override
protected boolean exposeHealthDetails(HttpServletRequest request,
Principal principal) {
return true;
}
}
static class TestEnvMvcEndpoint extends EnvironmentMvcEndpoint {
TestEnvMvcEndpoint(EnvironmentEndpoint delegate) {
super(delegate);
}
}
static class TestLoggersMvcEndpoint extends LoggersMvcEndpoint {
TestLoggersMvcEndpoint(LoggersEndpoint delegate) {
super(delegate);
}
}
static class TestHeapdumpMvcEndpoint extends HeapdumpMvcEndpoint {
}
static class TestLogFileMvcEndpoint extends LogFileMvcEndpoint {
}
static class TestMetricsMvcEndpoint extends MetricsMvcEndpoint {
TestMetricsMvcEndpoint(MetricsEndpoint delegate) {
super(delegate);
}
}
static class TestAuditEventsMvcEndpoint extends AuditEventsMvcEndpoint {
TestAuditEventsMvcEndpoint(AuditEventRepository auditEventRepository) {
super(auditEventRepository);
}
}
static class TestShutdownMvcEndpoint extends ShutdownMvcEndpoint {
TestShutdownMvcEndpoint(ShutdownEndpoint delegate) {
super(delegate);
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment