diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index e7294407ea0..9e458ae80b5 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -248,6 +248,16 @@ liquibase-core true + + org.mongodb + mongodb-driver-async + true + + + org.mongodb + mongodb-driver-reactivestreams + true + org.springframework spring-jdbc diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/mongo/MongoReactiveHealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/mongo/MongoReactiveHealthIndicatorAutoConfiguration.java new file mode 100644 index 00000000000..9a0fa531724 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/mongo/MongoReactiveHealthIndicatorAutoConfiguration.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012-2018 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.mongo; + +import java.util.Map; + +import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthIndicatorConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.actuate.mongo.MongoReactiveHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; + + + +/** + * {@link EnableAutoConfiguration Auto-configuration} for {@link MongoReactiveHealthIndicator}. + * + * @author Yulin Qin + * @since 2.0.0 + */ +@Configuration +@ConditionalOnClass(ReactiveMongoTemplate.class) +@ConditionalOnBean(ReactiveMongoTemplate.class) +@ConditionalOnEnabledHealthIndicator("mongo") +@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) +@AutoConfigureAfter(MongoReactiveDataAutoConfiguration.class) +public class MongoReactiveHealthIndicatorAutoConfiguration extends + CompositeReactiveHealthIndicatorConfiguration { + + private final Map reactiveMongoTemplate; + + public MongoReactiveHealthIndicatorAutoConfiguration( + Map reactiveMongoTemplate) { + this.reactiveMongoTemplate = reactiveMongoTemplate; + } + + @Bean + @ConditionalOnMissingBean(name = "mongoReactiveHealthIndicator") + public ReactiveHealthIndicator mongoReactiveHealthIndicator() { + return createHealthIndicator(this.reactiveMongoTemplate); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index e7732a33623..f73755a50b8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -53,6 +53,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMe org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.mongo.MongoReactiveHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/mongo/MongoReactiveHealthIndicatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/mongo/MongoReactiveHealthIndicatorAutoConfigurationTests.java new file mode 100644 index 00000000000..0491753c770 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/mongo/MongoReactiveHealthIndicatorAutoConfigurationTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012-2018 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.mongo; + +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; +import org.springframework.boot.actuate.health.ApplicationHealthIndicator; +import org.springframework.boot.actuate.mongo.MongoHealthIndicator; +import org.springframework.boot.actuate.mongo.MongoReactiveHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link MongoReactiveHealthIndicatorAutoConfiguration} + * + * @author Yulin Qin + */ +public class MongoReactiveHealthIndicatorAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class, + MongoReactiveAutoConfiguration.class, + MongoReactiveDataAutoConfiguration.class, + MongoReactiveHealthIndicatorAutoConfiguration.class, + HealthIndicatorAutoConfiguration.class)); + + @Test + public void runShouldCreateIndicator() { + this.contextRunner.run( + (context) -> assertThat(context).hasSingleBean(MongoReactiveHealthIndicator.class) + .doesNotHaveBean(MongoHealthIndicator.class) + .doesNotHaveBean(ApplicationHealthIndicator.class)); + } + + @Test + public void runWhenDisabledShouldNotCreateIndicator() { + this.contextRunner.withPropertyValues("management.health.mongo.enabled:false") + .run((context) -> assertThat(context) + .doesNotHaveBean(MongoReactiveHealthIndicator.class) + .doesNotHaveBean(MongoHealthIndicator.class) + .hasSingleBean(ApplicationHealthIndicator.class)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicator.java new file mode 100644 index 00000000000..d70c1139bb8 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicator.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2018 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.mongo; + +import org.bson.Document; +import reactor.core.publisher.Mono; + +import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.util.Assert; + + + +/** + * A {@link ReactiveHealthIndicator} for Mongo. + * + * @author Yulin Qin + * @since 2.0.0 + */ +public class MongoReactiveHealthIndicator extends AbstractReactiveHealthIndicator { + + private final ReactiveMongoTemplate reactiveMongoTemplate; + + public MongoReactiveHealthIndicator(ReactiveMongoTemplate reactiveMongoTemplate) { + Assert.notNull(reactiveMongoTemplate, "ReactiveMongoTemplate must not be null"); + this.reactiveMongoTemplate = reactiveMongoTemplate; + } + + @Override + protected Mono doHealthCheck(Health.Builder builder) { + Mono documentMono = this.reactiveMongoTemplate.executeCommand("{ buildInfo: 1 }"); + return documentMono.map(document -> up(builder, document)); + } + + private Health up(Health.Builder builder, Document document) { + return builder.up().withDetail("version", document.getString("version")).build(); + } +} + diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorTest.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorTest.java new file mode 100644 index 00000000000..fc9035d45dc --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2018 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.mongo; + +import com.mongodb.MongoException; +import org.bson.Document; +import org.junit.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link MongoReactiveHealthIndicator}. + * + * @author Yulin Qin + */ +public class MongoReactiveHealthIndicatorTest { + + @Test + public void testMongoIsUp() throws Exception { + Document document = mock(Document.class); + ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class); + given(reactiveMongoTemplate.executeCommand("{ buildInfo: 1 }")).willReturn(Mono.just(document)); + given(document.getString("version")).willReturn("2.6.4"); + + MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(reactiveMongoTemplate); + Mono health = mongoReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).containsOnlyKeys("version"); + assertThat(h.getDetails().get("version")).isEqualTo("2.6.4"); + }).verifyComplete(); + } + + @Test + public void testMongoIsDown() throws Exception { + ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class); + given(reactiveMongoTemplate.executeCommand("{ buildInfo: 1 }")).willThrow(new MongoException("Connection failed")); + + MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(reactiveMongoTemplate); + Mono health = mongoReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.DOWN); + assertThat(h.getDetails()).containsOnlyKeys("error"); + assertThat(h.getDetails().get("error")).isEqualTo("Connection failed"); + }).verifyComplete(); + + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java index de16566c56e..22f15dafc61 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2017 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. @@ -32,6 +32,7 @@ import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory; import org.springframework.data.mongodb.core.convert.MongoConverter; + /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive mongo * support. @@ -43,6 +44,7 @@ import org.springframework.data.mongodb.core.convert.MongoConverter; * to the {@literal test} database. * * @author Mark Paluch + * @author Yulin Qin * @since 2.0.0 */ @Configuration @@ -73,5 +75,4 @@ public class MongoReactiveDataAutoConfiguration { MongoConverter converter) { return new ReactiveMongoTemplate(reactiveMongoDatabaseFactory, converter); } - }