From dad9ec86d51bca5dc629c106dfee2d90f134eae5 Mon Sep 17 00:00:00 2001 From: Alexandre Dutra Date: Sat, 28 Mar 2020 15:52:48 +0100 Subject: [PATCH 1/2] Add health indicator for Cassandra that uses the CqlSession This commit provides a CassandraDriverHealthIndicator and CassandraDriverReactiveHealthIndicator that do not require Spring Data. As a result, a health indicator for Cassandra is provided even if the application does not use Spring Data. See gh-20887 --- .../build.gradle | 1 + ...verHealthContributorAutoConfiguration.java | 59 ++++++++++ ...iveHealthContributorAutoConfiguration.java | 58 ++++++++++ .../main/resources/META-INF/spring.factories | 2 + ...althContributorAutoConfigurationTests.java | 89 +++++++++++++++ ...althContributorAutoConfigurationTests.java | 79 +++++++++++++ .../spring-boot-actuator/build.gradle | 1 + .../CassandraDriverHealthIndicator.java | 65 +++++++++++ ...assandraDriverReactiveHealthIndicator.java | 61 ++++++++++ .../CassandraDriverHealthIndicatorTests.java | 74 ++++++++++++ ...draDriverReactiveHealthIndicatorTests.java | 108 ++++++++++++++++++ 11 files changed, 597 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicatorTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicatorTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle index 61b07a921f6..7eb842d0e50 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle @@ -31,6 +31,7 @@ dependencies { optional(platform(project(":spring-boot-project:spring-boot-dependencies"))) optional("ch.qos.logback:logback-classic") + optional("com.datastax.oss:java-driver-core") optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") optional("com.github.ben-manes.caffeine:caffeine") optional("com.hazelcast:hazelcast") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfiguration.java new file mode 100644 index 00000000000..75fda9deb7f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfiguration.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2020 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.cassandra; + +import java.util.Map; + +import com.datastax.oss.driver.api.core.CqlSession; + +import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraDriverHealthIndicator; +import org.springframework.boot.actuate.health.HealthContributor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for + * {@link CassandraDriverHealthIndicator}. + * + * @author Alexandre Dutra + * @since 2.4.0 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(CqlSession.class) +@ConditionalOnBean(CqlSession.class) +@ConditionalOnEnabledHealthIndicator("cassandra") +@AutoConfigureAfter({ CassandraAutoConfiguration.class, CassandraReactiveHealthContributorAutoConfiguration.class, + CassandraHealthContributorAutoConfiguration.class, + CassandraDriverReactiveHealthContributorAutoConfiguration.class }) +public class CassandraDriverHealthContributorAutoConfiguration + extends CompositeHealthContributorConfiguration { + + @Bean + @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) + public HealthContributor cassandraHealthContributor(Map sessions) { + return createContributor(sessions); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfiguration.java new file mode 100644 index 00000000000..78964eefe95 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfiguration.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2020 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.cassandra; + +import java.util.Map; + +import com.datastax.oss.driver.api.core.CqlSession; +import reactor.core.publisher.Flux; + +import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraDriverReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthContributor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for + * {@link CassandraDriverReactiveHealthIndicator}. + * + * @author Alexandre Dutra + * @since 2.4.0 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ CqlSession.class, Flux.class }) +@ConditionalOnBean(CqlSession.class) +@ConditionalOnEnabledHealthIndicator("cassandra") +@AutoConfigureAfter({ CassandraAutoConfiguration.class, CassandraReactiveHealthContributorAutoConfiguration.class, + CassandraHealthContributorAutoConfiguration.class }) +public class CassandraDriverReactiveHealthContributorAutoConfiguration + extends CompositeReactiveHealthContributorConfiguration { + + @Bean + @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) + public ReactiveHealthContributor cassandraHealthContributor(Map sessions) { + return createContributor(sessions); + } + +} 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 e297520518c..c1e50891936 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 @@ -7,6 +7,8 @@ org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfigurat org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cassandra.CassandraReactiveHealthContributorAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.cassandra.CassandraDriverHealthContributorAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.cassandra.CassandraDriverReactiveHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfigurationTests.java new file mode 100644 index 00000000000..5bdb9348809 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfigurationTests.java @@ -0,0 +1,89 @@ +/* + * 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.cassandra; + +import com.datastax.oss.driver.api.core.CqlSession; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; +import org.springframework.boot.actuate.cassandra.CassandraDriverHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraDriverReactiveHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.data.cassandra.core.ReactiveCassandraOperations; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CassandraDriverHealthContributorAutoConfiguration}. + * + * @author Alexandre Dutra + * @since 2.4.0 + */ +class CassandraDriverHealthContributorAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withBean(CqlSession.class, () -> mock(CqlSession.class)).withConfiguration(AutoConfigurations.of( + CassandraDriverHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class)); + + @Test + void runShouldCreateDriverIndicator() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(CassandraDriverHealthIndicator.class) + .hasBean("cassandraHealthContributor").doesNotHaveBean(CassandraHealthIndicator.class) + .doesNotHaveBean(CassandraReactiveHealthIndicator.class) + .doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class)); + } + + @Test + void runWhenDisabledShouldNotCreateDriverIndicator() { + this.contextRunner.withPropertyValues("management.health.cassandra.enabled:false") + .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverHealthIndicator.class) + .doesNotHaveBean("cassandraHealthContributor")); + } + + @Test + void runWhenSpringDataPresentShouldNotCreateDriverIndicator() { + this.contextRunner.withConfiguration(AutoConfigurations.of(CassandraHealthContributorAutoConfiguration.class)) + .withBean(CassandraOperations.class, () -> mock(CassandraOperations.class)) + .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverHealthIndicator.class) + .hasSingleBean(CassandraHealthIndicator.class).hasBean("cassandraHealthContributor")); + } + + @Test + void runWhenReactorPresentShouldNotCreateDriverIndicator() { + this.contextRunner + .withConfiguration( + AutoConfigurations.of(CassandraDriverReactiveHealthContributorAutoConfiguration.class)) + .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverHealthIndicator.class) + .hasSingleBean(CassandraDriverReactiveHealthIndicator.class) + .hasBean("cassandraHealthContributor")); + } + + @Test + void runWhenSpringDataAndReactorPresentShouldNotCreateDriverIndicator() { + this.contextRunner + .withConfiguration(AutoConfigurations.of(CassandraReactiveHealthContributorAutoConfiguration.class)) + .withBean(ReactiveCassandraOperations.class, () -> mock(ReactiveCassandraOperations.class)) + .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverHealthIndicator.class) + .hasSingleBean(CassandraReactiveHealthIndicator.class).hasBean("cassandraHealthContributor")); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfigurationTests.java new file mode 100644 index 00000000000..bf2d8edb36e --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfigurationTests.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.cassandra; + +import com.datastax.oss.driver.api.core.CqlSession; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; +import org.springframework.boot.actuate.cassandra.CassandraDriverReactiveHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.data.cassandra.core.ReactiveCassandraOperations; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CassandraDriverReactiveHealthContributorAutoConfiguration}. + * + * @author Alexandre Dutra + * @since 2.4.0 + */ +class CassandraDriverReactiveHealthContributorAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withBean(CqlSession.class, () -> mock(CqlSession.class)) + .withConfiguration(AutoConfigurations.of(CassandraDriverReactiveHealthContributorAutoConfiguration.class, + HealthContributorAutoConfiguration.class)); + + @Test + void runShouldCreateDriverReactiveIndicator() { + this.contextRunner + .run((context) -> assertThat(context).hasSingleBean(CassandraDriverReactiveHealthIndicator.class) + .hasBean("cassandraHealthContributor").doesNotHaveBean(CassandraHealthIndicator.class) + .doesNotHaveBean(CassandraReactiveHealthIndicator.class)); + } + + @Test + void runWhenDisabledShouldNotCreateDriverReactiveIndicator() { + this.contextRunner.withPropertyValues("management.health.cassandra.enabled:false") + .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class) + .doesNotHaveBean("cassandraHealthContributor")); + } + + @Test + void runWhenSpringDataPresentShouldNotCreateDriverReactiveIndicator() { + this.contextRunner.withConfiguration(AutoConfigurations.of(CassandraHealthContributorAutoConfiguration.class)) + .withBean(CassandraOperations.class, () -> mock(CassandraOperations.class)) + .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class) + .hasSingleBean(CassandraHealthIndicator.class).hasBean("cassandraHealthContributor")); + } + + @Test + void runWhenSpringDataAndReactorPresentShouldNotCreateDriverReactiveIndicator() { + this.contextRunner + .withConfiguration(AutoConfigurations.of(CassandraReactiveHealthContributorAutoConfiguration.class)) + .withBean(ReactiveCassandraOperations.class, () -> mock(ReactiveCassandraOperations.class)) + .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class) + .hasSingleBean(CassandraReactiveHealthIndicator.class).hasBean("cassandraHealthContributor")); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/build.gradle b/spring-boot-project/spring-boot-actuator/build.gradle index 26598287084..f9f27e92b47 100644 --- a/spring-boot-project/spring-boot-actuator/build.gradle +++ b/spring-boot-project/spring-boot-actuator/build.gradle @@ -13,6 +13,7 @@ dependencies { api(project(":spring-boot-project:spring-boot")) optional(platform(project(":spring-boot-project:spring-boot-dependencies"))) + optional("com.datastax.oss:java-driver-core") optional("com.fasterxml.jackson.core:jackson-databind") optional("com.github.ben-manes.caffeine:caffeine") optional("com.hazelcast:hazelcast") diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java new file mode 100644 index 00000000000..75f262d51fc --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2020 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.cassandra; + +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; + +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.util.Assert; + +/** + * Simple implementation of a {@link HealthIndicator} returning status information for + * Cassandra data stores. + * + * This health indicator is automatically used when Spring Data Cassandra is not present, + * but the Cassandra driver is. + * + * @author Alexandre Dutra + * @since 2.4.0 + */ +public class CassandraDriverHealthIndicator extends AbstractHealthIndicator { + + private static final SimpleStatement SELECT = SimpleStatement + .newInstance("SELECT release_version FROM system.local").setConsistencyLevel(ConsistencyLevel.LOCAL_ONE); + + private final CqlSession session; + + /** + * Create a new {@link CassandraDriverHealthIndicator} instance. + * @param session the {@link CqlSession}. + */ + public CassandraDriverHealthIndicator(CqlSession session) { + super("Cassandra health check failed"); + Assert.notNull(session, "session must not be null"); + this.session = session; + } + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + Row row = this.session.execute(SELECT).one(); + builder.up(); + if (row != null && !row.isNull(0)) { + builder.withDetail("version", row.getString(0)); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java new file mode 100644 index 00000000000..04533afdc14 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2020 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.cassandra; + +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +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.util.Assert; + +/** + * Simple implementation of a {@link ReactiveHealthIndicator} returning status information + * for Cassandra data stores. + * + * This health indicator is automatically used when Spring Data Cassandra is not present, + * but the Cassandra driver is. + * + * @author Alexandre Dutra + * @since 2.4.0 + */ +public class CassandraDriverReactiveHealthIndicator extends AbstractReactiveHealthIndicator { + + private static final SimpleStatement SELECT = SimpleStatement + .newInstance("SELECT release_version FROM system.local").setConsistencyLevel(ConsistencyLevel.LOCAL_ONE); + + private final CqlSession session; + + /** + * Create a new {@link CassandraHealthIndicator} instance. + * @param session the {@link CqlSession}. + */ + public CassandraDriverReactiveHealthIndicator(CqlSession session) { + super("Cassandra health check failed"); + Assert.notNull(session, "session must not be null"); + this.session = session; + } + + @Override + protected Mono doHealthCheck(Health.Builder builder) { + return Mono.from(this.session.executeReactive(SELECT)) + .map((row) -> builder.up().withDetail("version", row.getString(0)).build()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicatorTests.java new file mode 100644 index 00000000000..875edd64c34 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicatorTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2020 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.cassandra; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.DriverTimeoutException; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CassandraDriverHealthIndicator}. + * + * @author Alexandre Dutra + * @since 2.4.0 + */ +class CassandraDriverHealthIndicatorTests { + + @Test + void createWhenCqlSessionIsNullShouldThrowException() { + assertThatIllegalArgumentException().isThrownBy(() -> new CassandraDriverHealthIndicator(null)); + } + + @Test + void healthWithCassandraUp() { + CqlSession session = mock(CqlSession.class); + ResultSet resultSet = mock(ResultSet.class); + Row row = mock(Row.class); + given(session.execute(any(SimpleStatement.class))).willReturn(resultSet); + given(resultSet.one()).willReturn(row); + given(row.isNull(0)).willReturn(false); + given(row.getString(0)).willReturn("1.0.0"); + CassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session); + Health health = healthIndicator.health(); + assertThat(health.getStatus()).isEqualTo(Status.UP); + assertThat(health.getDetails().get("version")).isEqualTo("1.0.0"); + } + + @Test + void healthWithCassandraDown() { + CqlSession session = mock(CqlSession.class); + given(session.execute(any(SimpleStatement.class))).willThrow(new DriverTimeoutException("Test Exception")); + CassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session); + Health health = healthIndicator.health(); + assertThat(health.getStatus()).isEqualTo(Status.DOWN); + assertThat(health.getDetails().get("error")) + .isEqualTo(DriverTimeoutException.class.getName() + ": Test Exception"); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicatorTests.java new file mode 100644 index 00000000000..a6c1537091b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicatorTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2012-2020 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.cassandra; + +import com.datastax.dse.driver.api.core.cql.reactive.ReactiveResultSet; +import com.datastax.dse.driver.api.core.cql.reactive.ReactiveRow; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.DriverTimeoutException; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import org.junit.jupiter.api.Test; +import org.mockito.stubbing.Answer; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.doAnswer; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.mock; + +/** + * Tests for {@link CassandraDriverReactiveHealthIndicator}. + * + * @author Alexandre Dutra + * @since 2.4.0 + */ +class CassandraDriverReactiveHealthIndicatorTests { + + @Test + void createWhenCqlSessionIsNullShouldThrowException() { + assertThatIllegalArgumentException().isThrownBy(() -> new CassandraDriverReactiveHealthIndicator(null)); + } + + @Test + void testCassandraIsUp() { + CqlSession session = mock(CqlSession.class); + ReactiveResultSet results = mock(ReactiveResultSet.class); + ReactiveRow row = mock(ReactiveRow.class); + given(session.executeReactive(any(SimpleStatement.class))).willReturn(results); + doAnswer(mockReactiveResultSetBehavior(row)).when(results).subscribe(any()); + given(row.getString(0)).willReturn("6.0.0"); + + CassandraDriverReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraDriverReactiveHealthIndicator( + session); + Mono health = cassandraReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).containsOnlyKeys("version"); + assertThat(h.getDetails().get("version")).isEqualTo("6.0.0"); + }).verifyComplete(); + } + + @Test + void testCassandraIsDown() { + CqlSession session = mock(CqlSession.class); + given(session.executeReactive(any(SimpleStatement.class))) + .willThrow(new DriverTimeoutException("Test Exception")); + + CassandraDriverReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraDriverReactiveHealthIndicator( + session); + Mono health = cassandraReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.DOWN); + assertThat(h.getDetails()).containsOnlyKeys("error"); + assertThat(h.getDetails().get("error")) + .isEqualTo(DriverTimeoutException.class.getName() + ": Test Exception"); + }).verifyComplete(); + } + + private Answer mockReactiveResultSetBehavior(ReactiveRow row) { + return (invocation) -> { + Subscriber subscriber = invocation.getArgument(0); + Subscription s = new Subscription() { + @Override + public void request(long n) { + subscriber.onNext(row); + subscriber.onComplete(); + } + + @Override + public void cancel() { + } + }; + subscriber.onSubscribe(s); + return null; + }; + } + +} From 35e069e2cd4b563590ffd5869f78e33324a43961 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 15 Jun 2020 11:05:31 +0200 Subject: [PATCH 2/2] Polish "Add health indicator for Cassandra that uses the CqlSession" See gh-20887 --- ...verHealthContributorAutoConfiguration.java | 59 ---------- ...iveHealthContributorAutoConfiguration.java | 58 ---------- ...draHealthContributorAutoConfiguration.java | 24 ++--- ...sandraHealthContributorConfigurations.java | 101 ++++++++++++++++++ ...iveHealthContributorAutoConfiguration.java | 25 ++--- .../main/resources/META-INF/spring.factories | 2 - ...althContributorAutoConfigurationTests.java | 89 --------------- ...althContributorAutoConfigurationTests.java | 79 -------------- ...althContributorAutoConfigurationTests.java | 53 +++++---- ...althContributorAutoConfigurationTests.java | 58 +++++++--- .../CassandraDriverHealthIndicator.java | 3 - ...assandraDriverReactiveHealthIndicator.java | 3 - ...draDriverReactiveHealthIndicatorTests.java | 2 - .../asciidoc/production-ready-features.adoc | 4 +- 14 files changed, 192 insertions(+), 368 deletions(-) delete mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfiguration.java delete mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorConfigurations.java delete mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfigurationTests.java delete mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfiguration.java deleted file mode 100644 index 75fda9deb7f..00000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfiguration.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2012-2020 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.cassandra; - -import java.util.Map; - -import com.datastax.oss.driver.api.core.CqlSession; - -import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; -import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; -import org.springframework.boot.actuate.cassandra.CassandraDriverHealthIndicator; -import org.springframework.boot.actuate.health.HealthContributor; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for - * {@link CassandraDriverHealthIndicator}. - * - * @author Alexandre Dutra - * @since 2.4.0 - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(CqlSession.class) -@ConditionalOnBean(CqlSession.class) -@ConditionalOnEnabledHealthIndicator("cassandra") -@AutoConfigureAfter({ CassandraAutoConfiguration.class, CassandraReactiveHealthContributorAutoConfiguration.class, - CassandraHealthContributorAutoConfiguration.class, - CassandraDriverReactiveHealthContributorAutoConfiguration.class }) -public class CassandraDriverHealthContributorAutoConfiguration - extends CompositeHealthContributorConfiguration { - - @Bean - @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) - public HealthContributor cassandraHealthContributor(Map sessions) { - return createContributor(sessions); - } - -} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfiguration.java deleted file mode 100644 index 78964eefe95..00000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfiguration.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2012-2020 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.cassandra; - -import java.util.Map; - -import com.datastax.oss.driver.api.core.CqlSession; -import reactor.core.publisher.Flux; - -import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; -import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; -import org.springframework.boot.actuate.cassandra.CassandraDriverReactiveHealthIndicator; -import org.springframework.boot.actuate.health.ReactiveHealthContributor; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for - * {@link CassandraDriverReactiveHealthIndicator}. - * - * @author Alexandre Dutra - * @since 2.4.0 - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ CqlSession.class, Flux.class }) -@ConditionalOnBean(CqlSession.class) -@ConditionalOnEnabledHealthIndicator("cassandra") -@AutoConfigureAfter({ CassandraAutoConfiguration.class, CassandraReactiveHealthContributorAutoConfiguration.class, - CassandraHealthContributorAutoConfiguration.class }) -public class CassandraDriverReactiveHealthContributorAutoConfiguration - extends CompositeReactiveHealthContributorConfiguration { - - @Bean - @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) - public ReactiveHealthContributor cassandraHealthContributor(Map sessions) { - return createContributor(sessions); - } - -} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfiguration.java index 0a10ca472c2..c15a049c188 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfiguration.java @@ -16,24 +16,19 @@ package org.springframework.boot.actuate.autoconfigure.cassandra; -import java.util.Map; - import com.datastax.oss.driver.api.core.CqlSession; -import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; +import org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthContributorConfigurations.CassandraDriverConfiguration; +import org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthContributorConfigurations.CassandraOperationsConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; -import org.springframework.boot.actuate.health.HealthContributor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; -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.cassandra.CassandraDataAutoConfiguration; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.context.annotation.Import; /** * {@link EnableAutoConfiguration Auto-configuration} for @@ -44,18 +39,11 @@ import org.springframework.data.cassandra.core.CassandraOperations; * @since 2.1.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ CqlSession.class, CassandraOperations.class }) -@ConditionalOnBean(CassandraOperations.class) +@ConditionalOnClass(CqlSession.class) @ConditionalOnEnabledHealthIndicator("cassandra") @AutoConfigureAfter({ CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class, CassandraReactiveHealthContributorAutoConfiguration.class }) -public class CassandraHealthContributorAutoConfiguration - extends CompositeHealthContributorConfiguration { - - @Bean - @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) - public HealthContributor cassandraHealthContributor(Map cassandraOperations) { - return createContributor(cassandraOperations); - } +@Import({ CassandraOperationsConfiguration.class, CassandraDriverConfiguration.class }) +public class CassandraHealthContributorAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorConfigurations.java new file mode 100644 index 00000000000..a618380a4f7 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorConfigurations.java @@ -0,0 +1,101 @@ +/* + * Copyright 2012-2020 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.cassandra; + +import java.util.Map; + +import com.datastax.oss.driver.api.core.CqlSession; + +import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; +import org.springframework.boot.actuate.cassandra.CassandraDriverHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraDriverReactiveHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; +import org.springframework.boot.actuate.health.HealthContributor; +import org.springframework.boot.actuate.health.ReactiveHealthContributor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.data.cassandra.core.ReactiveCassandraOperations; + +/** + * Health contributor options for Cassandra. + * + * @author Stephane Nicoll + */ +class CassandraHealthContributorConfigurations { + + @Configuration(proxyBeanMethods = false) + @ConditionalOnBean(CqlSession.class) + static class CassandraDriverConfiguration + extends CompositeHealthContributorConfiguration { + + @Bean + @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) + HealthContributor cassandraHealthContributor(Map sessions) { + return createContributor(sessions); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(CassandraOperations.class) + @ConditionalOnBean(CassandraOperations.class) + static class CassandraOperationsConfiguration + extends CompositeHealthContributorConfiguration { + + @Bean + @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) + HealthContributor cassandraHealthContributor(Map cassandraOperations) { + return createContributor(cassandraOperations); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnBean(CqlSession.class) + static class CassandraReactiveDriverConfiguration extends + CompositeReactiveHealthContributorConfiguration { + + @Bean + @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) + ReactiveHealthContributor cassandraHealthContributor(Map sessions) { + return createContributor(sessions); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(ReactiveCassandraOperations.class) + @ConditionalOnBean(ReactiveCassandraOperations.class) + static class CassandraReactiveOperationsConfiguration extends + CompositeReactiveHealthContributorConfiguration { + + @Bean + @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) + ReactiveHealthContributor cassandraHealthContributor( + Map reactiveCassandraOperations) { + return createContributor(reactiveCassandraOperations); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfiguration.java index fbe71367b8f..b6fbfdd7c82 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfiguration.java @@ -15,24 +15,19 @@ */ package org.springframework.boot.actuate.autoconfigure.cassandra; -import java.util.Map; - import com.datastax.oss.driver.api.core.CqlSession; import reactor.core.publisher.Flux; -import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; +import org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthContributorConfigurations.CassandraReactiveDriverConfiguration; +import org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthContributorConfigurations.CassandraReactiveOperationsConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; -import org.springframework.boot.actuate.health.ReactiveHealthContributor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; 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.cassandra.CassandraReactiveDataAutoConfiguration; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.cassandra.core.ReactiveCassandraOperations; +import org.springframework.context.annotation.Import; /** * {@link EnableAutoConfiguration Auto-configuration} for @@ -43,18 +38,10 @@ import org.springframework.data.cassandra.core.ReactiveCassandraOperations; * @since 2.1.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ CqlSession.class, ReactiveCassandraOperations.class, Flux.class }) -@ConditionalOnBean(ReactiveCassandraOperations.class) +@ConditionalOnClass({ CqlSession.class, Flux.class }) @ConditionalOnEnabledHealthIndicator("cassandra") @AutoConfigureAfter(CassandraReactiveDataAutoConfiguration.class) -public class CassandraReactiveHealthContributorAutoConfiguration extends - CompositeReactiveHealthContributorConfiguration { - - @Bean - @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) - public ReactiveHealthContributor cassandraHealthContributor( - Map reactiveCassandraOperations) { - return createContributor(reactiveCassandraOperations); - } +@Import({ CassandraReactiveOperationsConfiguration.class, CassandraReactiveDriverConfiguration.class }) +public class CassandraReactiveHealthContributorAutoConfiguration { } 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 c1e50891936..e297520518c 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 @@ -7,8 +7,6 @@ org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfigurat org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cassandra.CassandraReactiveHealthContributorAutoConfiguration,\ -org.springframework.boot.actuate.autoconfigure.cassandra.CassandraDriverHealthContributorAutoConfiguration,\ -org.springframework.boot.actuate.autoconfigure.cassandra.CassandraDriverReactiveHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfigurationTests.java deleted file mode 100644 index 5bdb9348809..00000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverHealthContributorAutoConfigurationTests.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.cassandra; - -import com.datastax.oss.driver.api.core.CqlSession; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; -import org.springframework.boot.actuate.cassandra.CassandraDriverHealthIndicator; -import org.springframework.boot.actuate.cassandra.CassandraDriverReactiveHealthIndicator; -import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; -import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.data.cassandra.core.CassandraOperations; -import org.springframework.data.cassandra.core.ReactiveCassandraOperations; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link CassandraDriverHealthContributorAutoConfiguration}. - * - * @author Alexandre Dutra - * @since 2.4.0 - */ -class CassandraDriverHealthContributorAutoConfigurationTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean(CqlSession.class, () -> mock(CqlSession.class)).withConfiguration(AutoConfigurations.of( - CassandraDriverHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class)); - - @Test - void runShouldCreateDriverIndicator() { - this.contextRunner.run((context) -> assertThat(context).hasSingleBean(CassandraDriverHealthIndicator.class) - .hasBean("cassandraHealthContributor").doesNotHaveBean(CassandraHealthIndicator.class) - .doesNotHaveBean(CassandraReactiveHealthIndicator.class) - .doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class)); - } - - @Test - void runWhenDisabledShouldNotCreateDriverIndicator() { - this.contextRunner.withPropertyValues("management.health.cassandra.enabled:false") - .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverHealthIndicator.class) - .doesNotHaveBean("cassandraHealthContributor")); - } - - @Test - void runWhenSpringDataPresentShouldNotCreateDriverIndicator() { - this.contextRunner.withConfiguration(AutoConfigurations.of(CassandraHealthContributorAutoConfiguration.class)) - .withBean(CassandraOperations.class, () -> mock(CassandraOperations.class)) - .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverHealthIndicator.class) - .hasSingleBean(CassandraHealthIndicator.class).hasBean("cassandraHealthContributor")); - } - - @Test - void runWhenReactorPresentShouldNotCreateDriverIndicator() { - this.contextRunner - .withConfiguration( - AutoConfigurations.of(CassandraDriverReactiveHealthContributorAutoConfiguration.class)) - .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverHealthIndicator.class) - .hasSingleBean(CassandraDriverReactiveHealthIndicator.class) - .hasBean("cassandraHealthContributor")); - } - - @Test - void runWhenSpringDataAndReactorPresentShouldNotCreateDriverIndicator() { - this.contextRunner - .withConfiguration(AutoConfigurations.of(CassandraReactiveHealthContributorAutoConfiguration.class)) - .withBean(ReactiveCassandraOperations.class, () -> mock(ReactiveCassandraOperations.class)) - .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverHealthIndicator.class) - .hasSingleBean(CassandraReactiveHealthIndicator.class).hasBean("cassandraHealthContributor")); - } - -} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfigurationTests.java deleted file mode 100644 index bf2d8edb36e..00000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraDriverReactiveHealthContributorAutoConfigurationTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.cassandra; - -import com.datastax.oss.driver.api.core.CqlSession; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; -import org.springframework.boot.actuate.cassandra.CassandraDriverReactiveHealthIndicator; -import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; -import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.data.cassandra.core.CassandraOperations; -import org.springframework.data.cassandra.core.ReactiveCassandraOperations; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link CassandraDriverReactiveHealthContributorAutoConfiguration}. - * - * @author Alexandre Dutra - * @since 2.4.0 - */ -class CassandraDriverReactiveHealthContributorAutoConfigurationTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean(CqlSession.class, () -> mock(CqlSession.class)) - .withConfiguration(AutoConfigurations.of(CassandraDriverReactiveHealthContributorAutoConfiguration.class, - HealthContributorAutoConfiguration.class)); - - @Test - void runShouldCreateDriverReactiveIndicator() { - this.contextRunner - .run((context) -> assertThat(context).hasSingleBean(CassandraDriverReactiveHealthIndicator.class) - .hasBean("cassandraHealthContributor").doesNotHaveBean(CassandraHealthIndicator.class) - .doesNotHaveBean(CassandraReactiveHealthIndicator.class)); - } - - @Test - void runWhenDisabledShouldNotCreateDriverReactiveIndicator() { - this.contextRunner.withPropertyValues("management.health.cassandra.enabled:false") - .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class) - .doesNotHaveBean("cassandraHealthContributor")); - } - - @Test - void runWhenSpringDataPresentShouldNotCreateDriverReactiveIndicator() { - this.contextRunner.withConfiguration(AutoConfigurations.of(CassandraHealthContributorAutoConfiguration.class)) - .withBean(CassandraOperations.class, () -> mock(CassandraOperations.class)) - .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class) - .hasSingleBean(CassandraHealthIndicator.class).hasBean("cassandraHealthContributor")); - } - - @Test - void runWhenSpringDataAndReactorPresentShouldNotCreateDriverReactiveIndicator() { - this.contextRunner - .withConfiguration(AutoConfigurations.of(CassandraReactiveHealthContributorAutoConfiguration.class)) - .withBean(ReactiveCassandraOperations.class, () -> mock(ReactiveCassandraOperations.class)) - .run((context) -> assertThat(context).doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class) - .hasSingleBean(CassandraReactiveHealthIndicator.class).hasBean("cassandraHealthContributor")); - } - -} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfigurationTests.java index 65baa9377b6..3b96f1a2019 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfigurationTests.java @@ -16,15 +16,15 @@ package org.springframework.boot.actuate.autoconfigure.cassandra; +import com.datastax.oss.driver.api.core.CqlSession; import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; +import org.springframework.boot.actuate.cassandra.CassandraDriverHealthIndicator; import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.core.CassandraOperations; import static org.assertj.core.api.Assertions.assertThat; @@ -34,33 +34,50 @@ import static org.mockito.Mockito.mock; * Tests for {@link CassandraHealthContributorAutoConfiguration}. * * @author Phillip Webb + * @author Stephane Nicoll */ class CassandraHealthContributorAutoConfigurationTests { - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(CassandraConfiguration.class, - CassandraHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class)); + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(CassandraHealthContributorAutoConfiguration.class, + HealthContributorAutoConfiguration.class)); @Test - void runShouldCreateIndicator() { - this.contextRunner.run((context) -> assertThat(context).hasSingleBean(CassandraHealthIndicator.class)); + void runWithoutCqlSessionOrCassandraOperationsShouldNotCreateIndicator() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean("cassandraHealthContributor") + .doesNotHaveBean(CassandraHealthIndicator.class).doesNotHaveBean(CassandraDriverHealthIndicator.class)); } @Test - void runWhenDisabledShouldNotCreateIndicator() { - this.contextRunner.withPropertyValues("management.health.cassandra.enabled:false") - .run((context) -> assertThat(context).doesNotHaveBean(CassandraHealthIndicator.class)); + void runWithCassandraOperationsShouldCreateRegularIndicator() { + this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) + .withBean(CassandraOperations.class, () -> mock(CassandraOperations.class)) + .run((context) -> assertThat(context).hasSingleBean(CassandraHealthIndicator.class) + .doesNotHaveBean(CassandraDriverHealthIndicator.class)); } - @Configuration(proxyBeanMethods = false) - @AutoConfigureBefore(CassandraHealthContributorAutoConfiguration.class) - static class CassandraConfiguration { + @Test + void runWithCqlSessionOnlyShouldCreateDriverIndicator() { + this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)).run((context) -> assertThat(context) + .hasSingleBean(CassandraDriverHealthIndicator.class).doesNotHaveBean(CassandraHealthIndicator.class)); + } - @Bean - CassandraOperations cassandraOperations() { - return mock(CassandraOperations.class); - } + @Test + void runWithCqlSessionAndSpringDataAbsentShouldCreateDriverIndicator() { + this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) + .withClassLoader(new FilteredClassLoader("org.springframework.data")) + .run((context) -> assertThat(context).hasSingleBean(CassandraDriverHealthIndicator.class) + .doesNotHaveBean(CassandraHealthIndicator.class)); + } + @Test + void runWhenDisabledShouldNotCreateIndicator() { + this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) + .withBean(CassandraOperations.class, () -> mock(CassandraOperations.class)) + .withPropertyValues("management.health.cassandra.enabled:false") + .run((context) -> assertThat(context).doesNotHaveBean("cassandraHealthContributor") + .doesNotHaveBean(CassandraHealthIndicator.class) + .doesNotHaveBean(CassandraDriverHealthIndicator.class)); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfigurationTests.java index 94d5495135f..2b28ae87060 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfigurationTests.java @@ -16,14 +16,18 @@ package org.springframework.boot.actuate.autoconfigure.cassandra; +import com.datastax.oss.driver.api.core.CqlSession; import org.junit.jupiter.api.Test; -import org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthContributorAutoConfigurationTests.CassandraConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; +import org.springframework.boot.actuate.cassandra.CassandraDriverHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraDriverReactiveHealthIndicator; import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.ReactiveCassandraOperations; import static org.assertj.core.api.Assertions.assertThat; @@ -37,31 +41,53 @@ import static org.mockito.Mockito.mock; */ class CassandraReactiveHealthContributorAutoConfigurationTests { - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean(ReactiveCassandraOperations.class, () -> mock(ReactiveCassandraOperations.class)) + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(CassandraReactiveHealthContributorAutoConfiguration.class, - HealthContributorAutoConfiguration.class)); + CassandraHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class)); @Test - void runShouldCreateIndicator() { - this.contextRunner.run((context) -> assertThat(context).hasSingleBean(CassandraReactiveHealthIndicator.class) - .hasBean("cassandraHealthContributor")); + void runWithoutCqlSessionOrReactiveCassandraOperationsShouldNotCreateIndicator() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean("cassandraHealthContributor") + .doesNotHaveBean(CassandraReactiveHealthIndicator.class) + .doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class)); } @Test - void runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() { - this.contextRunner - .withConfiguration(AutoConfigurations.of(CassandraConfiguration.class, - CassandraHealthContributorAutoConfiguration.class)) - .run((context) -> assertThat(context).hasSingleBean(CassandraReactiveHealthIndicator.class) - .hasBean("cassandraHealthContributor").doesNotHaveBean(CassandraHealthIndicator.class)); + void runWithReactiveCassandraOperationsShouldOnlyCreateReactiveIndicator() { + this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) + .withBean(ReactiveCassandraOperations.class, () -> mock(ReactiveCassandraOperations.class)) + .withBean(CassandraOperations.class, () -> mock(CassandraOperations.class)) + .run((context) -> assertThat(context).hasBean("cassandraHealthContributor") + .hasSingleBean(CassandraReactiveHealthIndicator.class) + .doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class) + .doesNotHaveBean(CassandraHealthIndicator.class) + .doesNotHaveBean(CassandraDriverHealthIndicator.class)); + } + + @Test + void runWithCqlSessionShouldCreateDriverIndicator() { + this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) + .run((context) -> assertThat(context).hasBean("cassandraHealthContributor") + .hasSingleBean(CassandraDriverReactiveHealthIndicator.class) + .doesNotHaveBean(CassandraReactiveHealthIndicator.class)); + } + + @Test + void runWithCqlSessionAndSpringDataAbsentShouldACreateDriverIndicator() { + this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) + .withClassLoader(new FilteredClassLoader("org.springframework.data")) + .run((context) -> assertThat(context).hasBean("cassandraHealthContributor") + .hasSingleBean(CassandraDriverReactiveHealthIndicator.class) + .doesNotHaveBean(CassandraReactiveHealthIndicator.class)); } @Test void runWhenDisabledShouldNotCreateIndicator() { - this.contextRunner.withPropertyValues("management.health.cassandra.enabled:false") - .run((context) -> assertThat(context).doesNotHaveBean(CassandraReactiveHealthIndicator.class) - .doesNotHaveBean("cassandraHealthContributor")); + this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) + .withBean(ReactiveCassandraOperations.class, () -> mock(ReactiveCassandraOperations.class)) + .withPropertyValues("management.health.cassandra.enabled:false") + .run((context) -> assertThat(context).doesNotHaveBean("cassandraHealthContributor") + .doesNotHaveBean(CassandraReactiveHealthIndicator.class)); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java index 75f262d51fc..bbb1468c0e7 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java @@ -30,9 +30,6 @@ import org.springframework.util.Assert; * Simple implementation of a {@link HealthIndicator} returning status information for * Cassandra data stores. * - * This health indicator is automatically used when Spring Data Cassandra is not present, - * but the Cassandra driver is. - * * @author Alexandre Dutra * @since 2.4.0 */ diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java index 04533afdc14..40483ca04ef 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java @@ -29,9 +29,6 @@ import org.springframework.util.Assert; * Simple implementation of a {@link ReactiveHealthIndicator} returning status information * for Cassandra data stores. * - * This health indicator is automatically used when Spring Data Cassandra is not present, - * but the Cassandra driver is. - * * @author Alexandre Dutra * @since 2.4.0 */ diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicatorTests.java index a6c1537091b..6cf98f77ec4 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicatorTests.java @@ -58,7 +58,6 @@ class CassandraDriverReactiveHealthIndicatorTests { given(session.executeReactive(any(SimpleStatement.class))).willReturn(results); doAnswer(mockReactiveResultSetBehavior(row)).when(results).subscribe(any()); given(row.getString(0)).willReturn("6.0.0"); - CassandraDriverReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraDriverReactiveHealthIndicator( session); Mono health = cassandraReactiveHealthIndicator.health(); @@ -74,7 +73,6 @@ class CassandraDriverReactiveHealthIndicatorTests { CqlSession session = mock(CqlSession.class); given(session.executeReactive(any(SimpleStatement.class))) .willThrow(new DriverTimeoutException("Test Exception")); - CassandraDriverReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraDriverReactiveHealthIndicator( session); Mono health = cassandraReactiveHealthIndicator.health(); diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc index a7488c79ddf..446a5eb5baa 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc @@ -655,7 +655,7 @@ The following `HealthIndicators` are auto-configured by Spring Boot when appropr |=== | Name | Description -| {spring-boot-actuator-module-code}/cassandra/CassandraHealthIndicator.java[`CassandraHealthIndicator`] +| {spring-boot-actuator-module-code}/cassandra/CassandraHealthIndicator.java[`CassandraHealthIndicator`] or {spring-boot-actuator-module-code}/cassandra/CassandraDriverHealthIndicator.java[`CassandraDriverHealthIndicator`] | Checks that a Cassandra database is up. | {spring-boot-actuator-module-code}/couchbase/CouchbaseHealthIndicator.java[`CouchbaseHealthIndicator`] @@ -830,7 +830,7 @@ The following `ReactiveHealthIndicators` are auto-configured by Spring Boot when |=== | Name | Description -| {spring-boot-actuator-module-code}/cassandra/CassandraReactiveHealthIndicator.java[`CassandraReactiveHealthIndicator`] +| {spring-boot-actuator-module-code}/cassandra/CassandraReactiveHealthIndicator.java[`CassandraReactiveHealthIndicator`] or {spring-boot-actuator-module-code}/cassandra/CassandraDriverReactiveHealthIndicator.java[`CassandraDriverReactiveHealthIndicator`] | Checks that a Cassandra database is up. | {spring-boot-actuator-module-code}/couchbase/CouchbaseReactiveHealthIndicator.java[`CouchbaseReactiveHealthIndicator`]