From 155cfb1805e4ca74baf199ed6387106ca657914b Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 19 Sep 2016 12:40:38 +0100 Subject: [PATCH] Fix boot curies href when server has custom servlet path Previously, the servlet path was being applied twice. Once by the code that sets up the DefaultCurieProvider and once by the provider itself which uses ServletUriComponentBuilder's fromCurrentServletMapping() to build the application URI. This commit removes the duplicate logic when creating the DefaultCurieProvider. Closes gh-6585 --- .../EndpointWebMvcAutoConfiguration.java | 1 + ...ermediaManagementContextConfiguration.java | 11 -- .../BootCuriesHrefIntegrationTests.java | 149 ++++++++++++++++++ 3 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/BootCuriesHrefIntegrationTests.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 7580a0bdc38..9ac5aba91e5 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 @@ -182,6 +182,7 @@ public class EndpointWebMvcAutoConfiguration childContext.setParent(this.applicationContext); childContext.setNamespace("management"); childContext.setId(this.applicationContext.getId() + ":management"); + childContext.setClassLoader(this.applicationContext.getClassLoader()); childContext.register(EndpointWebMvcChildContextConfiguration.class, PropertyPlaceholderAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class, diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java index 12a0457404d..28ddfafa0ba 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java @@ -126,20 +126,9 @@ public class EndpointWebMvcHypermediaManagementContextConfiguration { ManagementServerProperties management, DocsMvcEndpoint endpoint) { String path = management.getContextPath() + endpoint.getPath() + "/#spring_boot_actuator__{rel}"; - if (serverAndManagementPortsAreTheSame(server, management)) { - path = server.getPath(path); - } return new DefaultCurieProvider("boot", new UriTemplate(path)); } - private boolean serverAndManagementPortsAreTheSame(ServerProperties server, - ManagementServerProperties management) { - if (server.getPort() == null) { - return management.getPort() == null; - } - return server.getPort().equals(management.getPort()) && management.getPort() != 0; - } - @Configuration static class DocsMvcEndpointConfiguration { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/BootCuriesHrefIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/BootCuriesHrefIntegrationTests.java new file mode 100644 index 00000000000..d8a7924c4fb --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/BootCuriesHrefIntegrationTests.java @@ -0,0 +1,149 @@ +/* + * 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. + * 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.autoconfigure; + +import java.net.URL; + +import com.jayway.jsonpath.JsonPath; +import net.minidev.json.JSONArray; +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; +import org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.ResponseEntity; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for the href of the actuator's curies link + * + * @author Andy Wilkinson + */ +public class BootCuriesHrefIntegrationTests { + + private AnnotationConfigEmbeddedWebApplicationContext context; + + @After + public void closeContext() { + this.context.close(); + } + + @Test + public void basicCuriesHref() { + int port = load("endpoints.docs.curies.enabled:true", "server.port:0"); + assertThat(getCurieHref("http://localhost:" + port + "/actuator")).isEqualTo( + "http://localhost:" + port + "/docs/#spring_boot_actuator__{rel}"); + } + + @Test + public void curiesHrefWithCustomContextPath() { + int port = load("endpoints.docs.curies.enabled:true", "server.port:0", + "server.context-path:/context"); + assertThat(getCurieHref("http://localhost:" + port + "/context/actuator")) + .isEqualTo("http://localhost:" + port + + "/context/docs/#spring_boot_actuator__{rel}"); + } + + @Test + public void curiesHrefWithCustomServletPath() { + int port = load("endpoints.docs.curies.enabled:true", "server.port:0", + "server.servlet-path:/servlet"); + assertThat(getCurieHref("http://localhost:" + port + "/servlet/actuator")) + .isEqualTo("http://localhost:" + port + + "/servlet/docs/#spring_boot_actuator__{rel}"); + } + + @Test + public void curiesHrefWithCustomServletAndContextPaths() { + int port = load("endpoints.docs.curies.enabled:true", "server.port:0", + "server.context-path:/context", "server.servlet-path:/servlet"); + assertThat(getCurieHref("http://localhost:" + port + "/context/servlet/actuator")) + .isEqualTo("http://localhost:" + port + + "/context/servlet/docs/#spring_boot_actuator__{rel}"); + } + + @Test + public void curiesHrefWithCustomServletContextAndManagementContextPaths() { + int port = load("endpoints.docs.curies.enabled:true", "server.port:0", + "server.context-path:/context", "server.servlet-path:/servlet", + "management.context-path:/management"); + assertThat(getCurieHref("http://localhost:" + port + + "/context/servlet/management/")).isEqualTo("http://localhost:" + port + + "/context/servlet/management/docs/#spring_boot_actuator__{rel}"); + } + + @Test + public void serverPathsAreIgnoredWithSeparateManagementPort() { + int port = load("endpoints.docs.curies.enabled:true", "server.port:0", + "server.context-path:/context", "server.servlet-path:/servlet", + "management.port:0"); + assertThat(getCurieHref("http://localhost:" + port + "/actuator/")).isEqualTo( + "http://localhost:" + port + "/docs/#spring_boot_actuator__{rel}"); + } + + @Test + public void managementContextPathWithSeparateManagementPort() { + int port = load("endpoints.docs.curies.enabled:true", + "management.context-path:/management", "server.port:0", + "management.port:0"); + assertThat(getCurieHref("http://localhost:" + port + "/management/")) + .isEqualTo("http://localhost:" + port + + "/management/docs/#spring_boot_actuator__{rel}"); + } + + private int load(String... properties) { + this.context = new AnnotationConfigEmbeddedWebApplicationContext(); + this.context.setClassLoader(new ClassLoader(getClass().getClassLoader()) { + + @Override + public URL getResource(String name) { + if ("META-INF/resources/spring-boot-actuator/docs/index.html" + .equals(name)) { + return super.getResource("actuator-docs-index.html"); + } + return super.getResource(name); + } + + }); + EnvironmentTestUtils.addEnvironment(this.context, properties); + this.context.register(TestConfiguration.class); + new ServerPortInfoApplicationContextInitializer().initialize(this.context); + this.context.refresh(); + return Integer.parseInt( + this.context.getEnvironment().getProperty("local.management.port")); + } + + private String getCurieHref(String uri) { + ResponseEntity response = new TestRestTemplate().getForEntity(uri, + String.class); + JSONArray bootCuriesHrefs = JsonPath.parse(response.getBody()) + .read("_links.curies[?(@.name == 'boot')].href"); + assertThat(bootCuriesHrefs).hasSize(1); + return (String) bootCuriesHrefs.get(0); + } + + @Configuration + @MinimalActuatorHypermediaApplication + static class TestConfiguration { + + } + +}