From 4ec95b8308cd301d74e160a7c1a6109c6ee9b64c Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 13 Dec 2016 09:42:14 +0000 Subject: [PATCH] Ensure that JolokiaMvcEndpoint destroys underlying controller Closes gh-7606 --- .../endpoint/mvc/JolokiaMvcEndpoint.java | 11 +- .../JolokiaMvcEndpointIntegrationTests.java | 111 ++++++++++++++++++ .../endpoint/mvc/JolokiaMvcEndpointTests.java | 97 ++++----------- 3 files changed, 142 insertions(+), 77 deletions(-) create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointIntegrationTests.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java index 0ab3dd7b59b..1f63a06985b 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java @@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletResponse; import org.jolokia.http.AgentServlet; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; @@ -44,8 +45,9 @@ import org.springframework.web.util.UrlPathHelper; */ @ConfigurationProperties(prefix = "endpoints.jolokia", ignoreUnknownFields = false) @HypermediaDisabled -public class JolokiaMvcEndpoint extends AbstractMvcEndpoint - implements InitializingBean, ApplicationContextAware, ServletContextAware { +public class JolokiaMvcEndpoint extends AbstractMvcEndpoint implements InitializingBean, + ApplicationContextAware, ServletContextAware, DisposableBean { + private final ServletWrappingController controller = new ServletWrappingController(); public JolokiaMvcEndpoint() { @@ -74,6 +76,11 @@ public class JolokiaMvcEndpoint extends AbstractMvcEndpoint this.controller.setApplicationContext(context); } + @Override + public void destroy() { + this.controller.destroy(); + } + @RequestMapping("/**") public ModelAndView handle(HttpServletRequest request, HttpServletResponse response) throws Exception { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointIntegrationTests.java new file mode 100644 index 00000000000..bbbb5d20e4b --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointIntegrationTests.java @@ -0,0 +1,111 @@ +/* + * Copyright 2013-2016 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.Set; + +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.JolokiaAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringRunner; +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.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.containsString; +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; + +/** + * Integration tests for {@link JolokiaMvcEndpoint} + * + * @author Christian Dupuis + * @author Dave Syer + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class JolokiaMvcEndpointIntegrationTests { + + @Autowired + private MvcEndpoints endpoints; + + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @Before + public void setUp() { + this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + EnvironmentTestUtils.addEnvironment((ConfigurableApplicationContext) this.context, + "foo:bar"); + } + + @Test + public void endpointRegistered() throws Exception { + Set values = this.endpoints.getEndpoints(); + assertThat(values).hasAtLeastOneElementOfType(JolokiaMvcEndpoint.class); + } + + @Test + public void search() throws Exception { + this.mvc.perform(get("/jolokia/search/java.lang:*")).andExpect(status().isOk()) + .andExpect(content().string(containsString("GarbageCollector"))); + } + + @Test + public void read() throws Exception { + this.mvc.perform(get("/jolokia/read/java.lang:type=Memory")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("NonHeapMemoryUsage"))); + } + + @Test + public void list() throws Exception { + this.mvc.perform(get("/jolokia/list/java.lang/type=Memory/attr")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("NonHeapMemoryUsage"))); + } + + @Configuration + @EnableConfigurationProperties + @EnableWebMvc + @Import({ JacksonAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + 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/JolokiaMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointTests.java index 2eed780f5e2..b052fe4a90e 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpointTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2012-2016 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. @@ -16,98 +16,45 @@ package org.springframework.boot.actuate.endpoint.mvc; -import java.util.Set; - 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.JolokiaAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; -import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; -import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.util.EnvironmentTestUtils; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.mock.web.MockServletContext; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.mvc.ServletWrappingController; import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.containsString; -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; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** - * Tests for {@link JolokiaMvcEndpoint} + * Tests for {@link JolokiaMvcEndpoint}. * - * @author Christian Dupuis - * @author Dave Syer + * @author Andy Wilkinson */ -@RunWith(SpringRunner.class) -@DirtiesContext -@SpringBootTest public class JolokiaMvcEndpointTests { - @Autowired - private MvcEndpoints endpoints; + private final JolokiaMvcEndpoint endpoint = new JolokiaMvcEndpoint(); - @Autowired - private WebApplicationContext context; - - private MockMvc mvc; + private final ServletWrappingController controller = (ServletWrappingController) spy( + ReflectionTestUtils.getField(this.endpoint, "controller")); @Before - public void setUp() { - this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); - EnvironmentTestUtils.addEnvironment((ConfigurableApplicationContext) this.context, - "foo:bar"); + public void before() { + ReflectionTestUtils.setField(this.endpoint, "controller", this.controller); } @Test - public void endpointRegistered() throws Exception { - Set values = this.endpoints.getEndpoints(); - assertThat(values).hasAtLeastOneElementOfType(JolokiaMvcEndpoint.class); - } - - @Test - public void search() throws Exception { - this.mvc.perform(get("/jolokia/search/java.lang:*")).andExpect(status().isOk()) - .andExpect(content().string(containsString("GarbageCollector"))); - } - - @Test - public void read() throws Exception { - this.mvc.perform(get("/jolokia/read/java.lang:type=Memory")) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("NonHeapMemoryUsage"))); - } - - @Test - public void list() throws Exception { - this.mvc.perform(get("/jolokia/list/java.lang/type=Memory/attr")) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("NonHeapMemoryUsage"))); - } - - @Configuration - @EnableConfigurationProperties - @EnableWebMvc - @Import({ JacksonAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class, - ManagementServerPropertiesAutoConfiguration.class }) - public static class Config { - + public void controllerIsDestroyed() throws Exception { + this.endpoint.setApplicationContext(mock(WebApplicationContext.class)); + this.endpoint.setServletContext(new MockServletContext()); + this.endpoint.afterPropertiesSet(); + this.endpoint.destroy(); + assertThat(this.endpoint).isInstanceOf(DisposableBean.class); + verify(this.controller).destroy(); } }