diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorAutoConfiguration.java index 5d685be9eb..13f1899f7e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorAutoConfiguration.java @@ -16,26 +16,20 @@ package org.springframework.boot.actuate.autoconfigure.couchbase; -import java.util.Map; - import com.couchbase.client.java.Bucket; -import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthIndicatorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.couchbase.CouchbaseHealthIndicator; -import org.springframework.boot.actuate.health.HealthIndicator; 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.couchbase.CouchbaseAutoConfiguration; import org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; +import org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration; import org.springframework.context.annotation.Configuration; -import org.springframework.data.couchbase.core.CouchbaseOperations; +import org.springframework.context.annotation.Import; /** * {@link EnableAutoConfiguration Auto-configuration} for @@ -46,37 +40,14 @@ import org.springframework.data.couchbase.core.CouchbaseOperations; * @since 2.0.0 */ @Configuration -@ConditionalOnClass({ CouchbaseOperations.class, Bucket.class }) -@ConditionalOnBean(CouchbaseOperations.class) +@ConditionalOnClass(Bucket.class) @ConditionalOnEnabledHealthIndicator("couchbase") @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) -@AutoConfigureAfter(CouchbaseDataAutoConfiguration.class) -@EnableConfigurationProperties(CouchbaseHealthIndicatorProperties.class) -public class CouchbaseHealthIndicatorAutoConfiguration extends - CompositeHealthIndicatorConfiguration { - - private final Map couchbaseOperations; - - private final CouchbaseHealthIndicatorProperties properties; - - public CouchbaseHealthIndicatorAutoConfiguration( - Map couchbaseOperations, - CouchbaseHealthIndicatorProperties properties) { - this.couchbaseOperations = couchbaseOperations; - this.properties = properties; - } - - @Bean - @ConditionalOnMissingBean(name = "couchbaseHealthIndicator") - public HealthIndicator couchbaseHealthIndicator() { - return createHealthIndicator(this.couchbaseOperations); - } - - @Override - protected CouchbaseHealthIndicator createHealthIndicator( - CouchbaseOperations couchbaseOperations) { - return new CouchbaseHealthIndicator(couchbaseOperations, - this.properties.getTimeout()); - } +@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, + CouchbaseDataAutoConfiguration.class, + CouchbaseReactiveDataAutoConfiguration.class }) +@Import({ CouchbaseReactiveHealthIndicatorConfiguration.class, + CouchbaseHealthIndicatorConfiguration.class }) +public class CouchbaseHealthIndicatorAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorConfiguration.java new file mode 100644 index 0000000000..2d8f081e7b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorConfiguration.java @@ -0,0 +1,69 @@ +/* + * 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.couchbase; + +import java.util.Map; + +import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthIndicatorConfiguration; +import org.springframework.boot.actuate.couchbase.CouchbaseHealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicator; +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.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.core.CouchbaseOperations; + +/** + * Configuration for {@link CouchbaseHealthIndicator}. + * + * @author EddĂș MelĂ©ndez + * @author Stephane Nicoll + * @since 2.0.0 + */ +@Configuration +@ConditionalOnClass(CouchbaseOperations.class) +@ConditionalOnBean(CouchbaseOperations.class) +@EnableConfigurationProperties(CouchbaseHealthIndicatorProperties.class) +public class CouchbaseHealthIndicatorConfiguration extends + CompositeHealthIndicatorConfiguration { + + private final Map couchbaseOperations; + + private final CouchbaseHealthIndicatorProperties properties; + + CouchbaseHealthIndicatorConfiguration( + Map couchbaseOperations, + CouchbaseHealthIndicatorProperties properties) { + this.couchbaseOperations = couchbaseOperations; + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean(name = "couchbaseHealthIndicator") + public HealthIndicator couchbaseHealthIndicator() { + return createHealthIndicator(this.couchbaseOperations); + } + + @Override + protected CouchbaseHealthIndicator createHealthIndicator( + CouchbaseOperations couchbaseOperations) { + return new CouchbaseHealthIndicator(couchbaseOperations, + this.properties.getTimeout()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthIndicatorConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthIndicatorConfiguration.java new file mode 100644 index 0000000000..23ad168ad7 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthIndicatorConfiguration.java @@ -0,0 +1,71 @@ +/* + * 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.couchbase; + +import java.util.Map; + +import reactor.core.publisher.Flux; + +import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthIndicatorConfiguration; +import org.springframework.boot.actuate.couchbase.CouchbaseReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +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.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.core.RxJavaCouchbaseOperations; + +/** + * Configuration for {@link CouchbaseReactiveHealthIndicator}. + * + * @author Mikalai Lushchytski + * @author Stephane Nicoll + * @since 2.1.0 + */ +@Configuration +@ConditionalOnClass({ RxJavaCouchbaseOperations.class, Flux.class }) +@ConditionalOnBean(RxJavaCouchbaseOperations.class) +@EnableConfigurationProperties(CouchbaseHealthIndicatorProperties.class) +public class CouchbaseReactiveHealthIndicatorConfiguration extends + CompositeReactiveHealthIndicatorConfiguration { + + private final Map couchbaseOperations; + + private final CouchbaseHealthIndicatorProperties properties; + + CouchbaseReactiveHealthIndicatorConfiguration( + Map couchbaseOperations, + CouchbaseHealthIndicatorProperties properties) { + this.couchbaseOperations = couchbaseOperations; + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean(name = "couchbaseReactiveHealthIndicator") + public ReactiveHealthIndicator couchbaseReactiveHealthIndicator() { + return createHealthIndicator(this.couchbaseOperations); + } + + @Override + protected CouchbaseReactiveHealthIndicator createHealthIndicator( + RxJavaCouchbaseOperations couchbaseOperations) { + return new CouchbaseReactiveHealthIndicator(couchbaseOperations, + this.properties.getTimeout()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorConfigurationTests.java similarity index 83% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorAutoConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorConfigurationTests.java index 21fce0037b..b8ca7c46d0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthIndicatorConfigurationTests.java @@ -13,16 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.boot.actuate.autoconfigure.couchbase; import org.junit.Test; import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.couchbase.CouchbaseHealthIndicator; +import org.springframework.boot.actuate.couchbase.CouchbaseReactiveHealthIndicator; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -33,22 +32,23 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; /** - * Tests for {@link CouchbaseHealthIndicatorAutoConfiguration}. + * Tests for {@link CouchbaseHealthIndicatorConfiguration}. * * @author Phillip Webb * @author Stephane Nicoll */ -public class CouchbaseHealthIndicatorAutoConfigurationTests { +public class CouchbaseHealthIndicatorConfigurationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(CouchbaseConfiguration.class, - CouchbaseHealthIndicatorAutoConfiguration.class, - HealthIndicatorAutoConfiguration.class)); + .withUserConfiguration(CouchbaseMockConfiguration.class).withConfiguration( + AutoConfigurations.of(CouchbaseHealthIndicatorAutoConfiguration.class, + HealthIndicatorAutoConfiguration.class)); @Test public void runShouldCreateIndicator() { this.contextRunner.run((context) -> assertThat(context) .hasSingleBean(CouchbaseHealthIndicator.class) + .doesNotHaveBean(CouchbaseReactiveHealthIndicator.class) .doesNotHaveBean(ApplicationHealthIndicator.class)); } @@ -72,8 +72,7 @@ public class CouchbaseHealthIndicatorAutoConfigurationTests { } @Configuration - @AutoConfigureBefore(CouchbaseHealthIndicatorAutoConfiguration.class) - protected static class CouchbaseConfiguration { + protected static class CouchbaseMockConfiguration { @Bean public CouchbaseOperations couchbaseOperations() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthIndicatorConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthIndicatorConfigurationTests.java new file mode 100644 index 0000000000..33385c7f8c --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthIndicatorConfigurationTests.java @@ -0,0 +1,85 @@ +/* + * 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.couchbase; + +import java.time.Duration; + +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; +import org.springframework.boot.actuate.couchbase.CouchbaseHealthIndicator; +import org.springframework.boot.actuate.couchbase.CouchbaseReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ApplicationHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.core.RxJavaCouchbaseOperations; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CouchbaseReactiveHealthIndicatorConfiguration}. + * + * @author Mikalai Lushchytski + */ +public class CouchbaseReactiveHealthIndicatorConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(CouchbaseMockConfiguration.class).withConfiguration( + AutoConfigurations.of(CouchbaseHealthIndicatorAutoConfiguration.class, + HealthIndicatorAutoConfiguration.class)); + + @Test + public void runShouldCreateIndicator() { + this.contextRunner.run((context) -> assertThat(context) + .hasSingleBean(CouchbaseReactiveHealthIndicator.class) + .doesNotHaveBean(CouchbaseHealthIndicator.class) + .doesNotHaveBean(ApplicationHealthIndicator.class)); + } + + @Test + public void runWithCustomTimeoutShouldCreateIndicator() { + this.contextRunner.withPropertyValues("management.health.couchbase.timeout=2s") + .run((context) -> { + assertThat(context) + .hasSingleBean(CouchbaseReactiveHealthIndicator.class); + assertThat(context.getBean(CouchbaseReactiveHealthIndicator.class)) + .hasFieldOrPropertyWithValue("timeout", + Duration.ofSeconds(2)); + }); + } + + @Test + public void runWhenDisabledShouldNotCreateIndicator() { + this.contextRunner.withPropertyValues("management.health.couchbase.enabled:false") + .run((context) -> assertThat(context) + .doesNotHaveBean(CouchbaseReactiveHealthIndicator.class) + .hasSingleBean(ApplicationHealthIndicator.class)); + } + + @Configuration + protected static class CouchbaseMockConfiguration { + + @Bean + public RxJavaCouchbaseOperations couchbaseOperations() { + return mock(RxJavaCouchbaseOperations.class); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/pom.xml b/spring-boot-project/spring-boot-actuator/pom.xml index 055feabaf3..ba0b2dd341 100644 --- a/spring-boot-project/spring-boot-actuator/pom.xml +++ b/spring-boot-project/spring-boot-actuator/pom.xml @@ -61,6 +61,11 @@ micrometer-registry-prometheus true + + io.reactivex + rxjava-reactive-streams + true + io.searchbox jest diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/couchbase/CouchbaseReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/couchbase/CouchbaseReactiveHealthIndicator.java new file mode 100644 index 0000000000..218cb26a2a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/couchbase/CouchbaseReactiveHealthIndicator.java @@ -0,0 +1,74 @@ +/* + * 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.couchbase; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; + +import com.couchbase.client.java.bucket.BucketInfo; +import com.couchbase.client.java.cluster.ClusterInfo; +import reactor.core.publisher.Mono; +import rx.Observable; +import rx.RxReactiveStreams; +import rx.Single; + +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.couchbase.core.RxJavaCouchbaseOperations; +import org.springframework.util.StringUtils; + +/** + * A {@link ReactiveHealthIndicator} for Couchbase. + * + * @author Mikalai Lushchytski + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class CouchbaseReactiveHealthIndicator extends AbstractReactiveHealthIndicator { + + private final RxJavaCouchbaseOperations couchbaseOperations; + + private final Duration timeout; + + /** + * Create a new {@link CouchbaseReactiveHealthIndicator} instance. + * @param couchbaseOperations the reactive couchbase operations + * @param timeout the request timeout + */ + public CouchbaseReactiveHealthIndicator(RxJavaCouchbaseOperations couchbaseOperations, + Duration timeout) { + this.couchbaseOperations = couchbaseOperations; + this.timeout = timeout; + } + + @Override + protected Mono doHealthCheck(Health.Builder builder) { + ClusterInfo cluster = this.couchbaseOperations.getCouchbaseClusterInfo(); + String versions = StringUtils + .collectionToCommaDelimitedString(cluster.getAllVersions()); + Observable bucket = this.couchbaseOperations.getCouchbaseBucket() + .bucketManager().async().info() + .timeout(this.timeout.toMillis(), TimeUnit.MILLISECONDS); + Single health = bucket.map(BucketInfo::nodeList) + .map(StringUtils::collectionToCommaDelimitedString) + .map((nodes) -> builder.up().withDetail("versions", versions) + .withDetail("nodes", nodes).build()) + .toSingle(); + return Mono.from(RxReactiveStreams.toPublisher(health)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/couchbase/CouchbaseReactiveHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/couchbase/CouchbaseReactiveHealthIndicatorTests.java new file mode 100644 index 0000000000..4edd07b700 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/couchbase/CouchbaseReactiveHealthIndicatorTests.java @@ -0,0 +1,127 @@ +/* + * 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.couchbase; + +import java.net.InetAddress; +import java.time.Duration; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.bucket.AsyncBucketManager; +import com.couchbase.client.java.bucket.BucketInfo; +import com.couchbase.client.java.bucket.BucketManager; +import com.couchbase.client.java.cluster.ClusterInfo; +import com.couchbase.client.java.error.TranscodingException; +import com.couchbase.client.java.util.features.Version; +import org.junit.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; +import rx.Observable; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; +import org.springframework.data.couchbase.core.RxJavaCouchbaseOperations; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CouchbaseReactiveHealthIndicator}. + */ +public class CouchbaseReactiveHealthIndicatorTests { + + @Test + public void couchbaseIsUp() { + RxJavaCouchbaseOperations rxJavaCouchbaseOperations = mock( + RxJavaCouchbaseOperations.class); + AsyncBucketManager asyncBucketManager = mockAsyncBucketManager( + rxJavaCouchbaseOperations); + BucketInfo info = mock(BucketInfo.class); + InetAddress node1Address = mock(InetAddress.class); + InetAddress node2Address = mock(InetAddress.class); + given(info.nodeList()).willReturn(Arrays.asList(node1Address, node2Address)); + given(node1Address.toString()).willReturn("127.0.0.1"); + given(node2Address.toString()).willReturn("127.0.0.2"); + given(asyncBucketManager.info()).willReturn(Observable.just(info)); + CouchbaseReactiveHealthIndicator couchbaseReactiveHealthIndicator = new CouchbaseReactiveHealthIndicator( + rxJavaCouchbaseOperations, Duration.ofSeconds(2)); + Mono health = couchbaseReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).containsKeys("versions", "nodes"); + assertThat(h.getDetails().get("versions")).isEqualTo("5.5.0,6.0.0"); + assertThat(h.getDetails().get("nodes")).isEqualTo("127.0.0.1,127.0.0.2"); + }).verifyComplete(); + } + + @Test + public void couchbaseTimeout() { + RxJavaCouchbaseOperations rxJavaCouchbaseOperations = mock( + RxJavaCouchbaseOperations.class); + AsyncBucketManager asyncBucketManager = mockAsyncBucketManager( + rxJavaCouchbaseOperations); + given(asyncBucketManager.info()).willReturn( + Observable.just(mock(BucketInfo.class)).delay(20, TimeUnit.MILLISECONDS)); + CouchbaseReactiveHealthIndicator couchbaseReactiveHealthIndicator = new CouchbaseReactiveHealthIndicator( + rxJavaCouchbaseOperations, Duration.ofMillis(10)); + Mono health = couchbaseReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.DOWN); + assertThat(h.getDetails()).containsOnlyKeys("error"); + assertThat(h.getDetails().get("error")).asString() + .contains(TimeoutException.class.getName()); + }).verifyComplete(); + } + + @Test + public void couchbaseIsDown() { + RxJavaCouchbaseOperations rxJavaCouchbaseOperations = mock( + RxJavaCouchbaseOperations.class); + AsyncBucketManager asyncBucketManager = mockAsyncBucketManager( + rxJavaCouchbaseOperations); + given(asyncBucketManager.info()) + .willReturn(Observable.error(new TranscodingException("Failure"))); + CouchbaseReactiveHealthIndicator couchbaseReactiveHealthIndicator = new CouchbaseReactiveHealthIndicator( + rxJavaCouchbaseOperations, Duration.ofSeconds(2)); + Mono health = couchbaseReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.DOWN); + assertThat(h.getDetails()).containsOnlyKeys("error"); + assertThat(h.getDetails().get("error")) + .isEqualTo(TranscodingException.class.getName() + ": Failure"); + }).verifyComplete(); + } + + private AsyncBucketManager mockAsyncBucketManager( + RxJavaCouchbaseOperations rxJavaCouchbaseOperations) { + ClusterInfo clusterInfo = mock(ClusterInfo.class); + given(rxJavaCouchbaseOperations.getCouchbaseClusterInfo()) + .willReturn(clusterInfo); + given(clusterInfo.getAllVersions()) + .willReturn(Arrays.asList(new Version(5, 5, 0), new Version(6, 0, 0))); + Bucket bucket = mock(Bucket.class); + BucketManager bucketManager = mock(BucketManager.class); + AsyncBucketManager asyncBucketManager = mock(AsyncBucketManager.class); + given(rxJavaCouchbaseOperations.getCouchbaseBucket()).willReturn(bucket); + given(bucket.bucketManager()).willReturn(bucketManager); + given(bucketManager.async()).willReturn(asyncBucketManager); + return asyncBucketManager; + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index ac8e88c00d..98386320af 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -926,6 +926,9 @@ appropriate: |{sc-spring-boot-actuator}/cassandra/CassandraReactiveHealthIndicator.{sc-ext}[`CassandraReactiveHealthIndicator`] |Checks that a Cassandra database is up. +|{sc-spring-boot-actuator}/couchbase/CouchbaseReactiveHealthIndicator.{sc-ext}[`CouchbaseReactiveHealthIndicator`] +|Checks that a Couchbase cluster is up. + |{sc-spring-boot-actuator}/mongo/MongoReactiveHealthIndicator.{sc-ext}[`MongoReactiveHealthIndicator`] |Checks that a Mongo database is up.