Provide links to all types of endpoints

Previously, links were only provide to web endpoints. This commit
expands link resolution to also provide links for servlet endpoints,
controller endpoints, and rest controller endpoints.

Closes gh-11902
This commit is contained in:
Andy Wilkinson
2018-02-08 20:43:24 +00:00
parent 772d4cc739
commit 2993dccd1e
24 changed files with 480 additions and 72 deletions

View File

@@ -25,6 +25,7 @@ import org.assertj.core.api.Condition;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@@ -37,12 +38,10 @@ import static org.mockito.Mockito.mock;
*/
public class EndpointLinksResolverTests {
private final EndpointLinksResolver linksResolver = new EndpointLinksResolver();
@Test
public void linkResolutionWithTrailingSlashStripsSlashOnSelfLink() {
Map<String, Link> links = this.linksResolver.resolveLinks(Collections.emptyList(),
"https://api.example.com/actuator/");
Map<String, Link> links = new EndpointLinksResolver(Collections.emptyList())
.resolveLinks("https://api.example.com/actuator/");
assertThat(links).hasSize(1);
assertThat(links).hasEntrySatisfying("self",
linkWithHref("https://api.example.com/actuator"));
@@ -50,15 +49,15 @@ public class EndpointLinksResolverTests {
@Test
public void linkResolutionWithoutTrailingSlash() {
Map<String, Link> links = this.linksResolver.resolveLinks(Collections.emptyList(),
"https://api.example.com/actuator");
Map<String, Link> links = new EndpointLinksResolver(Collections.emptyList())
.resolveLinks("https://api.example.com/actuator");
assertThat(links).hasSize(1);
assertThat(links).hasEntrySatisfying("self",
linkWithHref("https://api.example.com/actuator"));
}
@Test
public void resolvedLinksContainsALinkForEachEndpointOperation() {
public void resolvedLinksContainsALinkForEachWebEndpointOperation() {
List<WebOperation> operations = new ArrayList<>();
operations.add(operationWithPath("/alpha", "alpha"));
operations.add(operationWithPath("/alpha/{name}", "alpha-name"));
@@ -67,8 +66,8 @@ public class EndpointLinksResolverTests {
given(endpoint.isEnableByDefault()).willReturn(true);
given(endpoint.getOperations()).willReturn(operations);
String requestUrl = "https://api.example.com/actuator";
Map<String, Link> links = this.linksResolver
.resolveLinks(Collections.singletonList(endpoint), requestUrl);
Map<String, Link> links = new EndpointLinksResolver(
Collections.singletonList(endpoint)).resolveLinks(requestUrl);
assertThat(links).hasSize(3);
assertThat(links).hasEntrySatisfying("self",
linkWithHref("https://api.example.com/actuator"));
@@ -78,6 +77,39 @@ public class EndpointLinksResolverTests {
linkWithHref("https://api.example.com/actuator/alpha/{name}"));
}
@Test
public void resolvedLinksContainsALinkForServletEndpoint() {
ExposableServletEndpoint servletEndpoint = mock(ExposableServletEndpoint.class);
given(servletEndpoint.getId()).willReturn("alpha");
given(servletEndpoint.isEnableByDefault()).willReturn(true);
given(servletEndpoint.getRootPath()).willReturn("alpha");
String requestUrl = "https://api.example.com/actuator";
Map<String, Link> links = new EndpointLinksResolver(
Collections.singletonList(servletEndpoint)).resolveLinks(requestUrl);
assertThat(links).hasSize(2);
assertThat(links).hasEntrySatisfying("self",
linkWithHref("https://api.example.com/actuator"));
assertThat(links).hasEntrySatisfying("alpha",
linkWithHref("https://api.example.com/actuator/alpha"));
}
@Test
public void resolvedLinksContainsALinkForControllerEndpoint() {
ExposableControllerEndpoint controllerEndpoint = mock(
ExposableControllerEndpoint.class);
given(controllerEndpoint.getId()).willReturn("alpha");
given(controllerEndpoint.isEnableByDefault()).willReturn(true);
given(controllerEndpoint.getRootPath()).willReturn("alpha");
String requestUrl = "https://api.example.com/actuator";
Map<String, Link> links = new EndpointLinksResolver(
Collections.singletonList(controllerEndpoint)).resolveLinks(requestUrl);
assertThat(links).hasSize(2);
assertThat(links).hasEntrySatisfying("self",
linkWithHref("https://api.example.com/actuator"));
assertThat(links).hasEntrySatisfying("alpha",
linkWithHref("https://api.example.com/actuator/alpha"));
}
private WebOperation operationWithPath(String path, String id) {
WebOperationRequestPredicate predicate = new WebOperationRequestPredicate(path,
WebEndpointHttpMethod.GET, Collections.emptyList(),

View File

@@ -35,6 +35,7 @@ import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.servlet.ServletContainer;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;
@@ -110,7 +111,8 @@ public class JerseyWebEndpointIntegrationTests extends
Collection<Resource> resources = new JerseyEndpointResourceFactory()
.createEndpointResources(
new EndpointMapping(environment.getProperty("endpointPath")),
endpointDiscoverer.getEndpoints(), endpointMediaTypes);
endpointDiscoverer.getEndpoints(), endpointMediaTypes,
new EndpointLinksResolver(endpointDiscoverer.getEndpoints()));
resourceConfig.registerResources(new HashSet<>(resources));
resourceConfig.register(JacksonFeature.class);
resourceConfig.register(new ObjectMapperContextResolver(new ObjectMapper()),

View File

@@ -22,6 +22,7 @@ import java.util.Arrays;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;
@@ -132,7 +133,8 @@ public class WebFluxEndpointIntegrationTests
return new WebFluxEndpointHandlerMapping(
new EndpointMapping(environment.getProperty("endpointPath")),
endpointDiscoverer.getEndpoints(), endpointMediaTypes,
corsConfiguration);
corsConfiguration,
new EndpointLinksResolver(endpointDiscoverer.getEndpoints()));
}
@Bean

View File

@@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;
@@ -129,7 +130,8 @@ public class MvcWebEndpointIntegrationTests extends
return new WebMvcEndpointHandlerMapping(
new EndpointMapping(environment.getProperty("endpointPath")),
endpointDiscoverer.getEndpoints(), endpointMediaTypes,
corsConfiguration);
corsConfiguration,
new EndpointLinksResolver(endpointDiscoverer.getEndpoints()));
}
}

View File

@@ -31,6 +31,7 @@ import org.junit.runners.model.InitializationError;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.PathMapper;
@@ -104,7 +105,8 @@ class JerseyEndpointsRunner extends AbstractWebEndpointRunner {
Collections.emptyList(), Collections.emptyList());
Collection<Resource> resources = new JerseyEndpointResourceFactory()
.createEndpointResources(new EndpointMapping("/actuator"),
discoverer.getEndpoints(), endpointMediaTypes);
discoverer.getEndpoints(), endpointMediaTypes,
new EndpointLinksResolver(discoverer.getEndpoints()));
config.registerResources(new HashSet<>(resources));
}

View File

@@ -25,6 +25,7 @@ import org.junit.runners.model.InitializationError;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.PathMapper;
@@ -110,7 +111,8 @@ class WebFluxEndpointsRunner extends AbstractWebEndpointRunner {
Collections.emptyList(), Collections.emptyList());
return new WebFluxEndpointHandlerMapping(new EndpointMapping("/actuator"),
discoverer.getEndpoints(), endpointMediaTypes,
new CorsConfiguration());
new CorsConfiguration(),
new EndpointLinksResolver(discoverer.getEndpoints()));
}
}

View File

@@ -25,6 +25,7 @@ import org.junit.runners.model.InitializationError;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.PathMapper;
@@ -93,7 +94,8 @@ class WebMvcEndpointRunner extends AbstractWebEndpointRunner {
Collections.emptyList(), Collections.emptyList());
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/actuator"),
discoverer.getEndpoints(), endpointMediaTypes,
new CorsConfiguration());
new CorsConfiguration(),
new EndpointLinksResolver(discoverer.getEndpoints()));
}
}