diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthContributorRegistryHealthIndicatorRegistryAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthContributorRegistryHealthIndicatorRegistryAdapter.java new file mode 100644 index 0000000000..41c38f3ccb --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthContributorRegistryHealthIndicatorRegistryAdapter.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.health; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.actuate.health.HealthContributor; +import org.springframework.boot.actuate.health.HealthContributorRegistry; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; +import org.springframework.boot.actuate.health.NamedContributor; +import org.springframework.util.Assert; + +/** + * Adapter class to convert a {@link HealthContributorRegistry} to a legacy + * {@link HealthIndicatorRegistry}. + * + * @author Phillip Webb + */ +@SuppressWarnings("deprecation") +class HealthContributorRegistryHealthIndicatorRegistryAdapter implements HealthIndicatorRegistry { + + private final HealthContributorRegistry contributorRegistry; + + HealthContributorRegistryHealthIndicatorRegistryAdapter(HealthContributorRegistry contributorRegistry) { + Assert.notNull(contributorRegistry, "ContributorRegistry must not be null"); + this.contributorRegistry = contributorRegistry; + } + + @Override + public void register(String name, HealthIndicator healthIndicator) { + this.contributorRegistry.registerContributor(name, healthIndicator); + } + + @Override + public HealthIndicator unregister(String name) { + HealthContributor contributor = this.contributorRegistry.unregisterContributor(name); + if (contributor instanceof HealthIndicator) { + return (HealthIndicator) contributor; + } + return null; + } + + @Override + public HealthIndicator get(String name) { + HealthContributor contributor = this.contributorRegistry.getContributor(name); + if (contributor instanceof HealthIndicator) { + return (HealthIndicator) contributor; + } + return null; + } + + @Override + public Map getAll() { + Map all = new LinkedHashMap(); + for (NamedContributor namedContributor : this.contributorRegistry) { + if (namedContributor.getContributor() instanceof HealthIndicator) { + all.put(namedContributor.getName(), (HealthIndicator) namedContributor.getContributor()); + } + } + return all; + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfiguration.java index e0d17b6320..972ee5d3a6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfiguration.java @@ -20,6 +20,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.condition.Conditi import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -32,11 +33,20 @@ import org.springframework.context.annotation.Import; * @since 2.0.0 */ @Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties(HealthEndpointProperties.class) @ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class) +@EnableConfigurationProperties @Import({ LegacyHealthEndpointAdaptersConfiguration.class, LegacyHealthEndpointCompatibilityConfiguration.class, HealthEndpointConfiguration.class, ReactiveHealthEndpointConfiguration.class, HealthEndpointWebExtensionConfiguration.class, HealthEndpointReactiveWebExtensionConfiguration.class }) public class HealthEndpointAutoConfiguration { + @Bean + @SuppressWarnings("deprecation") + HealthEndpointProperties healthEndpointProperties(HealthIndicatorProperties healthIndicatorProperties) { + HealthEndpointProperties healthEndpointProperties = new HealthEndpointProperties(); + healthEndpointProperties.getStatus().getOrder().addAll(healthIndicatorProperties.getOrder()); + healthEndpointProperties.getStatus().getHttpMapping().putAll(healthIndicatorProperties.getHttpMapping()); + return healthEndpointProperties; + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorProperties.java index 37019a17f1..b72d49f036 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorProperties.java @@ -16,9 +16,12 @@ package org.springframework.boot.actuate.autoconfigure.health; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; /** @@ -29,26 +32,25 @@ import org.springframework.boot.context.properties.DeprecatedConfigurationProper * @deprecated since 2.2.0 in favor of {@link HealthEndpointProperties} */ @Deprecated +@ConfigurationProperties(prefix = "management.health.status") public class HealthIndicatorProperties { - private final HealthEndpointProperties healthEndpointProperties; + private List order = new ArrayList<>(); - HealthIndicatorProperties(HealthEndpointProperties healthEndpointProperties) { - this.healthEndpointProperties = healthEndpointProperties; - } + private final Map httpMapping = new LinkedHashMap(); @DeprecatedConfigurationProperty(replacement = "management.endpoint.health.status.order") public List getOrder() { - return this.healthEndpointProperties.getStatus().getOrder(); + return this.order; } - public void setOrder(List statusOrder) { - this.healthEndpointProperties.getStatus().setOrder(statusOrder); + public void setOrder(List order) { + this.order = order; } @DeprecatedConfigurationProperty(replacement = "management.endpoint.health.status.http-mapping") public Map getHttpMapping() { - return this.healthEndpointProperties.getStatus().getHttpMapping(); + return this.httpMapping; } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthProperties.java index 7ce78e2d31..9ed9bbcf6f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthProperties.java @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.health; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -76,7 +77,7 @@ public abstract class HealthProperties { /** * Comma-separated list of health statuses in order of severity. */ - private List order = null; + private List order = new ArrayList<>(); /** * Mapping of health statuses to HTTP status codes. By default, registered health diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/LegacyHealthEndpointCompatibilityConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/LegacyHealthEndpointCompatibilityConfiguration.java index 89c5377b8f..3b01411f07 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/LegacyHealthEndpointCompatibilityConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/LegacyHealthEndpointCompatibilityConfiguration.java @@ -16,11 +16,18 @@ package org.springframework.boot.actuate.autoconfigure.health; +import io.micrometer.shaded.reactor.core.publisher.Mono; + import org.springframework.boot.actuate.health.HealthAggregator; +import org.springframework.boot.actuate.health.HealthContributorRegistry; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; import org.springframework.boot.actuate.health.HealthStatusHttpMapper; import org.springframework.boot.actuate.health.OrderedHealthAggregator; +import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry; +import org.springframework.boot.actuate.health.ReactiveHealthIndicatorRegistry; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -32,12 +39,12 @@ import org.springframework.context.annotation.Configuration; */ @Configuration(proxyBeanMethods = false) @SuppressWarnings("deprecation") +@EnableConfigurationProperties class LegacyHealthEndpointCompatibilityConfiguration { @Bean - @ConfigurationProperties(prefix = "management.health.status") - HealthIndicatorProperties healthIndicatorProperties(HealthEndpointProperties healthEndpointProperties) { - return new HealthIndicatorProperties(healthEndpointProperties); + HealthIndicatorProperties healthIndicatorProperties() { + return new HealthIndicatorProperties(); } @Bean @@ -60,4 +67,25 @@ class LegacyHealthEndpointCompatibilityConfiguration { return mapper; } + @Bean + @ConditionalOnMissingBean(HealthIndicatorRegistry.class) + HealthContributorRegistryHealthIndicatorRegistryAdapter healthIndicatorRegistry( + HealthContributorRegistry healthContributorRegistry) { + return new HealthContributorRegistryHealthIndicatorRegistryAdapter(healthContributorRegistry); + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(Mono.class) + static class LegacyReactiveHealthEndpointCompatibilityConfiguration { + + @Bean + @ConditionalOnMissingBean(ReactiveHealthIndicatorRegistry.class) + ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter reactiveHealthIndicatorRegistry( + ReactiveHealthContributorRegistry reactiveHealthContributorRegistry) { + return new ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter( + reactiveHealthContributorRegistry); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter.java new file mode 100644 index 0000000000..5b1cdce8d8 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter.java @@ -0,0 +1,83 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.health; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.actuate.health.HealthContributorRegistry; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; +import org.springframework.boot.actuate.health.NamedContributor; +import org.springframework.boot.actuate.health.ReactiveHealthContributor; +import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthIndicatorRegistry; +import org.springframework.util.Assert; + +/** + * Adapter class to convert a {@link HealthContributorRegistry} to a legacy + * {@link HealthIndicatorRegistry}. + * + * @author Phillip Webb + */ +@SuppressWarnings("deprecation") +class ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter + implements ReactiveHealthIndicatorRegistry { + + private final ReactiveHealthContributorRegistry contributorRegistry; + + ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter( + ReactiveHealthContributorRegistry contributorRegistry) { + Assert.notNull(contributorRegistry, "ContributorRegistry must not be null"); + this.contributorRegistry = contributorRegistry; + } + + @Override + public void register(String name, ReactiveHealthIndicator healthIndicator) { + this.contributorRegistry.registerContributor(name, healthIndicator); + } + + @Override + public ReactiveHealthIndicator unregister(String name) { + ReactiveHealthContributor contributor = this.contributorRegistry.unregisterContributor(name); + if (contributor instanceof ReactiveHealthIndicator) { + return (ReactiveHealthIndicator) contributor; + } + return null; + } + + @Override + public ReactiveHealthIndicator get(String name) { + ReactiveHealthContributor contributor = this.contributorRegistry.getContributor(name); + if (contributor instanceof ReactiveHealthIndicator) { + return (ReactiveHealthIndicator) contributor; + } + return null; + } + + @Override + public Map getAll() { + Map all = new LinkedHashMap<>(); + for (NamedContributor namedContributor : this.contributorRegistry) { + if (namedContributor.getContributor() instanceof ReactiveHealthIndicator) { + all.put(namedContributor.getName(), (ReactiveHealthIndicator) namedContributor.getContributor()); + } + } + return all; + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthContributorRegistryHealthIndicatorRegistryAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthContributorRegistryHealthIndicatorRegistryAdapterTests.java new file mode 100644 index 0000000000..e815ccfc81 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthContributorRegistryHealthIndicatorRegistryAdapterTests.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.health; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.health.CompositeHealthContributor; +import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry; +import org.springframework.boot.actuate.health.HealthContributorRegistry; +import org.springframework.boot.actuate.health.HealthIndicator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.entry; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link HealthContributorRegistryHealthIndicatorRegistryAdapter}. + * + * @author Phillip Webb + */ +class HealthContributorRegistryHealthIndicatorRegistryAdapterTests { + + private HealthContributorRegistry contributorRegistry = new DefaultHealthContributorRegistry(); + + private HealthContributorRegistryHealthIndicatorRegistryAdapter adapter = new HealthContributorRegistryHealthIndicatorRegistryAdapter( + this.contributorRegistry); + + @Test + void createWhenContributorRegistryIsNullThrowsException() { + assertThatIllegalArgumentException() + .isThrownBy(() -> new HealthContributorRegistryHealthIndicatorRegistryAdapter(null)) + .withMessage("ContributorRegistry must not be null"); + } + + @Test + void registerDelegatesToContributorRegistry() { + HealthIndicator healthIndicator = mock(HealthIndicator.class); + this.adapter.register("test", healthIndicator); + assertThat(this.contributorRegistry.getContributor("test")).isSameAs(healthIndicator); + } + + @Test + void unregisterWhenDelegatesToContributorRegistry() { + HealthIndicator healthIndicator = mock(HealthIndicator.class); + this.contributorRegistry.registerContributor("test", healthIndicator); + HealthIndicator unregistered = this.adapter.unregister("test"); + assertThat(unregistered).isSameAs(healthIndicator); + assertThat(this.contributorRegistry.getContributor("test")).isNull(); + } + + @Test + void unregisterWhenContributorRegistryResultIsNotHealthIndicatorReturnsNull() { + CompositeHealthContributor healthContributor = mock(CompositeHealthContributor.class); + this.contributorRegistry.registerContributor("test", healthContributor); + HealthIndicator unregistered = this.adapter.unregister("test"); + assertThat(unregistered).isNull(); + assertThat(this.contributorRegistry.getContributor("test")).isNull(); + } + + @Test + void getDelegatesToContributorRegistry() { + HealthIndicator healthIndicator = mock(HealthIndicator.class); + this.contributorRegistry.registerContributor("test", healthIndicator); + assertThat(this.adapter.get("test")).isSameAs(healthIndicator); + } + + @Test + void getWhenContributorRegistryResultIsNotHealthIndicatorReturnsNull() { + CompositeHealthContributor healthContributor = mock(CompositeHealthContributor.class); + this.contributorRegistry.registerContributor("test", healthContributor); + assertThat(this.adapter.get("test")).isNull(); + } + + @Test + void getAllDelegatesContributorRegistry() { + HealthIndicator healthIndicator = mock(HealthIndicator.class); + this.contributorRegistry.registerContributor("test", healthIndicator); + Map all = this.adapter.getAll(); + assertThat(all).containsOnly(entry("test", healthIndicator)); + } + + @Test + void getAllWhenContributorRegistryContainsNonHealthIndicatorInstancesReturnsFilteredMap() { + CompositeHealthContributor healthContributor = mock(CompositeHealthContributor.class); + this.contributorRegistry.registerContributor("test1", healthContributor); + HealthIndicator healthIndicator = mock(HealthIndicator.class); + this.contributorRegistry.registerContributor("test2", healthIndicator); + Map all = this.adapter.getAll(); + assertThat(all).containsOnly(entry("test2", healthIndicator)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorRegistryInjectionIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorRegistryInjectionIntegrationTests.java new file mode 100644 index 0000000000..3d7469c50b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorRegistryInjectionIntegrationTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.health; + +import java.util.List; + +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.health.CompositeHealthIndicator; +import org.springframework.boot.actuate.health.HealthAggregator; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; +import org.springframework.boot.actuate.health.Status; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration test to ensure that the legacy {@link HealthIndicatorRegistry} can still be + * injected. + * + * @author Phillip Webb + */ +@SuppressWarnings("deprecation") +@SpringBootTest(webEnvironment = WebEnvironment.NONE) +public class HealthIndicatorRegistryInjectionIntegrationTests { + + // gh-18194 + + @Test + void meterRegistryBeanHasBeenConfigured(@Autowired MeterRegistry meterRegistry) { + assertThat(meterRegistry).isNotNull(); + assertThat(meterRegistry.get("health").gauge()).isNotNull(); + } + + @Configuration + @ImportAutoConfiguration({ HealthEndpointAutoConfiguration.class, HealthContributorAutoConfiguration.class, + CompositeMeterRegistryAutoConfiguration.class, MetricsAutoConfiguration.class }) + static class Config { + + Config(HealthAggregator healthAggregator, HealthIndicatorRegistry healthIndicatorRegistry, + List healthIndicators, MeterRegistry registry) { + CompositeHealthIndicator healthIndicator = new CompositeHealthIndicator(healthAggregator, + healthIndicatorRegistry); + for (int i = 0; i < healthIndicators.size(); i++) { + healthIndicatorRegistry.register(Integer.toString(i), healthIndicators.get(i)); + } + Gauge.builder("health", healthIndicator, this::getGuageValue) + .description("Spring boot health indicator. 3=UP, 2=OUT_OF_SERVICE, 1=DOWN, 0=UNKNOWN") + .strongReference(true).register(registry); + } + + private double getGuageValue(CompositeHealthIndicator health) { + Status status = health.health().getStatus(); + switch (status.getCode()) { + case "UP": + return 3; + case "OUT_OF_SERVICE": + return 2; + case "DOWN": + return 1; + case "UNKNOWN": + default: + return 0; + } + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapterTests.java new file mode 100644 index 0000000000..3d125ca0d0 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapterTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.health; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.health.CompositeReactiveHealthContributor; +import org.springframework.boot.actuate.health.DefaultReactiveHealthContributorRegistry; +import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.entry; +import static org.mockito.Mockito.mock; + +/** + * Test for + * {@link ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter}. + * + * @author Phillip Webb + */ +class ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapterTests { + + private ReactiveHealthContributorRegistry contributorRegistry = new DefaultReactiveHealthContributorRegistry(); + + private ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter adapter = new ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter( + this.contributorRegistry); + + @Test + void createWhenContributorRegistryIsNullThrowsException() { + assertThatIllegalArgumentException() + .isThrownBy(() -> new ReactiveHealthContributorRegistryReactiveHealthIndicatorRegistryAdapter(null)) + .withMessage("ContributorRegistry must not be null"); + } + + @Test + void registerDelegatesToContributorRegistry() { + ReactiveHealthIndicator healthIndicator = mock(ReactiveHealthIndicator.class); + this.adapter.register("test", healthIndicator); + assertThat(this.contributorRegistry.getContributor("test")).isSameAs(healthIndicator); + } + + @Test + void unregisterWhenDelegatesToContributorRegistry() { + ReactiveHealthIndicator healthIndicator = mock(ReactiveHealthIndicator.class); + this.contributorRegistry.registerContributor("test", healthIndicator); + ReactiveHealthIndicator unregistered = this.adapter.unregister("test"); + assertThat(unregistered).isSameAs(healthIndicator); + assertThat(this.contributorRegistry.getContributor("test")).isNull(); + } + + @Test + void unregisterWhenContributorRegistryResultIsNotHealthIndicatorReturnsNull() { + CompositeReactiveHealthContributor healthContributor = mock(CompositeReactiveHealthContributor.class); + this.contributorRegistry.registerContributor("test", healthContributor); + ReactiveHealthIndicator unregistered = this.adapter.unregister("test"); + assertThat(unregistered).isNull(); + assertThat(this.contributorRegistry.getContributor("test")).isNull(); + } + + @Test + void getDelegatesToContributorRegistry() { + ReactiveHealthIndicator healthIndicator = mock(ReactiveHealthIndicator.class); + this.contributorRegistry.registerContributor("test", healthIndicator); + assertThat(this.adapter.get("test")).isSameAs(healthIndicator); + } + + @Test + void getWhenContributorRegistryResultIsNotHealthIndicatorReturnsNull() { + CompositeReactiveHealthContributor healthContributor = mock(CompositeReactiveHealthContributor.class); + this.contributorRegistry.registerContributor("test", healthContributor); + assertThat(this.adapter.get("test")).isNull(); + } + + @Test + void getAllDelegatesContributorRegistry() { + ReactiveHealthIndicator healthIndicator = mock(ReactiveHealthIndicator.class); + this.contributorRegistry.registerContributor("test", healthIndicator); + Map all = this.adapter.getAll(); + assertThat(all).containsOnly(entry("test", healthIndicator)); + } + + @Test + void getAllWhenContributorRegistryContainsNonHealthIndicatorInstancesReturnsFilteredMap() { + CompositeReactiveHealthContributor healthContributor = mock(CompositeReactiveHealthContributor.class); + this.contributorRegistry.registerContributor("test1", healthContributor); + ReactiveHealthIndicator healthIndicator = mock(ReactiveHealthIndicator.class); + this.contributorRegistry.registerContributor("test2", healthIndicator); + Map all = this.adapter.getAll(); + assertThat(all).containsOnly(entry("test2", healthIndicator)); + } + +}