From 8bebe6dea9f02ace2d8f8357ec7d0a954488a6c4 Mon Sep 17 00:00:00 2001 From: Meang Akira Tanaka Date: Tue, 14 Jul 2015 19:42:34 +0200 Subject: [PATCH 1/3] Info endpoint See gh-3492 --- .../EndpointAutoConfiguration.java | 41 ++----- .../InfoProviderAutoConfiguration.java | 62 ++++++++++ .../boot/actuate/endpoint/InfoEndpoint.java | 50 +++++--- .../actuate/info/EnvironmentInfoProvider.java | 61 ++++++++++ .../boot/actuate/info/Info.java | 84 +++++++++++++ .../boot/actuate/info/InfoProvider.java | 17 +++ .../info/ScmGitPropertiesInfoProvider.java | 105 ++++++++++++++++ .../main/resources/META-INF/spring.factories | 1 + .../EndpointAutoConfigurationTests.java | 4 + .../actuate/endpoint/InfoEndpointTests.java | 43 ++++++- .../endpoint/mvc/InfoMvcEndpointTests.java | 115 ++++++++++++++++++ ...cEndpointWithoutAnyInfoProvidersTests.java | 75 ++++++++++++ .../info/EnvironmentInfoProviderTest.java | 64 ++++++++++ .../ScmGitPropertiesInfoProviderTest.java | 98 +++++++++++++++ .../sample/actuator/ExampleInfoProvider.java | 21 ++++ 15 files changed, 786 insertions(+), 55 deletions(-) create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTest.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTest.java create mode 100644 spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java index 52d5092de21..b37d47136e7 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -47,6 +46,7 @@ import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.OrderedHealthAggregator; +import org.springframework.boot.actuate.info.InfoProvider; import org.springframework.boot.actuate.trace.InMemoryTraceRepository; import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -57,17 +57,16 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; -import org.springframework.boot.autoconfigure.info.GitInfo; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.bind.PropertiesConfigurationFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationAwareOrderComparator; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.StandardEnvironment; import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; +import liquibase.integration.spring.SpringLiquibase; + /** * {@link EnableAutoConfiguration Auto-configuration} for common management * {@link Endpoint}s. @@ -78,24 +77,23 @@ import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; * @author Christian Dupuis * @author Stephane Nicoll * @author Eddú Meléndez + * @author Meang Akira Tanaka + * */ @Configuration @AutoConfigureAfter({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class }) @EnableConfigurationProperties(EndpointProperties.class) public class EndpointAutoConfiguration { - @Autowired - private InfoPropertiesConfiguration properties; - - @Autowired(required = false) - private GitInfo gitInfo; - @Autowired(required = false) private HealthAggregator healthAggregator = new OrderedHealthAggregator(); @Autowired(required = false) private Map healthIndicators = new HashMap(); + @Autowired(required = false) + private Map infoProviders = new HashMap(); + @Autowired(required = false) private Collection publicMetrics; @@ -123,12 +121,7 @@ public class EndpointAutoConfiguration { @Bean @ConditionalOnMissingBean public InfoEndpoint infoEndpoint() throws Exception { - LinkedHashMap info = new LinkedHashMap(); - info.putAll(this.properties.infoMap()); - if (this.gitInfo != null && this.gitInfo.getBranch() != null) { - info.put("git", this.gitInfo); - } - return new InfoEndpoint(info); + return new InfoEndpoint(this.infoProviders); } @Bean @@ -212,20 +205,4 @@ public class EndpointAutoConfiguration { } - @Configuration - protected static class InfoPropertiesConfiguration { - - @Autowired - private final ConfigurableEnvironment environment = new StandardEnvironment(); - - public Map infoMap() throws Exception { - PropertiesConfigurationFactory> factory = new PropertiesConfigurationFactory>( - new LinkedHashMap()); - factory.setTargetName("info"); - factory.setPropertySources(this.environment.getPropertySources()); - return factory.getObject(); - } - - } - } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java new file mode 100644 index 00000000000..aefba43f060 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java @@ -0,0 +1,62 @@ +/* + * 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.autoconfigure; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.info.EnvironmentInfoProvider; +import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.Resource; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for standard {@link InfoProvider}s. + * + * @author Meang Akira Tanaka + * @since 1.3.0 + */ +@Configuration +@AutoConfigureBefore({ EndpointAutoConfiguration.class }) +public class InfoProviderAutoConfiguration { + + @Autowired + private final ConfigurableEnvironment environment = new StandardEnvironment(); + + @Value("${spring.git.properties:classpath:git.properties}") + private Resource gitProperties; + + @Bean + @ConditionalOnMissingBean(name = "environmentInfoProvider") + public InfoProvider environmentInfoProvider() throws Exception { + return new EnvironmentInfoProvider(environment); + } + + @Bean + @ConditionalOnMissingBean(name = "scmInfoProvider") + public InfoProvider scmInfoProvider() throws Exception { + return new ScmGitPropertiesInfoProvider(gitProperties); + } + + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java index af8396901ca..9632b23ae14 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java @@ -16,43 +16,57 @@ package org.springframework.boot.actuate.endpoint; -import java.util.Collections; -import java.util.LinkedHashMap; import java.util.Map; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoProvider; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; /** * {@link Endpoint} to expose arbitrary application information. + * + * The information, which the {@link InfoEndpoint} can provide can be customized to display any informations, + * however initially the info endpoint will provide git version information (if available) and environment information, + * whose entries are prefixed with info. + * + * In order to add additional information to the endpoint, one has to implement a class, which implements the {@link org.springframework.boot.actuate.info.InfoProvider} + * interface and register it in the application context. The InfoEndpoint will automatically pick it up, when it is being instantiated. + * + * The standard InfoProvider for GIT is registered as the scmInfoProvider, and the registration can be changed + * in case standard provider does not meet ones requirements. + * + * @see org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider + * @see org.springframework.boot.actuate.info.EnvironmentInfoProvider * * @author Dave Syer + * @author Meang Akira Tanaka */ -@ConfigurationProperties(prefix = "endpoints.info") -public class InfoEndpoint extends AbstractEndpoint> { +@ConfigurationProperties(prefix = "endpoints.info", ignoreUnknownFields = false) +public class InfoEndpoint extends AbstractEndpoint { - private final Map info; + private final Map infoProviders; /** * Create a new {@link InfoEndpoint} instance. * - * @param info the info to expose + * @param infoProviders the infoProviders to be used */ - public InfoEndpoint(Map info) { + public InfoEndpoint(Map infoProviders) { super("info", false); - Assert.notNull(info, "Info must not be null"); - this.info = info; + Assert.notNull(infoProviders, "Info providers must not be null"); + this.infoProviders = infoProviders; } @Override - public Map invoke() { - Map info = new LinkedHashMap(this.info); - info.putAll(getAdditionalInfo()); - return info; + public Info invoke() { + Info result = new Info(); + for (InfoProvider provider : infoProviders.values()) { + Info info = provider.provide(); + if(info != null) { + result.put(provider.name(), info); + } + } + return result; } - - protected Map getAdditionalInfo() { - return Collections.emptyMap(); - } - } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java new file mode 100644 index 00000000000..573580e7ca3 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java @@ -0,0 +1,61 @@ +/* + * 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.info; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.bind.PropertiesConfigurationFactory; +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * A {@link InfoProvider} that provides all environment entries prefixed with info + * + * See something + * + * @author Meang Akira Tanaka + * @since 1.3.0 + */ +public class EnvironmentInfoProvider implements InfoProvider { + + private final ConfigurableEnvironment environment; + private final Map infoMap; + private final Info info; + + public EnvironmentInfoProvider(ConfigurableEnvironment environment) throws Exception { + this.environment = environment; + infoMap = extractInfoFromEnvironment(); + this.info = new Info(infoMap); + } + + @Override + public String name() { + return "environment"; + } + + @Override + public Info provide() { + return info; + } + + private Map extractInfoFromEnvironment() throws Exception { + PropertiesConfigurationFactory> factory = new PropertiesConfigurationFactory>( + new LinkedHashMap()); + factory.setTargetName("info"); + factory.setPropertySources(this.environment.getPropertySources()); + return factory.getObject(); + } +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java new file mode 100644 index 00000000000..1b339b8766c --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java @@ -0,0 +1,84 @@ +/* + * 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.info; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +/** + * Carries information from a specific info provider + * + * @see org.springframework.boot.actuate.endpoint.InfoEndpoint + * + * @author Meang Akira Tanaka + * @since 1.3.0 + */ +@JsonInclude(Include.NON_EMPTY) +public final class Info { + + private final Map details = new HashMap(); + + public Info() { + } + + public Info(Map details) { + this.details.putAll(details); + } + + /** + * @return the details of the info or an empty map. + */ + @JsonAnyGetter + public Map getDetails() { + return this.details; + } + + public void put(String infoId, Object value) { + this.details.put(infoId, value); + } + + @SuppressWarnings("unchecked") + public T get(String infoId) { + return (T) this.details.get(infoId); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj instanceof Info) { + Info other = (Info) obj; + return this.details.equals(other.details); + } + return false; + } + + @Override + public int hashCode() { + return this.details.hashCode(); + } + + @Override + public String toString() { + return getDetails().toString(); + } +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java new file mode 100644 index 00000000000..ad51181d8c0 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java @@ -0,0 +1,17 @@ +package org.springframework.boot.actuate.info; + +/** + * information provider for the info endpoint + * + * @author Meang Akira Tanaka + */ +public interface InfoProvider { + + String name(); + + /** + * @return a collection of information + */ + Info provide(); + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java new file mode 100644 index 00000000000..7e6984cef04 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java @@ -0,0 +1,105 @@ +package org.springframework.boot.actuate.info; + +import java.util.Properties; + +import org.springframework.boot.bind.PropertiesConfigurationFactory; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PropertiesLoaderUtils; + +/** + * A {@link InfoProvider} that provides git information extracted from the git.properties file generated by the maven plugin + * pl.project13.maven:git-commit-id-plugin. + * + * @author Meang Akira Tanaka + * @since 1.3.0 + */ +public class ScmGitPropertiesInfoProvider implements InfoProvider { + + private final Resource gitPropertiesResource; + private final GitInfo gitInfo; + + public ScmGitPropertiesInfoProvider(Resource gitPropertiesResource) throws Exception { + this.gitPropertiesResource = gitPropertiesResource; + gitInfo = extractGitInfo(); + } + + @Override + public String name() { + return "git"; + } + + @Override + public Info provide() { + if(gitInfo == null) { + return null; + } + + Info result = new Info(); + + result.put("branch", gitInfo.getBranch()); + result.put("commit", gitInfo.getCommit()); + + return result; + } + + + private GitInfo extractGitInfo() throws Exception { + PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory( + new GitInfo()); + factory.setTargetName("git"); + Properties properties = new Properties(); + if (this.gitPropertiesResource.exists()) { + properties = PropertiesLoaderUtils.loadProperties(this.gitPropertiesResource); + } else { + return null; + } + factory.setProperties(properties); + return factory.getObject(); + } + + + public static class GitInfo { + + private String branch; + + private final Commit commit = new Commit(); + + public String getBranch() { + return this.branch; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public Commit getCommit() { + return this.commit; + } + + public static class Commit { + + private String id; + + private String time; + + public String getId() { + return this.id == null ? "" + : (this.id.length() > 7 ? this.id.substring(0, 7) : this.id); + } + + public void setId(String id) { + this.id = id; + } + + public String getTime() { + return this.time; + } + + public void setTime(String time) { + this.time = time; + } + + } + + } +} diff --git a/spring-boot-actuator/src/main/resources/META-INF/spring.factories b/spring-boot-actuator/src/main/resources/META-INF/spring.factories index 3874247eadd..40a1efafd0d 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/spring.factories +++ b/spring-boot-actuator/src/main/resources/META-INF/spring.factories @@ -6,6 +6,7 @@ org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.InfoProviderAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration,\ diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java index 0b89c82090a..4a86b96c53e 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java @@ -37,6 +37,7 @@ import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.info.Info; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; @@ -59,6 +60,8 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Christian Dupuis * @author Stephane Nicoll * @author Eddú Meléndez + * @author Meang Akira Tanaka + * */ public class EndpointAutoConfigurationTests { @@ -143,6 +146,7 @@ public class EndpointAutoConfigurationTests { EnvironmentTestUtils.addEnvironment(this.context, "info.foo:bar"); this.context.register(ProjectInfoAutoConfiguration.class, EndpointAutoConfiguration.class); this.context.refresh(); + InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); assertThat(endpoint).isNotNull(); assertThat(endpoint.invoke().get("git")).isNotNull(); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java index d0a0573a320..7715fd691ad 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java @@ -16,10 +16,14 @@ package org.springframework.boot.actuate.endpoint; -import java.util.Collections; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; -import org.junit.Test; +import java.util.Map; +import org.junit.Test; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoProvider; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -31,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Phillip Webb * @author Dave Syer + * @author Meang Akira Tanaka */ public class InfoEndpointTests extends AbstractEndpointTests { @@ -40,7 +45,15 @@ public class InfoEndpointTests extends AbstractEndpointTests { @Test public void invoke() throws Exception { - assertThat(getEndpointBean().invoke().get("a")).isEqualTo("b"); + Info actual = ((Info) getEndpointBean().invoke().get("environment")); + assertThat(actual.get("key1"), equalTo((Object) "value1")); + } + + @Test + public void invoke_HasProvider_GetProviderInfo() throws Exception { + @SuppressWarnings("unchecked") + Map actual = ((Map) getEndpointBean().invoke().get("infoProvider")); + assertThat(actual.get("key1"), equalTo((Object) "value1")); } @Configuration @@ -48,9 +61,29 @@ public class InfoEndpointTests extends AbstractEndpointTests { public static class Config { @Bean - public InfoEndpoint endpoint() { - return new InfoEndpoint(Collections.singletonMap("a", "b")); + public InfoProvider infoProvider() { + return new InfoProvider() { + + @Override + public String name() { + return "environment"; + } + + @Override + public Info provide() { + Info result = new Info(); + result.put("key1", "value1"); + + return result; + } + + }; } + + @Bean + public InfoEndpoint endpoint(Map infoProviders) { + return new InfoEndpoint(infoProviders); + } } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java new file mode 100644 index 00000000000..20644b861e2 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java @@ -0,0 +1,115 @@ +package org.springframework.boot.actuate.endpoint.mvc; + +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 java.util.Map; + +import org.elasticsearch.common.collect.Maps; +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.InfoEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.InfoMvcEndpointTests.TestConfiguration; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; +import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; +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.TestPropertySource; +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; + +/** + * Tests for {@link InfoMvcEndpointTests} + * + * @author Meang Akira Tanaka + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = { TestConfiguration.class }) +@WebAppConfiguration +@TestPropertySource(properties = {"info.app.name=MyService"}) +public class InfoMvcEndpointTests { + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @Before + public void setUp() { + + this.context.getBean(InfoEndpoint.class).setEnabled(true); + this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + } + + @Test + public void home() throws Exception { + this.mvc.perform(get("/info")).andExpect(status().isOk()) + .andExpect(content().string(containsString("\"beanName2\":{\"key22\":\"value22\",\"key21\":\"value21\"},\"beanName1\":{\"key12\":\"value12\",\"key11\":\"value11\"}"))); + } + + @Import({ JacksonAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + EndpointWebMvcAutoConfiguration.class, + WebMvcAutoConfiguration.class, + ManagementServerPropertiesAutoConfiguration.class }) + @Configuration + public static class TestConfiguration { + + private Map infoProviders = Maps.newHashMap(); + + public TestConfiguration() { + InfoProvider infoProvider1 = new InfoProvider() { + + @Override + public Info provide() { + Info result = new Info(); + result.put("key11", "value11"); + result.put("key12", "value12"); + return result; + } + + @Override + public String name() { + return "beanName1"; + } + }; + infoProviders.put("beanName1", infoProvider1); + + InfoProvider infoProvider2 = new InfoProvider() { + + @Override + public Info provide() { + Info result = new Info(); + result.put("key21", "value21"); + result.put("key22", "value22"); + return result; + } + + @Override + public String name() { + return "beanName2"; + } + }; + infoProviders.put("beanName2", infoProvider2); + } + + @Bean + public InfoEndpoint endpoint() { + return new InfoEndpoint(infoProviders); + } + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java new file mode 100644 index 00000000000..99d07fa5e5f --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java @@ -0,0 +1,75 @@ +package org.springframework.boot.actuate.endpoint.mvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.HashMap; +import java.util.Map; + +import org.elasticsearch.common.collect.Maps; +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.InfoEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.InfoMvcEndpointWithoutAnyInfoProvidersTests.TestConfiguration; +import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; +import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; +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; + +/** + * Tests for {@link InfoMvcEndpointWithoutAnyInfoProvidersTests} + * + * @author Meang Akira Tanaka + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = { TestConfiguration.class }) +@WebAppConfiguration +public class InfoMvcEndpointWithoutAnyInfoProvidersTests { + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @Before + public void setUp() { + + this.context.getBean(InfoEndpoint.class).setEnabled(true); + this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + } + + @Test + public void home() throws Exception { + this.mvc.perform(get("/info")).andExpect(status().isOk()); + } + + @Import({ JacksonAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + EndpointWebMvcAutoConfiguration.class, + WebMvcAutoConfiguration.class, + ManagementServerPropertiesAutoConfiguration.class }) + @Configuration + public static class TestConfiguration { + + private Map infoProviders = Maps.newHashMap(); + + @Bean + public InfoEndpoint endpoint() { + return new InfoEndpoint(infoProviders); + } + + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTest.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTest.java new file mode 100644 index 00000000000..2e0c2c65bdb --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTest.java @@ -0,0 +1,64 @@ +package org.springframework.boot.actuate.info; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +import java.util.Properties; + +import org.junit.Test; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.StandardEnvironment; + +public class EnvironmentInfoProviderTest { + + @Test + public void provide_HasTwoRelevantEntries_ShowOnlyRelevantEntries() throws Exception { + String expectedAppName = "my app name"; + String expectedLanguage = "da-DK"; + + Properties properties = new Properties(); + properties.setProperty("info.app", expectedAppName); + properties.setProperty("info.lang", expectedLanguage); + properties.setProperty("logging.path", "notExpected"); + + PropertySource propertySource = new PropertiesPropertySource("mysettings", properties); + + StandardEnvironment environment = new StandardEnvironment(); + environment.getPropertySources().addLast(propertySource); + + EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(environment); + + Info actual = environmentInfoProvider.provide(); + assertThat(actual.getDetails().size(), is(equalTo(2))); + assertThat((String) actual.get("app"), is(equalTo(expectedAppName))); + assertThat((String) actual.get("lang"), is(equalTo(expectedLanguage))); + } + + @Test + public void provide_HasNoRelevantEntries_NoEntries() throws Exception { + Properties properties = new Properties(); + properties.setProperty("logging.path", "notExpected"); + + PropertySource propertySource = new PropertiesPropertySource("mysettings", properties); + + StandardEnvironment environment = new StandardEnvironment(); + environment.getPropertySources().addLast(propertySource); + + EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(environment); + + Info actual = environmentInfoProvider.provide(); + assertThat(actual.getDetails().size(), is(equalTo(0))); + } + + + @Test + public void provide_HasNoEntries_NoEntries() throws Exception { + EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(new StandardEnvironment()); + + Info actual = environmentInfoProvider.provide(); + assertThat(actual.getDetails().size(), is(equalTo(0))); + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTest.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTest.java new file mode 100644 index 00000000000..90eaf0fd557 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTest.java @@ -0,0 +1,98 @@ +package org.springframework.boot.actuate.info; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider.GitInfo.Commit; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; + +public class ScmGitPropertiesInfoProviderTest { + + + @Test + public void provide_HasBadFormatButExists_EmptyInfoReturned() throws Exception { + Resource resource = new ByteArrayResource("GARBAGE".getBytes()); + ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); + + Info actual = scmGitPropertiesInfoProvider.provide(); + assertThat(actual, is(not(nullValue()))); + assertThat((String) actual.get("branch"), is(nullValue())); + Commit actualCommit = (Commit) actual.get("commit"); + assertThat(actualCommit, is(not(nullValue()))); + assertThat(actualCommit.getId(), is(equalTo(""))); + assertThat(actualCommit.getTime(), is(nullValue())); + } + + @Test + public void provide_HasValidFormat_ExpectedDataReturned() throws Exception { + String gitProperties = "git.commit.id.abbrev=e02a4f3\r\n" + + "git.commit.user.email=dsyer@vmware.com\r\n" + + "git.commit.message.full=Update Spring\r\n" + + "git.commit.id=e02a4f3b6f452cdbf6dd311f1362679eb4c31ced\r\n" + + "git.commit.message.short=Update Spring\r\n" + + "git.commit.user.name=Dave Syer\r\n" + + "git.build.user.name=Dave Syer\r\n" + + "git.build.user.email=dsyer@vmware.com\r\n" + + "git.branch=develop\r\n" + + "git.commit.time=2013-04-24T08\\:42\\:13+0100\r\n" + + "git.build.time=2013-05-23T09\\:26\\:42+0100\r\n"; + + Resource resource = new ByteArrayResource(gitProperties.getBytes()); + ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); + + Info actual = scmGitPropertiesInfoProvider.provide(); + assertThat(actual, is(not(nullValue()))); + assertThat((String) actual.get("branch"), is(equalTo("develop"))); + Commit actualCommit = (Commit) actual.get("commit"); + assertThat(actualCommit, is(not(nullValue()))); + assertThat(actualCommit.getId(), is(equalTo("e02a4f3"))); + assertThat(actualCommit.getTime(), is(equalTo("2013-04-24T08:42:13+0100"))); + } + + + @Test + public void provide_HasValidFormatButMissingCommitTime_ExpectedDataReturnedWithoutCommitTime() throws Exception { + String gitProperties = "git.commit.id.abbrev=e02a4f3\r\n" + + "git.commit.user.email=dsyer@vmware.com\r\n" + + "git.commit.message.full=Update Spring\r\n" + + "git.commit.id=e02a4f3b6f452cdbf6dd311f1362679eb4c31ced\r\n" + + "git.commit.message.short=Update Spring\r\n" + + "git.commit.user.name=Dave Syer\r\n" + + "git.build.user.name=Dave Syer\r\n" + + "git.build.user.email=dsyer@vmware.com\r\n" + + "git.branch=develop\r\n" + + "git.build.time=2013-05-23T09\\:26\\:42+0100\r\n"; + + Resource resource = new ByteArrayResource(gitProperties.getBytes()); + ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); + + Info actual = scmGitPropertiesInfoProvider.provide(); + assertThat(actual, is(not(nullValue()))); + assertThat((String) actual.get("branch"), is(equalTo("develop"))); + Commit actualCommit = (Commit) actual.get("commit"); + assertThat(actualCommit, is(not(nullValue()))); + assertThat(actualCommit.getId(), is(equalTo("e02a4f3"))); + assertThat(actualCommit.getTime(), is(nullValue())); + } + + + @Test + public void provide_DoesNotExists_NullReturned() throws Exception { + + Resource resource = mock(Resource.class); + when(resource.exists()) + .thenReturn(false); + ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); + + Info actual = scmGitPropertiesInfoProvider.provide(); + assertThat(actual, is(nullValue())); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java new file mode 100644 index 00000000000..822d5b8d33b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java @@ -0,0 +1,21 @@ +package sample.actuator; + +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.stereotype.Component; + +@Component +public class ExampleInfoProvider implements InfoProvider { + + @Override + public Info provide() { + Info result = new Info(); + result.put("somekey", "somevalue"); + return result; + } + + @Override + public String name() { + return "example"; + } +} From 7618802838970273473be93b2d652617e687f4ca Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 1 Mar 2016 15:44:15 +0100 Subject: [PATCH 2/3] rebase to master --- .../EndpointAutoConfiguration.java | 5 +- .../InfoProviderAutoConfiguration.java | 9 +-- .../boot/actuate/endpoint/InfoEndpoint.java | 23 +++--- .../actuate/info/EnvironmentInfoProvider.java | 13 ++- .../boot/actuate/info/Info.java | 12 +-- .../boot/actuate/info/InfoProvider.java | 21 ++++- .../info/ScmGitPropertiesInfoProvider.java | 47 ++++++++--- .../EndpointAutoConfigurationTests.java | 2 - .../actuate/endpoint/InfoEndpointTests.java | 15 +--- .../endpoint/mvc/InfoMvcEndpointTests.java | 61 +++++++++----- ...cEndpointWithoutAnyInfoProvidersTests.java | 42 +++++++--- ...java => EnvironmentInfoProviderTests.java} | 55 ++++++++----- ...=> ScmGitPropertiesInfoProviderTests.java} | 80 +++++++++++-------- 13 files changed, 237 insertions(+), 148 deletions(-) rename spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/{EnvironmentInfoProviderTest.java => EnvironmentInfoProviderTests.java} (60%) rename spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/{ScmGitPropertiesInfoProviderTest.java => ScmGitPropertiesInfoProviderTests.java} (60%) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java index b37d47136e7..4f84782bb6f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java @@ -58,15 +58,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; -import org.springframework.boot.bind.PropertiesConfigurationFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; -import liquibase.integration.spring.SpringLiquibase; - /** * {@link EnableAutoConfiguration Auto-configuration} for common management * {@link Endpoint}s. @@ -81,7 +78,7 @@ import liquibase.integration.spring.SpringLiquibase; * */ @Configuration -@AutoConfigureAfter({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class }) +@AutoConfigureAfter({FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class}) @EnableConfigurationProperties(EndpointProperties.class) public class EndpointAutoConfiguration { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java index aefba43f060..60ed68d3027 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java @@ -37,7 +37,7 @@ import org.springframework.core.io.Resource; * @since 1.3.0 */ @Configuration -@AutoConfigureBefore({ EndpointAutoConfiguration.class }) +@AutoConfigureBefore({EndpointAutoConfiguration.class}) public class InfoProviderAutoConfiguration { @Autowired @@ -49,14 +49,13 @@ public class InfoProviderAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "environmentInfoProvider") public InfoProvider environmentInfoProvider() throws Exception { - return new EnvironmentInfoProvider(environment); + return new EnvironmentInfoProvider(this.environment); } - + @Bean @ConditionalOnMissingBean(name = "scmInfoProvider") public InfoProvider scmInfoProvider() throws Exception { - return new ScmGitPropertiesInfoProvider(gitProperties); + return new ScmGitPropertiesInfoProvider(this.gitProperties); } - } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java index 9632b23ae14..0f8bd3d02f5 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java @@ -25,16 +25,19 @@ import org.springframework.util.Assert; /** * {@link Endpoint} to expose arbitrary application information. - * - * The information, which the {@link InfoEndpoint} can provide can be customized to display any informations, - * however initially the info endpoint will provide git version information (if available) and environment information, - * whose entries are prefixed with info. * - * In order to add additional information to the endpoint, one has to implement a class, which implements the {@link org.springframework.boot.actuate.info.InfoProvider} - * interface and register it in the application context. The InfoEndpoint will automatically pick it up, when it is being instantiated. + * The information, which the {@link InfoEndpoint} can provide can be customized to + * display any information, however initially the info endpoint will provide git version + * information (if available) and environment information,whose entries are prefixed with + * info. * - * The standard InfoProvider for GIT is registered as the scmInfoProvider, and the registration can be changed - * in case standard provider does not meet ones requirements. + * In order to add additional information to the endpoint, one has to implement a class, + * which implements the {@link org.springframework.boot.actuate.info.InfoProvider} + * interface and register it in the application context. The InfoEndpoint will + * automatically pick it up, when it is being instantiated. + * + * The standard InfoProvider for GIT is registered as the scmInfoProvider, and the + * registration can be changed in case standard provider does not meet ones requirements. * * @see org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider * @see org.springframework.boot.actuate.info.EnvironmentInfoProvider @@ -61,9 +64,9 @@ public class InfoEndpoint extends AbstractEndpoint { @Override public Info invoke() { Info result = new Info(); - for (InfoProvider provider : infoProviders.values()) { + for (InfoProvider provider : this.infoProviders.values()) { Info info = provider.provide(); - if(info != null) { + if (info != null) { result.put(provider.name(), info); } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java index 573580e7ca3..062f8d75eb4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.boot.actuate.info; import java.util.LinkedHashMap; @@ -22,9 +23,8 @@ import org.springframework.boot.bind.PropertiesConfigurationFactory; import org.springframework.core.env.ConfigurableEnvironment; /** - * A {@link InfoProvider} that provides all environment entries prefixed with info - * - * See something + * A {@link InfoProvider} that provides all environment entries prefixed with + * info. * * @author Meang Akira Tanaka * @since 1.3.0 @@ -32,13 +32,12 @@ import org.springframework.core.env.ConfigurableEnvironment; public class EnvironmentInfoProvider implements InfoProvider { private final ConfigurableEnvironment environment; - private final Map infoMap; + private final Info info; public EnvironmentInfoProvider(ConfigurableEnvironment environment) throws Exception { this.environment = environment; - infoMap = extractInfoFromEnvironment(); - this.info = new Info(infoMap); + this.info = new Info(extractInfoFromEnvironment()); } @Override @@ -48,7 +47,7 @@ public class EnvironmentInfoProvider implements InfoProvider { @Override public Info provide() { - return info; + return this.info; } private Map extractInfoFromEnvironment() throws Exception { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java index 1b339b8766c..064e966685f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java @@ -24,17 +24,16 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; /** - * Carries information from a specific info provider - * - * @see org.springframework.boot.actuate.endpoint.InfoEndpoint + * Carries information from a specific info provider. * * @author Meang Akira Tanaka * @since 1.3.0 + * @see org.springframework.boot.actuate.endpoint.InfoEndpoint */ @JsonInclude(Include.NON_EMPTY) public final class Info { - private final Map details = new HashMap(); + private final Map details = new HashMap(); public Info() { } @@ -44,6 +43,7 @@ public final class Info { } /** + * Return the content. * @return the details of the info or an empty map. */ @JsonAnyGetter @@ -54,12 +54,12 @@ public final class Info { public void put(String infoId, Object value) { this.details.put(infoId, value); } - + @SuppressWarnings("unchecked") public T get(String infoId) { return (T) this.details.get(infoId); } - + @Override public boolean equals(Object obj) { if (obj == this) { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java index ad51181d8c0..1a76553676b 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java @@ -1,15 +1,32 @@ +/* + * 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.info; /** - * information provider for the info endpoint + * information provider for the info endpoint. * * @author Meang Akira Tanaka */ public interface InfoProvider { String name(); - + /** + * Return the {@link Info} instance. * @return a collection of information */ Info provide(); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java index 7e6984cef04..8b12488b7b1 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java @@ -1,3 +1,19 @@ +/* + * 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.info; import java.util.Properties; @@ -7,20 +23,22 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.support.PropertiesLoaderUtils; /** - * A {@link InfoProvider} that provides git information extracted from the git.properties file generated by the maven plugin + * A {@link InfoProvider} that provides git information extracted from the + * git.properties file generated by the maven plugin * pl.project13.maven:git-commit-id-plugin. - * + * * @author Meang Akira Tanaka * @since 1.3.0 */ public class ScmGitPropertiesInfoProvider implements InfoProvider { private final Resource gitPropertiesResource; + private final GitInfo gitInfo; public ScmGitPropertiesInfoProvider(Resource gitPropertiesResource) throws Exception { this.gitPropertiesResource = gitPropertiesResource; - gitInfo = extractGitInfo(); + this.gitInfo = extractGitInfo(); } @Override @@ -30,19 +48,19 @@ public class ScmGitPropertiesInfoProvider implements InfoProvider { @Override public Info provide() { - if(gitInfo == null) { + if (this.gitInfo == null) { return null; } - + Info result = new Info(); - - result.put("branch", gitInfo.getBranch()); - result.put("commit", gitInfo.getCommit()); - + + result.put("branch", this.gitInfo.getBranch()); + result.put("commit", this.gitInfo.getCommit()); + return result; } - + private GitInfo extractGitInfo() throws Exception { PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory( new GitInfo()); @@ -50,7 +68,8 @@ public class ScmGitPropertiesInfoProvider implements InfoProvider { Properties properties = new Properties(); if (this.gitPropertiesResource.exists()) { properties = PropertiesLoaderUtils.loadProperties(this.gitPropertiesResource); - } else { + } + else { return null; } factory.setProperties(properties); @@ -58,6 +77,9 @@ public class ScmGitPropertiesInfoProvider implements InfoProvider { } + /** + * Git info. + */ public static class GitInfo { private String branch; @@ -76,6 +98,9 @@ public class ScmGitPropertiesInfoProvider implements InfoProvider { return this.commit; } + /** + * Commit information. + */ public static class Commit { private String id; diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java index 4a86b96c53e..b42bb062ca1 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java @@ -37,7 +37,6 @@ import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.health.Health; -import org.springframework.boot.actuate.info.Info; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; @@ -61,7 +60,6 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Stephane Nicoll * @author Eddú Meléndez * @author Meang Akira Tanaka - * */ public class EndpointAutoConfigurationTests { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java index 7715fd691ad..b88294eb0a5 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java @@ -16,12 +16,10 @@ package org.springframework.boot.actuate.endpoint; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; - import java.util.Map; import org.junit.Test; + import org.springframework.boot.actuate.info.Info; import org.springframework.boot.actuate.info.InfoProvider; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -45,15 +43,8 @@ public class InfoEndpointTests extends AbstractEndpointTests { @Test public void invoke() throws Exception { - Info actual = ((Info) getEndpointBean().invoke().get("environment")); - assertThat(actual.get("key1"), equalTo((Object) "value1")); - } - - @Test - public void invoke_HasProvider_GetProviderInfo() throws Exception { - @SuppressWarnings("unchecked") - Map actual = ((Map) getEndpointBean().invoke().get("infoProvider")); - assertThat(actual.get("key1"), equalTo((Object) "value1")); + Info actual = getEndpointBean().invoke().get("environment"); + assertThat(actual.get("key1")).isEqualTo("value1"); } @Configuration diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java index 20644b861e2..d122c6621c1 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java @@ -1,9 +1,20 @@ -package org.springframework.boot.actuate.endpoint.mvc; +/* + * 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. + */ -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; +package org.springframework.boot.actuate.endpoint.mvc; import java.util.Map; @@ -11,6 +22,7 @@ import org.elasticsearch.common.collect.Maps; 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; @@ -32,13 +44,18 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; +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; + /** * Tests for {@link InfoMvcEndpointTests} * * @author Meang Akira Tanaka */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = { TestConfiguration.class }) +@SpringApplicationConfiguration(classes = {TestConfiguration.class}) @WebAppConfiguration @TestPropertySource(properties = {"info.app.name=MyService"}) public class InfoMvcEndpointTests { @@ -57,14 +74,16 @@ public class InfoMvcEndpointTests { @Test public void home() throws Exception { this.mvc.perform(get("/info")).andExpect(status().isOk()) - .andExpect(content().string(containsString("\"beanName2\":{\"key22\":\"value22\",\"key21\":\"value21\"},\"beanName1\":{\"key12\":\"value12\",\"key11\":\"value11\"}"))); + .andExpect(content().string( + containsString("\"beanName2\":{\"key22\":\"value22\",\"key21\":\"value21\"}," + + "\"beanName1\":{\"key12\":\"value12\",\"key11\":\"value11\"}"))); } - - @Import({ JacksonAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - EndpointWebMvcAutoConfiguration.class, - WebMvcAutoConfiguration.class, - ManagementServerPropertiesAutoConfiguration.class }) + + @Import({JacksonAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + EndpointWebMvcAutoConfiguration.class, + WebMvcAutoConfiguration.class, + ManagementServerPropertiesAutoConfiguration.class}) @Configuration public static class TestConfiguration { @@ -72,7 +91,7 @@ public class InfoMvcEndpointTests { public TestConfiguration() { InfoProvider infoProvider1 = new InfoProvider() { - + @Override public Info provide() { Info result = new Info(); @@ -86,10 +105,10 @@ public class InfoMvcEndpointTests { return "beanName1"; } }; - infoProviders.put("beanName1", infoProvider1); - + this.infoProviders.put("beanName1", infoProvider1); + InfoProvider infoProvider2 = new InfoProvider() { - + @Override public Info provide() { Info result = new Info(); @@ -103,13 +122,13 @@ public class InfoMvcEndpointTests { return "beanName2"; } }; - infoProviders.put("beanName2", infoProvider2); + this.infoProviders.put("beanName2", infoProvider2); } - + @Bean public InfoEndpoint endpoint() { - return new InfoEndpoint(infoProviders); + return new InfoEndpoint(this.infoProviders); } } - + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java index 99d07fa5e5f..9cb7bc6e9fa 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java @@ -1,15 +1,28 @@ -package org.springframework.boot.actuate.endpoint.mvc; +/* + * 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. + */ -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.springframework.boot.actuate.endpoint.mvc; -import java.util.HashMap; import java.util.Map; import org.elasticsearch.common.collect.Maps; 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; @@ -29,13 +42,16 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + /** * Tests for {@link InfoMvcEndpointWithoutAnyInfoProvidersTests} * * @author Meang Akira Tanaka */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = { TestConfiguration.class }) +@SpringApplicationConfiguration(classes = {TestConfiguration.class}) @WebAppConfiguration public class InfoMvcEndpointWithoutAnyInfoProvidersTests { @Autowired @@ -54,12 +70,12 @@ public class InfoMvcEndpointWithoutAnyInfoProvidersTests { public void home() throws Exception { this.mvc.perform(get("/info")).andExpect(status().isOk()); } - - @Import({ JacksonAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - EndpointWebMvcAutoConfiguration.class, - WebMvcAutoConfiguration.class, - ManagementServerPropertiesAutoConfiguration.class }) + + @Import({JacksonAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + EndpointWebMvcAutoConfiguration.class, + WebMvcAutoConfiguration.class, + ManagementServerPropertiesAutoConfiguration.class}) @Configuration public static class TestConfiguration { @@ -67,9 +83,9 @@ public class InfoMvcEndpointWithoutAnyInfoProvidersTests { @Bean public InfoEndpoint endpoint() { - return new InfoEndpoint(infoProviders); + return new InfoEndpoint(this.infoProviders); } } - + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTest.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java similarity index 60% rename from spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTest.java rename to spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java index 2e0c2c65bdb..e9d775ada11 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTest.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java @@ -1,64 +1,79 @@ -package org.springframework.boot.actuate.info; +/* + * 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. + */ -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; +package org.springframework.boot.actuate.info; import java.util.Properties; import org.junit.Test; + import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; -public class EnvironmentInfoProviderTest { +import static org.assertj.core.api.Assertions.assertThat; + +public class EnvironmentInfoProviderTests { @Test public void provide_HasTwoRelevantEntries_ShowOnlyRelevantEntries() throws Exception { String expectedAppName = "my app name"; String expectedLanguage = "da-DK"; - Properties properties = new Properties(); + Properties properties = new Properties(); properties.setProperty("info.app", expectedAppName); properties.setProperty("info.lang", expectedLanguage); properties.setProperty("logging.path", "notExpected"); - + PropertySource propertySource = new PropertiesPropertySource("mysettings", properties); StandardEnvironment environment = new StandardEnvironment(); environment.getPropertySources().addLast(propertySource); EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(environment); - + Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size(), is(equalTo(2))); - assertThat((String) actual.get("app"), is(equalTo(expectedAppName))); - assertThat((String) actual.get("lang"), is(equalTo(expectedLanguage))); + assertThat(actual.getDetails().size()).isEqualTo(2); + assertThat((String) actual.get("app")).isEqualTo(expectedAppName); + assertThat((String) actual.get("lang")).isEqualTo(expectedLanguage); } - + @Test public void provide_HasNoRelevantEntries_NoEntries() throws Exception { - Properties properties = new Properties(); + Properties properties = new Properties(); properties.setProperty("logging.path", "notExpected"); - + PropertySource propertySource = new PropertiesPropertySource("mysettings", properties); StandardEnvironment environment = new StandardEnvironment(); environment.getPropertySources().addLast(propertySource); EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(environment); - + Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size(), is(equalTo(0))); + assertThat(actual.getDetails().size()).isEqualTo(0); } - - + + @Test public void provide_HasNoEntries_NoEntries() throws Exception { EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(new StandardEnvironment()); - + Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size(), is(equalTo(0))); + assertThat(actual.getDetails().size()).isEqualTo(0); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTest.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java similarity index 60% rename from spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTest.java rename to spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java index 90eaf0fd557..1a6dba70555 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTest.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java @@ -1,33 +1,46 @@ -package org.springframework.boot.actuate.info; +/* + * 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. + */ -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +package org.springframework.boot.actuate.info; import org.junit.Test; + import org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider.GitInfo.Commit; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; -public class ScmGitPropertiesInfoProviderTest { +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +public class ScmGitPropertiesInfoProviderTests { + - @Test public void provide_HasBadFormatButExists_EmptyInfoReturned() throws Exception { Resource resource = new ByteArrayResource("GARBAGE".getBytes()); ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual, is(not(nullValue()))); - assertThat((String) actual.get("branch"), is(nullValue())); - Commit actualCommit = (Commit) actual.get("commit"); - assertThat(actualCommit, is(not(nullValue()))); - assertThat(actualCommit.getId(), is(equalTo(""))); - assertThat(actualCommit.getTime(), is(nullValue())); + assertThat(actual).isNotNull(); + assertThat((String) actual.get("branch")).isNull(); + Commit actualCommit = actual.get("commit"); + assertThat(actualCommit).isNotNull(); + assertThat(actualCommit.getId()).isEqualTo(""); + assertThat(actualCommit.getTime()).isNull(); } @Test @@ -43,17 +56,17 @@ public class ScmGitPropertiesInfoProviderTest { + "git.branch=develop\r\n" + "git.commit.time=2013-04-24T08\\:42\\:13+0100\r\n" + "git.build.time=2013-05-23T09\\:26\\:42+0100\r\n"; - + Resource resource = new ByteArrayResource(gitProperties.getBytes()); ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual, is(not(nullValue()))); - assertThat((String) actual.get("branch"), is(equalTo("develop"))); - Commit actualCommit = (Commit) actual.get("commit"); - assertThat(actualCommit, is(not(nullValue()))); - assertThat(actualCommit.getId(), is(equalTo("e02a4f3"))); - assertThat(actualCommit.getTime(), is(equalTo("2013-04-24T08:42:13+0100"))); + assertThat(actual).isNotNull(); + assertThat((String) actual.get("branch")).isEqualTo("develop"); + Commit actualCommit = actual.get("commit"); + assertThat(actualCommit).isNotNull(); + assertThat(actualCommit.getId()).isEqualTo("e02a4f3"); + assertThat(actualCommit.getTime()).isEqualTo("2013-04-24T08:42:13+0100"); } @@ -69,30 +82,27 @@ public class ScmGitPropertiesInfoProviderTest { + "git.build.user.email=dsyer@vmware.com\r\n" + "git.branch=develop\r\n" + "git.build.time=2013-05-23T09\\:26\\:42+0100\r\n"; - + Resource resource = new ByteArrayResource(gitProperties.getBytes()); ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual, is(not(nullValue()))); - assertThat((String) actual.get("branch"), is(equalTo("develop"))); - Commit actualCommit = (Commit) actual.get("commit"); - assertThat(actualCommit, is(not(nullValue()))); - assertThat(actualCommit.getId(), is(equalTo("e02a4f3"))); - assertThat(actualCommit.getTime(), is(nullValue())); + assertThat(actual).isNotNull(); + assertThat((String) actual.get("branch")).isEqualTo("develop"); + Commit actualCommit = (Commit) actual.get("commit"); + assertThat(actualCommit).isNotNull(); + assertThat(actualCommit.getId()).isEqualTo("e02a4f3"); + assertThat(actualCommit.getTime()).isNull(); } - @Test public void provide_DoesNotExists_NullReturned() throws Exception { - Resource resource = mock(Resource.class); - when(resource.exists()) - .thenReturn(false); + given(resource.exists()).willReturn(false); ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual, is(nullValue())); + assertThat(actual).isNull(); } } From 0490fbc7f85b1881f038dd9a1bd6240e06b43d1b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 1 Mar 2016 19:01:11 +0100 Subject: [PATCH 3/3] Polish contribution `InfoProvider` is now `InfoContributor` and contributes to the `Info` instance via a builder. The `Info` instance is immutable. Each contributor can be disabled via the `management.info..enabled` key or all can be disabled using `management.info.defaults.enabled` (this is similar to what the health endpoint does). By default, all keys from the environment starting with `info.` are exposed. If a `git.properties` file is present in the classpath, the content of `GitInfo` is exposed using the `git` key. A `SimpleInfoContributor` and `AbstractEnvironmentInfoContributor` are available for convenience. `InfoContributor` instances can be ordered the usual way, with a default order provided by `InfoProviderAutoConfiguration#DEFAULT_ORDER`. Closes gh-3492 --- .../ConditionalOnEnabledInfoContributor.java | 49 +++++++ .../EndpointAutoConfiguration.java | 6 +- .../InfoContributorAutoConfiguration.java | 68 +++++++++ .../InfoProviderAutoConfiguration.java | 61 -------- .../OnEnabledEndpointElementCondition.java | 84 +++++++++++ .../OnEnabledHealthIndicatorCondition.java | 47 ++----- .../OnEnabledInfoContributorCondition.java | 42 ++++++ .../boot/actuate/endpoint/InfoEndpoint.java | 58 ++++---- .../AbstractEnvironmentInfoContributor.java | 78 +++++++++++ .../info/EnvironmentInfoContributor.java | 45 ++++++ .../actuate/info/EnvironmentInfoProvider.java | 60 -------- .../boot/actuate/info/Info.java | 76 ++++++++-- ...InfoProvider.java => InfoContributor.java} | 15 +- .../info/ScmGitPropertiesInfoProvider.java | 130 ------------------ .../actuate/info/SimpleInfoContributor.java | 46 +++++++ ...itional-spring-configuration-metadata.json | 18 +++ .../main/resources/META-INF/spring.factories | 2 +- .../EndpointAutoConfigurationTests.java | 86 +++++++++++- ...InfoContributorAutoConfigurationTests.java | 125 +++++++++++++++++ .../actuate/endpoint/InfoEndpointTests.java | 29 ++-- .../endpoint/mvc/InfoMvcEndpointTests.java | 65 ++++----- ...cEndpointWithoutAnyInfoProvidersTests.java | 9 +- .../info/EnvironmentInfoContributorTests.java | 60 ++++++++ .../info/EnvironmentInfoProviderTests.java | 79 ----------- .../ScmGitPropertiesInfoProviderTests.java | 108 --------------- .../info/SimpleInfoContributorTests.java | 56 ++++++++ .../appendix-application-properties.adoc | 5 + .../actuator/ExampleInfoContributor.java | 34 +++++ .../sample/actuator/ExampleInfoProvider.java | 21 --- .../SampleActuatorApplicationTests.java | 3 + 30 files changed, 948 insertions(+), 617 deletions(-) create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnabledInfoContributor.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfiguration.java delete mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledEndpointElementCondition.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledInfoContributorCondition.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/AbstractEnvironmentInfoContributor.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java delete mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java rename spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/{InfoProvider.java => InfoContributor.java} (71%) delete mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SimpleInfoContributor.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfigurationTests.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoContributorTests.java delete mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java delete mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SimpleInfoContributorTests.java create mode 100644 spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoContributor.java delete mode 100644 spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnabledInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnabledInfoContributor.java new file mode 100644 index 00000000000..af8b47e4010 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnabledInfoContributor.java @@ -0,0 +1,49 @@ +/* + * 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.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; + +/** + * {@link Conditional} that checks whether or not a default info contributor is enabled. + * Matches if the value of the {@code management.info..enabled} property is + * {@code true}. Otherwise, matches if the value of the + * {@code management.info.defaults.enabled} property is {@code true} or if it is not + * configured. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Documented +@Conditional(OnEnabledInfoContributorCondition.class) +public @interface ConditionalOnEnabledInfoContributor { + + /** + * The name of the info contributor. + * @return the name of the info contributor + */ + String value(); + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java index 4f84782bb6f..8661b8e93e6 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java @@ -46,7 +46,7 @@ import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.OrderedHealthAggregator; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.actuate.trace.InMemoryTraceRepository; import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -89,7 +89,7 @@ public class EndpointAutoConfiguration { private Map healthIndicators = new HashMap(); @Autowired(required = false) - private Map infoProviders = new HashMap(); + private List infoContributors = new ArrayList(); @Autowired(required = false) private Collection publicMetrics; @@ -118,7 +118,7 @@ public class EndpointAutoConfiguration { @Bean @ConditionalOnMissingBean public InfoEndpoint infoEndpoint() throws Exception { - return new InfoEndpoint(this.infoProviders); + return new InfoEndpoint(this.infoContributors); } @Bean diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfiguration.java new file mode 100644 index 00000000000..96f7fe7d6b0 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfiguration.java @@ -0,0 +1,68 @@ +/* + * 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.autoconfigure; + +import java.io.IOException; + +import org.springframework.boot.actuate.info.EnvironmentInfoContributor; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.boot.actuate.info.SimpleInfoContributor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.boot.autoconfigure.info.GitInfo; +import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for standard {@link InfoContributor}s. + * + * @author Meang Akira Tanaka + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Configuration +@AutoConfigureAfter(ProjectInfoAutoConfiguration.class) +@AutoConfigureBefore(EndpointAutoConfiguration.class) +public class InfoContributorAutoConfiguration { + + /** + * The default order for the core {@link InfoContributor} beans. + */ + public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; + + @Bean + @ConditionalOnEnabledInfoContributor("env") + @Order(DEFAULT_ORDER) + public EnvironmentInfoContributor envInfoContributor(ConfigurableEnvironment environment) { + return new EnvironmentInfoContributor(environment); + } + + @Bean + @ConditionalOnEnabledInfoContributor("git") + @ConditionalOnSingleCandidate(GitInfo.class) + @Order(DEFAULT_ORDER) + public InfoContributor gitInfoContributor(GitInfo gitInfo) throws IOException { + return new SimpleInfoContributor("git", gitInfo); + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java deleted file mode 100644 index 60ed68d3027..00000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.autoconfigure; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.info.EnvironmentInfoProvider; -import org.springframework.boot.actuate.info.InfoProvider; -import org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.StandardEnvironment; -import org.springframework.core.io.Resource; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for standard {@link InfoProvider}s. - * - * @author Meang Akira Tanaka - * @since 1.3.0 - */ -@Configuration -@AutoConfigureBefore({EndpointAutoConfiguration.class}) -public class InfoProviderAutoConfiguration { - - @Autowired - private final ConfigurableEnvironment environment = new StandardEnvironment(); - - @Value("${spring.git.properties:classpath:git.properties}") - private Resource gitProperties; - - @Bean - @ConditionalOnMissingBean(name = "environmentInfoProvider") - public InfoProvider environmentInfoProvider() throws Exception { - return new EnvironmentInfoProvider(this.environment); - } - - @Bean - @ConditionalOnMissingBean(name = "scmInfoProvider") - public InfoProvider scmInfoProvider() throws Exception { - return new ScmGitPropertiesInfoProvider(this.gitProperties); - } - -} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledEndpointElementCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledEndpointElementCondition.java new file mode 100644 index 00000000000..ae5454d511b --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledEndpointElementCondition.java @@ -0,0 +1,84 @@ +/* + * 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 org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * Base endpoint element condition. An element can be disabled globally via the + * `defaults` name or individually via the name of the element. + * + * @author Stephane Nicoll + */ +abstract class OnEnabledEndpointElementCondition extends SpringBootCondition { + + private final String prefix; + + private final Class annotationType; + + OnEnabledEndpointElementCondition(String prefix, Class annotationType) { + this.prefix = prefix; + this.annotationType = annotationType; + } + + protected String getEndpointElementOutcomeMessage(String name, boolean match) { + return "The endpoint element " + name + " is " + (match ? "enabled" : "disabled"); + } + + protected String getDefaultEndpointElementOutcomeMessage(boolean match) { + return "All default endpoint elements are " + (match ? "enabled" : "disabled") + + " by default"; + } + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + AnnotationAttributes annotationAttributes = AnnotationAttributes + .fromMap(metadata.getAnnotationAttributes(this.annotationType.getName())); + String endpointName = annotationAttributes.getString("value"); + ConditionOutcome outcome = getEndpointOutcome(context, endpointName); + if (outcome != null) { + return outcome; + } + return getDefaultEndpointsOutcome(context); + } + + protected ConditionOutcome getEndpointOutcome(ConditionContext context, + String endpointName) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( + context.getEnvironment(), this.prefix + endpointName + "."); + if (resolver.containsProperty("enabled")) { + boolean match = resolver.getProperty("enabled", Boolean.class, true); + return new ConditionOutcome(match, + getEndpointElementOutcomeMessage(endpointName, match)); + } + return null; + } + + protected ConditionOutcome getDefaultEndpointsOutcome(ConditionContext context) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( + context.getEnvironment(), this.prefix + "defaults."); + boolean match = Boolean.valueOf(resolver.getProperty("enabled", "true")); + return new ConditionOutcome(match, getDefaultEndpointElementOutcomeMessage(match)); + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java index 4cbb0a369d2..35bceaf1e49 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java @@ -16,55 +16,28 @@ package org.springframework.boot.actuate.autoconfigure; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.type.AnnotatedTypeMetadata; /** * {@link Condition} that checks if a health indicator is enabled. * * @author Stephane Nicoll */ -class OnEnabledHealthIndicatorCondition extends SpringBootCondition { +class OnEnabledHealthIndicatorCondition extends OnEnabledEndpointElementCondition { - private static final String ANNOTATION_CLASS = ConditionalOnEnabledHealthIndicator.class - .getName(); - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, - AnnotatedTypeMetadata metadata) { - AnnotationAttributes annotationAttributes = AnnotationAttributes - .fromMap(metadata.getAnnotationAttributes(ANNOTATION_CLASS)); - String endpointName = annotationAttributes.getString("value"); - ConditionOutcome outcome = getHealthIndicatorOutcome(context, endpointName); - if (outcome != null) { - return outcome; - } - return getDefaultIndicatorsOutcome(context); + OnEnabledHealthIndicatorCondition() { + super("management.health.", ConditionalOnEnabledHealthIndicator.class); } - private ConditionOutcome getHealthIndicatorOutcome(ConditionContext context, - String endpointName) { - RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( - context.getEnvironment(), "management.health." + endpointName + "."); - if (resolver.containsProperty("enabled")) { - boolean match = resolver.getProperty("enabled", Boolean.class, true); - return new ConditionOutcome(match, "The health indicator " + endpointName - + " is " + (match ? "enabled" : "disabled")); - } - return null; + @Override + protected String getEndpointElementOutcomeMessage(String name, boolean match) { + return "The health indicator " + name + " is " + (match ? "enabled" : "disabled"); } - private ConditionOutcome getDefaultIndicatorsOutcome(ConditionContext context) { - RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( - context.getEnvironment(), "management.health.defaults."); - boolean match = Boolean.valueOf(resolver.getProperty("enabled", "true")); - return new ConditionOutcome(match, "All default health indicators are " - + (match ? "enabled" : "disabled") + " by default"); + @Override + protected String getDefaultEndpointElementOutcomeMessage(boolean match) { + return "All default health indicators are " + (match ? "enabled" : "disabled") + + " by default"; } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledInfoContributorCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledInfoContributorCondition.java new file mode 100644 index 00000000000..a591ce25a03 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledInfoContributorCondition.java @@ -0,0 +1,42 @@ +/* + * 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 org.springframework.context.annotation.Condition; + +/** + * {@link Condition} that checks if a info indicator is enabled. + * + * @author Stephane Nicoll + */ +class OnEnabledInfoContributorCondition extends OnEnabledEndpointElementCondition { + + OnEnabledInfoContributorCondition() { + super("management.info.", ConditionalOnEnabledInfoContributor.class); + } + + @Override + protected String getEndpointElementOutcomeMessage(String name, boolean match) { + return "The info contributor " + name + " is " + (match ? "enabled" : "disabled"); + } + + @Override + protected String getDefaultEndpointElementOutcomeMessage(boolean match) { + return "All default info contributors are " + (match ? "enabled" : "disabled") + + " by default"; + } +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java index 0f8bd3d02f5..d41fe6897f8 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java @@ -16,60 +16,56 @@ package org.springframework.boot.actuate.endpoint; +import java.util.Collections; +import java.util.List; import java.util.Map; import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; /** * {@link Endpoint} to expose arbitrary application information. * - * The information, which the {@link InfoEndpoint} can provide can be customized to - * display any information, however initially the info endpoint will provide git version - * information (if available) and environment information,whose entries are prefixed with - * info. - * - * In order to add additional information to the endpoint, one has to implement a class, - * which implements the {@link org.springframework.boot.actuate.info.InfoProvider} - * interface and register it in the application context. The InfoEndpoint will - * automatically pick it up, when it is being instantiated. - * - * The standard InfoProvider for GIT is registered as the scmInfoProvider, and the - * registration can be changed in case standard provider does not meet ones requirements. - * - * @see org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider - * @see org.springframework.boot.actuate.info.EnvironmentInfoProvider - * * @author Dave Syer * @author Meang Akira Tanaka + * @author Stephane Nicoll */ -@ConfigurationProperties(prefix = "endpoints.info", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.info") public class InfoEndpoint extends AbstractEndpoint { - private final Map infoProviders; + private final List infoContributors; /** * Create a new {@link InfoEndpoint} instance. - * - * @param infoProviders the infoProviders to be used + * @param infoContributors the info contributors to use */ - public InfoEndpoint(Map infoProviders) { + public InfoEndpoint(List infoContributors) { super("info", false); - Assert.notNull(infoProviders, "Info providers must not be null"); - this.infoProviders = infoProviders; + Assert.notNull(infoContributors, "Info contributors must not be null"); + this.infoContributors = infoContributors; } + @SuppressWarnings("deprecation") @Override public Info invoke() { - Info result = new Info(); - for (InfoProvider provider : this.infoProviders.values()) { - Info info = provider.provide(); - if (info != null) { - result.put(provider.name(), info); - } + Info.Builder builder = new Info.Builder(); + for (InfoContributor contributor : this.infoContributors) { + contributor.contribute(builder); } - return result; + builder.withDetails(getAdditionalInfo()); + return builder.build(); } + + /** + * Return additional information to include in the output. + * @return additional information + * @deprecated define an additional {@link InfoContributor} bean instead. + */ + @Deprecated + protected Map getAdditionalInfo() { + return Collections.emptyMap(); + } + } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/AbstractEnvironmentInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/AbstractEnvironmentInfoContributor.java new file mode 100644 index 00000000000..d529969baf3 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/AbstractEnvironmentInfoContributor.java @@ -0,0 +1,78 @@ +/* + * 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.info; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.bind.PropertiesConfigurationFactory; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.validation.BindException; + +/** + * A base {@link InfoContributor} implementation working on the {@link Environment}. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +public abstract class AbstractEnvironmentInfoContributor implements InfoContributor { + + private final ConfigurableEnvironment environment; + + protected AbstractEnvironmentInfoContributor(ConfigurableEnvironment environment) { + this.environment = environment; + } + + public final ConfigurableEnvironment getEnvironment() { + return this.environment; + } + + + /** + * Extract the keys from the environment using the specified {@code prefix}. The + * prefix won't be included. + *

Any key that starts with the {@code prefix} will be included + * @param prefix the prefix to use + * @return the keys from the environment matching the prefix + */ + protected Map extract(String prefix) { + Map content = new LinkedHashMap(); + bindEnvironmentTo(prefix, content); + return content; + } + + /** + * Bind the specified {@code target} from the environment using the {@code prefix}. + *

Any key that starts with the {@code prefix} will be bound to the {@code target}. + * @param prefix the prefix to use + * @param target the object to bind to + */ + protected void bindEnvironmentTo(String prefix, Object target) { + PropertiesConfigurationFactory factory = + new PropertiesConfigurationFactory(target); + factory.setTargetName(prefix); + factory.setPropertySources(this.environment.getPropertySources()); + try { + factory.bindPropertiesToTarget(); + } + catch (BindException ex) { + throw new IllegalStateException("Cannot bind to " + target, ex); + } + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java new file mode 100644 index 00000000000..9d34a4212df --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java @@ -0,0 +1,45 @@ +/* + * 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.info; + +import java.util.Map; + +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * A {@link InfoContributor} that provides all environment entries prefixed with + * info. + * + * @author Meang Akira Tanaka + * @author Stephane Nicoll + * @since 1.4.0 + */ +public class EnvironmentInfoContributor extends AbstractEnvironmentInfoContributor { + + private final Map info; + + public EnvironmentInfoContributor(ConfigurableEnvironment environment) { + super(environment); + this.info = extract("info"); + } + + @Override + public void contribute(Info.Builder builder) { + builder.withDetails(this.info); + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java deleted file mode 100644 index 062f8d75eb4..00000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.info; - -import java.util.LinkedHashMap; -import java.util.Map; - -import org.springframework.boot.bind.PropertiesConfigurationFactory; -import org.springframework.core.env.ConfigurableEnvironment; - -/** - * A {@link InfoProvider} that provides all environment entries prefixed with - * info. - * - * @author Meang Akira Tanaka - * @since 1.3.0 - */ -public class EnvironmentInfoProvider implements InfoProvider { - - private final ConfigurableEnvironment environment; - - private final Info info; - - public EnvironmentInfoProvider(ConfigurableEnvironment environment) throws Exception { - this.environment = environment; - this.info = new Info(extractInfoFromEnvironment()); - } - - @Override - public String name() { - return "environment"; - } - - @Override - public Info provide() { - return this.info; - } - - private Map extractInfoFromEnvironment() throws Exception { - PropertiesConfigurationFactory> factory = new PropertiesConfigurationFactory>( - new LinkedHashMap()); - factory.setTargetName("info"); - factory.setPropertySources(this.environment.getPropertySources()); - return factory.getObject(); - } -} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java index 064e966685f..1895eff4175 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java @@ -16,7 +16,7 @@ package org.springframework.boot.actuate.info; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import com.fasterxml.jackson.annotation.JsonAnyGetter; @@ -24,22 +24,23 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; /** - * Carries information from a specific info provider. + * Carries information of the application. + *

+ * Each detail element can singular or a hierarchical object such as a pojo or a nested + * Map. * * @author Meang Akira Tanaka - * @since 1.3.0 - * @see org.springframework.boot.actuate.endpoint.InfoEndpoint + * @author Stephane Nicoll + * @since 1.4.0 */ @JsonInclude(Include.NON_EMPTY) public final class Info { - private final Map details = new HashMap(); + private final Map details; - public Info() { - } - - public Info(Map details) { - this.details.putAll(details); + private Info(Builder builder) { + this.details = new LinkedHashMap(); + this.details.putAll(builder.content); } /** @@ -51,13 +52,17 @@ public final class Info { return this.details; } - public void put(String infoId, Object value) { - this.details.put(infoId, value); + public Object get(String id) { + return this.details.get(id); } @SuppressWarnings("unchecked") - public T get(String infoId) { - return (T) this.details.get(infoId); + public T get(String id, Class type) { + Object value = get(id); + if (value != null && type != null && !type.isInstance(value)) { + throw new IllegalStateException("Info entry is not of required type [" + type.getName() + "]: " + value); + } + return (T) value; } @Override @@ -81,4 +86,47 @@ public final class Info { public String toString() { return getDetails().toString(); } + + /** + * Builder for creating immutable {@link Info} instances. + */ + public static class Builder { + + private final Map content; + + public Builder() { + this.content = new LinkedHashMap(); + } + + /** + * Record detail using {@code key} and {@code value}. + * @param key the detail key + * @param data the detail data + * @return this {@link Builder} instance + */ + public Builder withDetail(String key, Object data) { + this.content.put(key, data); + return this; + } + + /** + * Record several details. + * @param details the details + * @return this {@link Builder} instance + * @see #withDetail(String, Object) + */ + public Builder withDetails(Map details) { + this.content.putAll(details); + return this; + } + + /** + * Create a new {@link Info} instance base on the state of this builder. + * @return a new {@link Info} instance + */ + public Info build() { + return new Info(this); + } + + } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java similarity index 71% rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java index 1a76553676b..f4c7628e755 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java @@ -17,18 +17,17 @@ package org.springframework.boot.actuate.info; /** - * information provider for the info endpoint. + * Contributes additional info details. * - * @author Meang Akira Tanaka + * @author Stephane Nicoll + * @since 1.4.0 */ -public interface InfoProvider { - - String name(); +public interface InfoContributor { /** - * Return the {@link Info} instance. - * @return a collection of information + * Contributes additional details using the specified {@link Info.Builder Builder}. + * @param builder the builder to use */ - Info provide(); + void contribute(Info.Builder builder); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java deleted file mode 100644 index 8b12488b7b1..00000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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.info; - -import java.util.Properties; - -import org.springframework.boot.bind.PropertiesConfigurationFactory; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PropertiesLoaderUtils; - -/** - * A {@link InfoProvider} that provides git information extracted from the - * git.properties file generated by the maven plugin - * pl.project13.maven:git-commit-id-plugin. - * - * @author Meang Akira Tanaka - * @since 1.3.0 - */ -public class ScmGitPropertiesInfoProvider implements InfoProvider { - - private final Resource gitPropertiesResource; - - private final GitInfo gitInfo; - - public ScmGitPropertiesInfoProvider(Resource gitPropertiesResource) throws Exception { - this.gitPropertiesResource = gitPropertiesResource; - this.gitInfo = extractGitInfo(); - } - - @Override - public String name() { - return "git"; - } - - @Override - public Info provide() { - if (this.gitInfo == null) { - return null; - } - - Info result = new Info(); - - result.put("branch", this.gitInfo.getBranch()); - result.put("commit", this.gitInfo.getCommit()); - - return result; - } - - - private GitInfo extractGitInfo() throws Exception { - PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory( - new GitInfo()); - factory.setTargetName("git"); - Properties properties = new Properties(); - if (this.gitPropertiesResource.exists()) { - properties = PropertiesLoaderUtils.loadProperties(this.gitPropertiesResource); - } - else { - return null; - } - factory.setProperties(properties); - return factory.getObject(); - } - - - /** - * Git info. - */ - public static class GitInfo { - - private String branch; - - private final Commit commit = new Commit(); - - public String getBranch() { - return this.branch; - } - - public void setBranch(String branch) { - this.branch = branch; - } - - public Commit getCommit() { - return this.commit; - } - - /** - * Commit information. - */ - public static class Commit { - - private String id; - - private String time; - - public String getId() { - return this.id == null ? "" - : (this.id.length() > 7 ? this.id.substring(0, 7) : this.id); - } - - public void setId(String id) { - this.id = id; - } - - public String getTime() { - return this.time; - } - - public void setTime(String time) { - this.time = time; - } - - } - - } -} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SimpleInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SimpleInfoContributor.java new file mode 100644 index 00000000000..b6bd85cc197 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SimpleInfoContributor.java @@ -0,0 +1,46 @@ +/* + * 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.info; + +import org.springframework.util.Assert; + +/** + * A simple {@link InfoContributor} that exposes a single detail. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +public class SimpleInfoContributor implements InfoContributor { + + private final String prefix; + + private final Object detail; + + public SimpleInfoContributor(String prefix, Object detail) { + Assert.notNull(prefix, "Prefix must not be null"); + this.prefix = prefix; + this.detail = detail; + } + + @Override + public void contribute(Info.Builder builder) { + if (this.detail != null) { + builder.withDetail(this.prefix, this.detail); + } + } + +} diff --git a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json index fd726b13c20..674c2c69da5 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -123,6 +123,24 @@ "description": "Enable Mail health check.", "defaultValue": true }, + { + "name": "management.info.defaults.enabled", + "type": "java.lang.Boolean", + "description": "Enable default info contributors.", + "defaultValue": true + }, + { + "name": "management.info.env.enabled", + "type": "java.lang.Boolean", + "description": "Enable environment info.", + "defaultValue": true + }, + { + "name": "management.info.git.enabled", + "type": "java.lang.Boolean", + "description": "Enable git info.", + "defaultValue": true + }, { "name": "spring.git.properties", "type": "java.lang.String", diff --git a/spring-boot-actuator/src/main/resources/META-INF/spring.factories b/spring-boot-actuator/src/main/resources/META-INF/spring.factories index 40a1efafd0d..41a4f14cede 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/spring.factories +++ b/spring-boot-actuator/src/main/resources/META-INF/spring.factories @@ -6,7 +6,7 @@ org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration,\ -org.springframework.boot.actuate.autoconfigure.InfoProviderAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.InfoContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration,\ diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java index b42bb062ca1..0c3eab82612 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java @@ -16,9 +16,12 @@ package org.springframework.boot.actuate.autoconfigure; +import java.io.IOException; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; import org.junit.After; import org.junit.Test; @@ -37,16 +40,24 @@ import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration; +import org.springframework.boot.autoconfigure.info.ProjectInfoProperties; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; +import org.springframework.boot.bind.PropertiesConfigurationFactory; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.validation.BindException; import static org.assertj.core.api.Assertions.assertThat; @@ -139,10 +150,11 @@ public class EndpointAutoConfigurationTests { } @Test - public void testInfoEndpointConfiguration() throws Exception { + public void testInfoEndpoint() throws Exception { this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "info.foo:bar"); - this.context.register(ProjectInfoAutoConfiguration.class, EndpointAutoConfiguration.class); + this.context.register(ProjectInfoAutoConfiguration.class, + InfoContributorAutoConfiguration.class, EndpointAutoConfiguration.class); this.context.refresh(); InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); @@ -152,17 +164,34 @@ public class EndpointAutoConfigurationTests { } @Test - public void testNoGitProperties() throws Exception { + public void testInfoEndpointNoGitProperties() throws Exception { this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "spring.info.git.location:classpath:nonexistent"); - this.context.register(EndpointAutoConfiguration.class); + this.context.register(InfoContributorAutoConfiguration.class, EndpointAutoConfiguration.class); this.context.refresh(); InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); assertThat(endpoint).isNotNull(); assertThat(endpoint.invoke().get("git")).isNull(); } + @Test + public void testInfoEndpointOrdering() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, "info.name:foo"); + this.context.register(CustomInfoContributorsConfig.class, ProjectInfoAutoConfiguration.class, + InfoContributorAutoConfiguration.class, EndpointAutoConfiguration.class); + this.context.refresh(); + + InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); + Info info = endpoint.invoke(); + assertThat(info).isNotNull(); + assertThat(info.get("name")).isEqualTo("foo"); + assertThat(info.get("version")).isEqualTo("1.0"); + Object git = info.get("git"); + assertThat(git).isInstanceOf(Map.class); + } + @Test public void testFlywayEndpoint() { this.context = new AnnotationConfigApplicationContext(); @@ -206,4 +235,53 @@ public class EndpointAutoConfigurationTests { } } + + @Configuration + static class CustomInfoContributorsConfig { + + @Bean + @Order(InfoContributorAutoConfiguration.DEFAULT_ORDER - 1) + public InfoContributor myInfoContributor() { + return new InfoContributor() { + @Override + public void contribute(Info.Builder builder) { + builder.withDetail("name", "bar"); + builder.withDetail("version", "1.0"); + } + }; + } + + @Bean + @Order(InfoContributorAutoConfiguration.DEFAULT_ORDER + 1) + public InfoContributor myAnotherContributor(ProjectInfoProperties properties) + throws IOException, BindException { + return new GitFullInfoContributor(properties.getGit().getLocation()); + } + + private static class GitFullInfoContributor implements InfoContributor { + + private final Map content; + + GitFullInfoContributor(Resource location) throws BindException, IOException { + this.content = new LinkedHashMap(); + if (location.exists()) { + PropertiesConfigurationFactory> factory + = new PropertiesConfigurationFactory>(this.content); + factory.setTargetName("git"); + Properties gitInfoProperties = PropertiesLoaderUtils + .loadProperties(location); + factory.setProperties(gitInfoProperties); + factory.bindPropertiesToTarget(); + } + } + + @Override + public void contribute(Info.Builder builder) { + if (!this.content.isEmpty()) { + builder.withDetail("git", this.content); + } + } + } + + } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfigurationTests.java new file mode 100644 index 00000000000..0f0c5cfb57e --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfigurationTests.java @@ -0,0 +1,125 @@ +/* + * 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.util.Map; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.boot.autoconfigure.info.GitInfo; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link InfoContributorAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class InfoContributorAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void disableEnvContributor() { + load("management.info.env.enabled:false"); + Map beans = this.context + .getBeansOfType(InfoContributor.class); + assertThat(beans).hasSize(0); + } + + @Test + public void defaultInfoContributorsDisabled() { + load("management.info.defaults.enabled:false"); + Map beans = this.context + .getBeansOfType(InfoContributor.class); + assertThat(beans).hasSize(0); + } + + @Test + public void defaultInfoContributorsDisabledWithCustomOne() { + load(CustomInfoProviderConfiguration.class, + "management.info.defaults.enabled:false"); + Map beans = this.context + .getBeansOfType(InfoContributor.class); + assertThat(beans).hasSize(1); + assertThat(this.context.getBean("customInfoContributor")) + .isSameAs(beans.values().iterator().next()); + } + + @Test + public void gitInfoAvailable() { + load(GitInfoConfiguration.class); + Map beans = this.context + .getBeansOfType(InfoContributor.class); + assertThat(beans).containsKeys("gitInfoContributor"); + } + + private void load(String... environment) { + load(null, environment); + } + + private void load(Class config, String... environment) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + if (config != null) { + context.register(config); + } + context.register(InfoContributorAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(context, environment); + context.refresh(); + this.context = context; + } + + @Configuration + static class GitInfoConfiguration { + + @Bean + public GitInfo gitInfo() { + GitInfo gitInfo = new GitInfo(); + gitInfo.setBranch("master"); + gitInfo.getCommit().setId("abcdefg"); + return gitInfo; + } + } + + @Configuration + static class CustomInfoProviderConfiguration { + + @Bean + public InfoContributor customInfoContributor() { + return new InfoContributor() { + @Override + public void contribute(Info.Builder builder) { + } + }; + } + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java index b88294eb0a5..29306e73dd1 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java @@ -16,12 +16,12 @@ package org.springframework.boot.actuate.endpoint; -import java.util.Map; +import java.util.List; import org.junit.Test; import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -43,7 +43,7 @@ public class InfoEndpointTests extends AbstractEndpointTests { @Test public void invoke() throws Exception { - Info actual = getEndpointBean().invoke().get("environment"); + Info actual = getEndpointBean().invoke(); assertThat(actual.get("key1")).isEqualTo("value1"); } @@ -52,29 +52,22 @@ public class InfoEndpointTests extends AbstractEndpointTests { public static class Config { @Bean - public InfoProvider infoProvider() { - return new InfoProvider() { + public InfoContributor infoProvider() { + return new InfoContributor() { @Override - public String name() { - return "environment"; - } - - @Override - public Info provide() { - Info result = new Info(); - result.put("key1", "value1"); - - return result; + public void contribute(Info.Builder builder) { + builder.withDetail("key1", "value1"); } }; } - @Bean - public InfoEndpoint endpoint(Map infoProviders) { - return new InfoEndpoint(infoProviders); + public InfoEndpoint endpoint(List infoContributors) { + return new InfoEndpoint(infoContributors); } + } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java index d122c6621c1..6cb5d009c36 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java @@ -16,9 +16,10 @@ package org.springframework.boot.actuate.endpoint.mvc; +import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.Map; -import org.elasticsearch.common.collect.Maps; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -29,7 +30,7 @@ import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties import org.springframework.boot.actuate.endpoint.InfoEndpoint; import org.springframework.boot.actuate.endpoint.mvc.InfoMvcEndpointTests.TestConfiguration; import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; @@ -53,6 +54,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * Tests for {@link InfoMvcEndpointTests} * * @author Meang Akira Tanaka + * @author Stephane Nicoll */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = {TestConfiguration.class}) @@ -75,8 +77,10 @@ public class InfoMvcEndpointTests { public void home() throws Exception { this.mvc.perform(get("/info")).andExpect(status().isOk()) .andExpect(content().string( - containsString("\"beanName2\":{\"key22\":\"value22\",\"key21\":\"value21\"}," + - "\"beanName1\":{\"key12\":\"value12\",\"key11\":\"value11\"}"))); + containsString("\"beanName1\":{\"key11\":\"value11\",\"key12\":\"value12\"}") + )) + .andExpect(content().string( + containsString("\"beanName2\":{\"key21\":\"value21\",\"key22\":\"value22\"}"))); } @Import({JacksonAutoConfiguration.class, @@ -87,47 +91,36 @@ public class InfoMvcEndpointTests { @Configuration public static class TestConfiguration { - private Map infoProviders = Maps.newHashMap(); - - public TestConfiguration() { - InfoProvider infoProvider1 = new InfoProvider() { + @Bean + public InfoEndpoint endpoint() { + return new InfoEndpoint(Arrays.asList(beanName1(), beanName2())); + } - @Override - public Info provide() { - Info result = new Info(); - result.put("key11", "value11"); - result.put("key12", "value12"); - return result; - } + @Bean + public InfoContributor beanName1() { + return new InfoContributor() { @Override - public String name() { - return "beanName1"; + public void contribute(Info.Builder builder) { + Map content = new LinkedHashMap(); + content.put("key11", "value11"); + content.put("key12", "value12"); + builder.withDetail("beanName1", content); } }; - this.infoProviders.put("beanName1", infoProvider1); - - InfoProvider infoProvider2 = new InfoProvider() { - - @Override - public Info provide() { - Info result = new Info(); - result.put("key21", "value21"); - result.put("key22", "value22"); - return result; - } + } + @Bean + public InfoContributor beanName2() { + return new InfoContributor() { @Override - public String name() { - return "beanName2"; + public void contribute(Info.Builder builder) { + Map content = new LinkedHashMap(); + content.put("key21", "value21"); + content.put("key22", "value22"); + builder.withDetail("beanName2", content); } }; - this.infoProviders.put("beanName2", infoProvider2); - } - - @Bean - public InfoEndpoint endpoint() { - return new InfoEndpoint(this.infoProviders); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java index 9cb7bc6e9fa..8d48d92c357 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java @@ -16,9 +16,8 @@ package org.springframework.boot.actuate.endpoint.mvc; -import java.util.Map; +import java.util.Collections; -import org.elasticsearch.common.collect.Maps; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -28,7 +27,7 @@ import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfigur import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.endpoint.InfoEndpoint; import org.springframework.boot.actuate.endpoint.mvc.InfoMvcEndpointWithoutAnyInfoProvidersTests.TestConfiguration; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; @@ -79,11 +78,9 @@ public class InfoMvcEndpointWithoutAnyInfoProvidersTests { @Configuration public static class TestConfiguration { - private Map infoProviders = Maps.newHashMap(); - @Bean public InfoEndpoint endpoint() { - return new InfoEndpoint(this.infoProviders); + return new InfoEndpoint(Collections.emptyList()); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoContributorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoContributorTests.java new file mode 100644 index 00000000000..5b1d460d146 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoContributorTests.java @@ -0,0 +1,60 @@ +/* + * 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.info; + +import org.junit.Test; + +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.StandardEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link EnvironmentInfoContributor} + */ +public class EnvironmentInfoContributorTests { + + private final StandardEnvironment environment = new StandardEnvironment(); + + @Test + public void extractOnlyInfoProperty() { + EnvironmentTestUtils.addEnvironment(this.environment, + "info.app=my app", "info.version=1.0.0", "foo=bar"); + + Info actual = contributeFrom(this.environment); + assertThat(actual.get("app", String.class)).isEqualTo("my app"); + assertThat(actual.get("version", String.class)).isEqualTo("1.0.0"); + assertThat(actual.getDetails().size()).isEqualTo(2); + } + + @Test + public void extractNoEntry() { + EnvironmentTestUtils.addEnvironment(this.environment, "foo=bar"); + + Info actual = contributeFrom(this.environment); + assertThat(actual.getDetails().size()).isEqualTo(0); + } + + private static Info contributeFrom(ConfigurableEnvironment environment) { + EnvironmentInfoContributor contributor = new EnvironmentInfoContributor(environment); + Info.Builder builder = new Info.Builder(); + contributor.contribute(builder); + return builder.build(); + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java deleted file mode 100644 index e9d775ada11..00000000000 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.info; - -import java.util.Properties; - -import org.junit.Test; - -import org.springframework.core.env.PropertiesPropertySource; -import org.springframework.core.env.PropertySource; -import org.springframework.core.env.StandardEnvironment; - -import static org.assertj.core.api.Assertions.assertThat; - -public class EnvironmentInfoProviderTests { - - @Test - public void provide_HasTwoRelevantEntries_ShowOnlyRelevantEntries() throws Exception { - String expectedAppName = "my app name"; - String expectedLanguage = "da-DK"; - - Properties properties = new Properties(); - properties.setProperty("info.app", expectedAppName); - properties.setProperty("info.lang", expectedLanguage); - properties.setProperty("logging.path", "notExpected"); - - PropertySource propertySource = new PropertiesPropertySource("mysettings", properties); - - StandardEnvironment environment = new StandardEnvironment(); - environment.getPropertySources().addLast(propertySource); - - EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(environment); - - Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size()).isEqualTo(2); - assertThat((String) actual.get("app")).isEqualTo(expectedAppName); - assertThat((String) actual.get("lang")).isEqualTo(expectedLanguage); - } - - @Test - public void provide_HasNoRelevantEntries_NoEntries() throws Exception { - Properties properties = new Properties(); - properties.setProperty("logging.path", "notExpected"); - - PropertySource propertySource = new PropertiesPropertySource("mysettings", properties); - - StandardEnvironment environment = new StandardEnvironment(); - environment.getPropertySources().addLast(propertySource); - - EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(environment); - - Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size()).isEqualTo(0); - } - - - @Test - public void provide_HasNoEntries_NoEntries() throws Exception { - EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(new StandardEnvironment()); - - Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size()).isEqualTo(0); - } - -} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java deleted file mode 100644 index 1a6dba70555..00000000000 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.info; - -import org.junit.Test; - -import org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider.GitInfo.Commit; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -public class ScmGitPropertiesInfoProviderTests { - - - @Test - public void provide_HasBadFormatButExists_EmptyInfoReturned() throws Exception { - Resource resource = new ByteArrayResource("GARBAGE".getBytes()); - ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); - - Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual).isNotNull(); - assertThat((String) actual.get("branch")).isNull(); - Commit actualCommit = actual.get("commit"); - assertThat(actualCommit).isNotNull(); - assertThat(actualCommit.getId()).isEqualTo(""); - assertThat(actualCommit.getTime()).isNull(); - } - - @Test - public void provide_HasValidFormat_ExpectedDataReturned() throws Exception { - String gitProperties = "git.commit.id.abbrev=e02a4f3\r\n" - + "git.commit.user.email=dsyer@vmware.com\r\n" - + "git.commit.message.full=Update Spring\r\n" - + "git.commit.id=e02a4f3b6f452cdbf6dd311f1362679eb4c31ced\r\n" - + "git.commit.message.short=Update Spring\r\n" - + "git.commit.user.name=Dave Syer\r\n" - + "git.build.user.name=Dave Syer\r\n" - + "git.build.user.email=dsyer@vmware.com\r\n" - + "git.branch=develop\r\n" - + "git.commit.time=2013-04-24T08\\:42\\:13+0100\r\n" - + "git.build.time=2013-05-23T09\\:26\\:42+0100\r\n"; - - Resource resource = new ByteArrayResource(gitProperties.getBytes()); - ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); - - Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual).isNotNull(); - assertThat((String) actual.get("branch")).isEqualTo("develop"); - Commit actualCommit = actual.get("commit"); - assertThat(actualCommit).isNotNull(); - assertThat(actualCommit.getId()).isEqualTo("e02a4f3"); - assertThat(actualCommit.getTime()).isEqualTo("2013-04-24T08:42:13+0100"); - } - - - @Test - public void provide_HasValidFormatButMissingCommitTime_ExpectedDataReturnedWithoutCommitTime() throws Exception { - String gitProperties = "git.commit.id.abbrev=e02a4f3\r\n" - + "git.commit.user.email=dsyer@vmware.com\r\n" - + "git.commit.message.full=Update Spring\r\n" - + "git.commit.id=e02a4f3b6f452cdbf6dd311f1362679eb4c31ced\r\n" - + "git.commit.message.short=Update Spring\r\n" - + "git.commit.user.name=Dave Syer\r\n" - + "git.build.user.name=Dave Syer\r\n" - + "git.build.user.email=dsyer@vmware.com\r\n" - + "git.branch=develop\r\n" - + "git.build.time=2013-05-23T09\\:26\\:42+0100\r\n"; - - Resource resource = new ByteArrayResource(gitProperties.getBytes()); - ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); - - Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual).isNotNull(); - assertThat((String) actual.get("branch")).isEqualTo("develop"); - Commit actualCommit = (Commit) actual.get("commit"); - assertThat(actualCommit).isNotNull(); - assertThat(actualCommit.getId()).isEqualTo("e02a4f3"); - assertThat(actualCommit.getTime()).isNull(); - } - - @Test - public void provide_DoesNotExists_NullReturned() throws Exception { - Resource resource = mock(Resource.class); - given(resource.exists()).willReturn(false); - ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); - - Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual).isNull(); - } - -} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SimpleInfoContributorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SimpleInfoContributorTests.java new file mode 100644 index 00000000000..9b75e4f7b32 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SimpleInfoContributorTests.java @@ -0,0 +1,56 @@ +/* + * 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.info; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SimpleInfoContributor}. + * + * @author Stephane Nicoll + */ +public class SimpleInfoContributorTests { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + @Test + public void prefixIsMandatory() { + this.thrown.expect(IllegalArgumentException.class); + new SimpleInfoContributor(null, new Object()); + } + + @Test + public void mapSimpleObject() { + Object o = new Object(); + Info info = contributeFrom("test", o); + assertThat(info.get("test")).isSameAs(o); + } + + + private static Info contributeFrom(String prefix, Object detail) { + SimpleInfoContributor contributor = new SimpleInfoContributor(prefix, detail); + Info.Builder builder = new Info.Builder(); + contributor.contribute(builder); + return builder.build(); + } + +} diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 94dd7e18998..7670bbba3fa 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -884,6 +884,11 @@ content into your application; rather pick only the properties that you need. management.health.solr.enabled=true # Enable Solr health check. management.health.status.order=DOWN, OUT_OF_SERVICE, UNKNOWN, UP # Comma-separated list of health statuses in order of severity. + # INFO CONTRIBUTORS + management.info.defaults.enabled=true # Enable default health indicators. + management.info.env.enabled=true # Enable environment info. + management.info.git.enabled=true # Enable git info. + # TRACING (({sc-spring-boot-actuator}/trace/TraceProperties.{sc-ext}[TraceProperties]) management.trace.include=request-headers,response-headers,errors # Items to be included in the trace. diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoContributor.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoContributor.java new file mode 100644 index 00000000000..4d976d69302 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoContributor.java @@ -0,0 +1,34 @@ +/* + * 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 sample.actuator; + +import java.util.Collections; + +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.stereotype.Component; + +@Component +public class ExampleInfoContributor implements InfoContributor { + + @Override + public void contribute(Info.Builder builder) { + builder.withDetail("example", + Collections.singletonMap("someKey", "someValue")); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java deleted file mode 100644 index 822d5b8d33b..00000000000 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java +++ /dev/null @@ -1,21 +0,0 @@ -package sample.actuator; - -import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoProvider; -import org.springframework.stereotype.Component; - -@Component -public class ExampleInfoProvider implements InfoProvider { - - @Override - public Info provide() { - Info result = new Info(); - result.put("somekey", "somevalue"); - return result; - } - - @Override - public String name() { - return "example"; - } -} diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java index 2277acbfc3d..436b564db63 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java @@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Basic integration tests for service demo application. * * @author Dave Syer + * @author Stephane Nicoll */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(SampleActuatorApplication.class) @@ -145,6 +146,8 @@ public class SampleActuatorApplicationTests { assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()) .contains("\"artifact\":\"spring-boot-sample-actuator\""); + assertThat(entity.getBody()) + .contains("\"someKey\":\"someValue\""); } @Test