From a8bf9d34d586d5defbef5ead09e558b01d0c2702 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 7 Apr 2015 17:24:45 +0100 Subject: [PATCH] Honour endpoint.enabled:false for nested paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, only invocations of /metricName/ would honour the enabled property and return a not found (404) response. For endpoints which support nested paths, access to /metricName/foo would ignore the enabled flag and return an OK (200) response. Furthermore, there was a comment in EndpointMvcAdapter that suggested that an endpoint shouldn’t be called when it is disabled, however this was not the case. This commit updates EndpointWebMvcAutoConfiguration and JolokiaAutoConfiguration to only register their MvcEndpoint beans if the underlying endpoint is enabled. This means that an EndpointMvcAdapter should not be called if its delegate is disabled, making the comment described above accurate. The check for the delegate being enabled has been retained so as not to rely upon the auto-configurations’ behaviour. The methods which handle nested paths (MetricsMvcEndpoint.value() and EnvironmentMvcEndpoint.value()) have been updated to add the same check for the enablement of their delegate. Fixes gh-2767 --- .../EndpointWebMvcAutoConfiguration.java | 13 +- .../JolokiaAutoConfiguration.java | 11 +- .../endpoint/mvc/EndpointMvcAdapter.java | 24 +++- .../endpoint/mvc/EnvironmentMvcEndpoint.java | 8 +- .../endpoint/mvc/MetricsMvcEndpoint.java | 8 +- .../EndpointWebMvcAutoConfigurationTests.java | 132 +++++++++++++++--- .../JolokiaAutoConfigurationTests.java | 34 ++++- .../mvc/EnvironmentMvcEndpointTests.java | 12 +- ...> JolokiaMvcEndpointContextPathTests.java} | 8 +- ...ests.java => JolokiaMvcEndpointTests.java} | 10 +- .../endpoint/mvc/MetricsMvcEndpointTests.java | 124 ++++++++++++++++ 11 files changed, 338 insertions(+), 46 deletions(-) rename spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/{JolokiaEndpointContextPathTests.java => JolokiaMvcEndpointContextPathTests.java} (91%) rename spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/{JolokiaEndpointTests.java => JolokiaMvcEndpointTests.java} (94%) create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpointTests.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java index ebce6a5877e..174b02af599 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -51,8 +51,8 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; @@ -84,6 +84,7 @@ import org.springframework.web.servlet.DispatcherServlet; * @author Dave Syer * @author Phillip Webb * @author Christian Dupuis + * @author Andy Wilkinson */ @Configuration @ConditionalOnClass({ Servlet.class, DispatcherServlet.class }) @@ -155,14 +156,14 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, @Bean @ConditionalOnBean(EnvironmentEndpoint.class) - @ConditionalOnProperty(prefix = "endpoints.env", name = "enabled", matchIfMissing = true) + @ConditionalOnExpression("${endpoints.env.enabled:${endpoints.enabled:true}}") public EnvironmentMvcEndpoint environmentMvcEndpoint(EnvironmentEndpoint delegate) { return new EnvironmentMvcEndpoint(delegate); } @Bean @ConditionalOnBean(HealthEndpoint.class) - @ConditionalOnProperty(prefix = "endpoints.health", name = "enabled", matchIfMissing = true) + @ConditionalOnExpression("${endpoints.health.enabled:${endpoints.enabled:true}}") public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate) { Security security = this.managementServerProperties.getSecurity(); boolean secure = (security == null || security.isEnabled()); @@ -176,14 +177,14 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, @Bean @ConditionalOnBean(MetricsEndpoint.class) - @ConditionalOnProperty(prefix = "endpoints.metrics", name = "enabled", matchIfMissing = true) + @ConditionalOnExpression("${endpoints.metrics.enabled:${endpoints.enabled:true}}") public MetricsMvcEndpoint metricsMvcEndpoint(MetricsEndpoint delegate) { return new MetricsMvcEndpoint(delegate); } @Bean @ConditionalOnBean(ShutdownEndpoint.class) - @ConditionalOnProperty(prefix = "endpoints.shutdown", name = "enabled", matchIfMissing = true) + @ConditionalOnExpression("${endpoints.shutdown.enabled:false}") public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) { return new ShutdownMvcEndpoint(delegate); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfiguration.java index da6a6c7cedc..3cfe63c42f4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 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. @@ -25,8 +25,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -39,8 +39,8 @@ import org.springframework.context.annotation.Configuration; * *

* This configuration will get automatically enabled as soon as the Jolokia - * {@link AgentServlet} is on the classpath. To disable set - * endpoints.jolokia.enabled: false. + * {@link AgentServlet} is on the classpath. To disable it set + * endpoints.jolokia.enabled: false or endpoints.enabled: false. * *

* Additional configuration parameters for Jolokia can be provided by specifying @@ -50,11 +50,12 @@ import org.springframework.context.annotation.Configuration; * * @author Christian Dupuis * @author Dave Syer + * @author Andy Wilkinson */ @Configuration @ConditionalOnWebApplication @ConditionalOnClass({ AgentServlet.class }) -@ConditionalOnProperty(prefix = "endpoints.jolokia", name = "enabled", matchIfMissing = true) +@ConditionalOnExpression("${endpoints.jolokia.enabled:${endpoints.enabled:true}}") @AutoConfigureBefore(ManagementSecurityAutoConfiguration.class) @AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class) @EnableConfigurationProperties(JolokiaProperties.class) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointMvcAdapter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointMvcAdapter.java index dc70c2d0974..e6159326a20 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointMvcAdapter.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointMvcAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -31,9 +31,14 @@ import org.springframework.web.bind.annotation.ResponseBody; * Adapter class to expose {@link Endpoint}s as {@link MvcEndpoint}s. * * @author Dave Syer + * @author Andy Wilkinson */ public class EndpointMvcAdapter implements MvcEndpoint { + private final ResponseEntity> disabledResponse = new ResponseEntity>( + Collections.singletonMap("message", "This endpoint is disabled"), + HttpStatus.NOT_FOUND); + private final Endpoint delegate; /** @@ -49,9 +54,9 @@ public class EndpointMvcAdapter implements MvcEndpoint { @ResponseBody public Object invoke() { if (!this.delegate.isEnabled()) { - // Shouldn't happen - return new ResponseEntity>(Collections.singletonMap( - "message", "This endpoint is disabled"), HttpStatus.NOT_FOUND); + // Shouldn't happen - MVC endpoint shouldn't be registered when delegate's + // disabled + return this.disabledResponse; } return this.delegate.invoke(); } @@ -76,4 +81,15 @@ public class EndpointMvcAdapter implements MvcEndpoint { return this.delegate.getClass(); } + /** + * Returns the response that should be returned when the endpoint is disabled. + * + * @see Endpoint#isEnabled() + * @since 1.2.4 + * @return The response to be returned when the endpoint is disabled + */ + protected ResponseEntity getDisabledResponse() { + return this.disabledResponse; + } + } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java index 28e34f0803c..3915131dedb 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; * * @author Dave Syer * @author Christian Dupuis + * @author Andy Wilkinson */ public class EnvironmentMvcEndpoint extends EndpointMvcAdapter implements EnvironmentAware { @@ -44,6 +45,11 @@ public class EnvironmentMvcEndpoint extends EndpointMvcAdapter implements @RequestMapping(value = "/{name:.*}", method = RequestMethod.GET) @ResponseBody public Object value(@PathVariable String name) { + if (!getDelegate().isEnabled()) { + // Shouldn't happen - MVC endpoint shouldn't be registered when delegate's + // disabled + return getDisabledResponse(); + } String result = this.environment.getProperty(name); if (result == null) { throw new NoSuchPropertyException("No such property: " + name); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java index eb9b951daa1..3aeb7596469 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -28,6 +28,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; * Adapter to expose {@link MetricsEndpoint} as an {@link MvcEndpoint}. * * @author Dave Syer + * @author Andy Wilkinson */ public class MetricsMvcEndpoint extends EndpointMvcAdapter { @@ -41,6 +42,11 @@ public class MetricsMvcEndpoint extends EndpointMvcAdapter { @RequestMapping(value = "/{name:.*}", method = RequestMethod.GET) @ResponseBody public Object value(@PathVariable String name) { + if (!this.delegate.isEnabled()) { + // Shouldn't happen - MVC endpoint shouldn't be registered when delegate's + // disabled + return getDisabledResponse(); + } Object value = this.delegate.invoke().get(name); if (value == null) { throw new NoSuchMetricException("No such metric: " + name); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java index fdc950ef8d0..73dab07bab3 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -31,7 +31,11 @@ import org.junit.Test; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer; +import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint; import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; @@ -67,6 +71,7 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertEquals; @@ -79,6 +84,7 @@ import static org.junit.Assert.assertTrue; * * @author Phillip Webb * @author Greg Turnquist + * @author Andy Wilkinson */ public class EndpointWebMvcAutoConfigurationTests { @@ -100,8 +106,9 @@ public class EndpointWebMvcAutoConfigurationTests { @Test public void onSamePort() throws Exception { - this.applicationContext.register(RootConfig.class, BaseConfiguration.class, - ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); + this.applicationContext.register(RootConfig.class, EndpointConfig.class, + BaseConfiguration.class, ServerPortConfig.class, + EndpointWebMvcAutoConfiguration.class); this.applicationContext.refresh(); assertContent("/controller", ports.get().server, "controlleroutput"); assertContent("/endpoint", ports.get().server, "endpointoutput"); @@ -116,8 +123,9 @@ public class EndpointWebMvcAutoConfigurationTests { public void onSamePortWithoutHeader() throws Exception { EnvironmentTestUtils.addEnvironment(this.applicationContext, "management.add-application-context-header:false"); - this.applicationContext.register(RootConfig.class, BaseConfiguration.class, - ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); + this.applicationContext.register(RootConfig.class, EndpointConfig.class, + BaseConfiguration.class, ServerPortConfig.class, + EndpointWebMvcAutoConfiguration.class); this.applicationContext.refresh(); assertFalse(hasHeader("/endpoint", ports.get().server, "X-Application-Context")); this.applicationContext.close(); @@ -126,9 +134,9 @@ public class EndpointWebMvcAutoConfigurationTests { @Test public void onDifferentPort() throws Exception { - this.applicationContext.register(RootConfig.class, DifferentPortConfig.class, - BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class, - ErrorMvcAutoConfiguration.class); + this.applicationContext.register(RootConfig.class, EndpointConfig.class, + DifferentPortConfig.class, BaseConfiguration.class, + EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class); this.applicationContext.refresh(); assertContent("/controller", ports.get().server, "controlleroutput"); assertContent("/endpoint", ports.get().server, null); @@ -144,9 +152,9 @@ public class EndpointWebMvcAutoConfigurationTests { @Test public void onRandomPort() throws Exception { - this.applicationContext.register(RootConfig.class, RandomPortConfig.class, - BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class, - ErrorMvcAutoConfiguration.class); + this.applicationContext.register(RootConfig.class, EndpointConfig.class, + RandomPortConfig.class, BaseConfiguration.class, + EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class); GrabManagementPort grabManagementPort = new GrabManagementPort( this.applicationContext); this.applicationContext.addApplicationListener(grabManagementPort); @@ -161,8 +169,9 @@ public class EndpointWebMvcAutoConfigurationTests { @Test public void disabled() throws Exception { - this.applicationContext.register(RootConfig.class, DisableConfig.class, - BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class); + this.applicationContext.register(RootConfig.class, EndpointConfig.class, + DisableConfig.class, BaseConfiguration.class, + EndpointWebMvcAutoConfiguration.class); this.applicationContext.refresh(); assertContent("/controller", ports.get().server, "controlleroutput"); assertContent("/endpoint", ports.get().server, null); @@ -176,8 +185,9 @@ public class EndpointWebMvcAutoConfigurationTests { public void specificPortsViaProperties() throws Exception { EnvironmentTestUtils.addEnvironment(this.applicationContext, "server.port:" + ports.get().server, "management.port:" + ports.get().management); - this.applicationContext.register(RootConfig.class, BaseConfiguration.class, - EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class); + this.applicationContext.register(RootConfig.class, EndpointConfig.class, + BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class, + ErrorMvcAutoConfiguration.class); this.applicationContext.refresh(); assertContent("/controller", ports.get().server, "controlleroutput"); assertContent("/endpoint", ports.get().server, null); @@ -191,8 +201,8 @@ public class EndpointWebMvcAutoConfigurationTests { public void contextPath() throws Exception { EnvironmentTestUtils.addEnvironment(this.applicationContext, "management.contextPath:/test"); - this.applicationContext.register(RootConfig.class, ServerPortConfig.class, - PropertyPlaceholderAutoConfiguration.class, + this.applicationContext.register(RootConfig.class, EndpointConfig.class, + ServerPortConfig.class, PropertyPlaceholderAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class, ServerPropertiesAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class, @@ -255,6 +265,88 @@ public class EndpointWebMvcAutoConfigurationTests { assertThat(mapping, not(instanceOf(EndpointHandlerMapping.class))); } + @Test + public void endpointsDefaultConfiguration() throws Exception { + this.applicationContext.register(RootConfig.class, BaseConfiguration.class, + ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); + this.applicationContext.refresh(); + // /health, /metrics, /env (/shutdown is disabled by default) + assertThat(this.applicationContext.getBeansOfType(MvcEndpoint.class).size(), + is(equalTo(3))); + } + + @Test + public void endpointsAllDisabled() throws Exception { + this.applicationContext.register(RootConfig.class, BaseConfiguration.class, + ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(this.applicationContext, + "endpoints.enabled:false"); + this.applicationContext.refresh(); + assertThat(this.applicationContext.getBeansOfType(MvcEndpoint.class).size(), + is(equalTo(0))); + } + + @Test + public void environmentEndpointDisabled() throws Exception { + endpointDisabled("env", EnvironmentMvcEndpoint.class); + } + + @Test + public void environmentEndpointEnabledOverride() throws Exception { + endpointEnabledOverride("env", EnvironmentMvcEndpoint.class); + } + + @Test + public void metricsEndpointDisabled() throws Exception { + endpointDisabled("metrics", MetricsMvcEndpoint.class); + } + + @Test + public void metricsEndpointEnabledOverride() throws Exception { + endpointEnabledOverride("metrics", MetricsMvcEndpoint.class); + } + + @Test + public void healthEndpointDisabled() throws Exception { + endpointDisabled("health", HealthMvcEndpoint.class); + } + + @Test + public void healthEndpointEnabledOverride() throws Exception { + endpointEnabledOverride("health", HealthMvcEndpoint.class); + } + + @Test + public void shutdownEndpointEnabled() { + this.applicationContext.register(RootConfig.class, BaseConfiguration.class, + ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(this.applicationContext, + "endpoints.shutdown.enabled:true"); + this.applicationContext.refresh(); + assertThat(this.applicationContext.getBeansOfType(ShutdownMvcEndpoint.class) + .size(), is(equalTo(1))); + } + + private void endpointDisabled(String name, Class type) { + this.applicationContext.register(RootConfig.class, BaseConfiguration.class, + ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(this.applicationContext, + String.format("endpoints.%s.enabled:false", name)); + this.applicationContext.refresh(); + assertThat(this.applicationContext.getBeansOfType(type).size(), is(equalTo(0))); + } + + private void endpointEnabledOverride(String name, Class type) + throws Exception { + this.applicationContext.register(RootConfig.class, BaseConfiguration.class, + ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(this.applicationContext, + "endpoints.enabled:false", + String.format("endpoints.%s.enabled:true", name)); + this.applicationContext.refresh(); + assertThat(this.applicationContext.getBeansOfType(type).size(), is(equalTo(1))); + } + private void assertAllClosed() throws Exception { assertContent("/controller", ports.get().server, null); assertContent("/endpoint", ports.get().server, null); @@ -307,6 +399,7 @@ public class EndpointWebMvcAutoConfigurationTests { @Configuration @Import({ PropertyPlaceholderAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class, + EndpointAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class, @@ -323,6 +416,11 @@ public class EndpointWebMvcAutoConfigurationTests { return new TestController(); } + } + + @Configuration + public static class EndpointConfig { + @Bean public TestEndpoint testEndpoint() { return new TestEndpoint(); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java index 5ac1d76aad8..dae25a2d46b 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 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. @@ -37,6 +37,7 @@ import static org.junit.Assert.assertEquals; * Tests for {@link JolokiaAutoConfiguration}. * * @author Christian Dupuis + * @author Andy Wilkinson */ public class JolokiaAutoConfigurationTests { @@ -67,10 +68,23 @@ public class JolokiaAutoConfigurationTests { } @Test - public void agentDisabled() throws Exception { + public void endpointDisabled() throws Exception { + assertEndpointDisabled("endpoints.jolokia.enabled:false"); + } + + @Test + public void allEndpointsDisabled() throws Exception { + assertEndpointDisabled("endpoints.enabled:false"); + } + + @Test + public void endpointEnabledAsOverride() throws Exception { + assertEndpointEnabled("endpoints.enabled:false", "endpoints.jolokia.enabled:true"); + } + + private void assertEndpointDisabled(String... pairs) { this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "endpoints.jolokia.enabled:false"); + EnvironmentTestUtils.addEnvironment(this.context, pairs); this.context.register(Config.class, WebMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class, @@ -80,6 +94,18 @@ public class JolokiaAutoConfigurationTests { assertEquals(0, this.context.getBeanNamesForType(JolokiaMvcEndpoint.class).length); } + private void assertEndpointEnabled(String... pairs) { + this.context = new AnnotationConfigEmbeddedWebApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, pairs); + this.context.register(Config.class, WebMvcAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + ManagementServerPropertiesAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + JolokiaAutoConfiguration.class); + this.context.refresh(); + assertEquals(1, this.context.getBeanNamesForType(JolokiaMvcEndpoint.class).length); + } + @Configuration @EnableConfigurationProperties protected static class Config { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpointTests.java index 7ef5a5defb5..fa1f71dd163 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpointTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -44,7 +44,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** + * Tests for {@link EnvironmentMvcEndpoint} + * * @author Dave Syer + * @author Andy Wilkinson */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = { TestConfiguration.class }) @@ -58,6 +61,7 @@ public class EnvironmentMvcEndpointTests { @Before public void setUp() { + this.context.getBean(EnvironmentEndpoint.class).setEnabled(true); this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); EnvironmentTestUtils.addEnvironment( (ConfigurableApplicationContext) this.context, "foo:bar"); @@ -75,6 +79,12 @@ public class EnvironmentMvcEndpointTests { .andExpect(content().string(equalToIgnoringCase("bar"))); } + @Test + public void subWhenDisabled() throws Exception { + this.context.getBean(EnvironmentEndpoint.class).setEnabled(false); + this.mvc.perform(get("/env/foo")).andExpect(status().isNotFound()); + } + @Import({ EndpointWebMvcAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class }) @EnableWebMvc diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointContextPathTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointContextPathTests.java similarity index 91% rename from spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointContextPathTests.java rename to spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointContextPathTests.java index 00fcedaf26c..f50fb4f05c1 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointContextPathTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointContextPathTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 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. @@ -23,8 +23,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; -import org.springframework.boot.actuate.endpoint.mvc.JolokiaEndpointContextPathTests.Config; -import org.springframework.boot.actuate.endpoint.mvc.JolokiaEndpointContextPathTests.ContextPathListener; +import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpointContextPathTests.Config; +import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpointContextPathTests.ContextPathListener; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.SpringApplicationConfiguration; @@ -51,7 +51,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = { Config.class }, initializers = ContextPathListener.class) @WebAppConfiguration -public class JolokiaEndpointContextPathTests { +public class JolokiaMvcEndpointContextPathTests { @Autowired private MvcEndpoints endpoints; diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointTests.java similarity index 94% rename from spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointTests.java rename to spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointTests.java index 952523073e0..9b02bb663c1 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 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. @@ -25,7 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; -import org.springframework.boot.actuate.endpoint.mvc.JolokiaEndpointTests.Config; +import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpointTests.Config; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.SpringApplicationConfiguration; @@ -47,13 +47,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** + * Tests for {@link JolokiaMvcEndpoint} + * * @author Christian Dupuis * @author Dave Syer */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = { Config.class }) @WebAppConfiguration -public class JolokiaEndpointTests { +public class JolokiaMvcEndpointTests { @Autowired private MvcEndpoints endpoints; @@ -103,5 +105,7 @@ public class JolokiaEndpointTests { @Import({ EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class }) public static class Config { + } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpointTests.java new file mode 100644 index 00000000000..fc50083c290 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpointTests.java @@ -0,0 +1,124 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.endpoint.mvc; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; +import org.springframework.boot.actuate.endpoint.MetricsEndpoint; +import org.springframework.boot.actuate.endpoint.PublicMetrics; +import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpointTests.TestConfiguration; +import org.springframework.boot.actuate.metrics.Metric; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Tests for {@link MetricsMvcEndpoint} + * + * @author Andy Wilkinson + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = { TestConfiguration.class }) +@WebAppConfiguration +public class MetricsMvcEndpointTests { + + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @Before + public void setUp() { + this.context.getBean(MetricsEndpoint.class).setEnabled(true); + this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + } + + @Test + public void home() throws Exception { + this.mvc.perform(get("/metrics")).andExpect(status().isOk()) + .andExpect(content().string(containsString("\"foo\":1"))); + } + + @Test + public void homeWhenDisabled() throws Exception { + this.context.getBean(MetricsEndpoint.class).setEnabled(false); + this.mvc.perform(get("/metrics")).andExpect(status().isNotFound()); + } + + @Test + public void specificMetric() throws Exception { + this.mvc.perform(get("/metrics/foo")).andExpect(status().isOk()) + .andExpect(content().string(equalTo("1"))); + } + + @Test + public void specificMetricWhenDisabled() throws Exception { + this.context.getBean(MetricsEndpoint.class).setEnabled(false); + this.mvc.perform(get("/metrics/foo")).andExpect(status().isNotFound()); + } + + @Test + public void specificMetricThatDoesNotExist() throws Exception { + this.mvc.perform(get("/metrics/bar")).andExpect(status().isNotFound()); + } + + @Import({ EndpointWebMvcAutoConfiguration.class, + ManagementServerPropertiesAutoConfiguration.class }) + @EnableWebMvc + @Configuration + public static class TestConfiguration { + + @Bean + public MetricsEndpoint endpoint() { + return new MetricsEndpoint(new PublicMetrics() { + + @Override + public Collection> metrics() { + return Arrays.> asList(new Metric("foo", 1)); + } + + }); + } + + @Bean + public MetricsMvcEndpoint mvcEndpoint() { + return new MetricsMvcEndpoint(endpoint()); + } + + } + +}