diff --git a/spring-boot-project/spring-boot-actuator/build.gradle b/spring-boot-project/spring-boot-actuator/build.gradle index 98caa5d11f0..3dbf075f41a 100644 --- a/spring-boot-project/spring-boot-actuator/build.gradle +++ b/spring-boot-project/spring-boot-actuator/build.gradle @@ -101,6 +101,7 @@ dependencies { testImplementation("org.springframework:spring-test") testImplementation("com.squareup.okhttp3:mockwebserver") testImplementation("org.testcontainers:junit-jupiter") + testImplementation("org.testcontainers:mongodb") testImplementation("org.testcontainers:neo4j") testImplementation("org.testcontainers:testcontainers") diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoHealthIndicator.java index 75fba5119f5..307fa646c8c 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoHealthIndicator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -43,7 +43,7 @@ public class MongoHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Health.Builder builder) throws Exception { - Document result = this.mongoTemplate.executeCommand("{ isMaster: 1 }"); + Document result = this.mongoTemplate.executeCommand("{ hello: 1 }"); builder.up().withDetail("maxWireVersion", result.getInteger("maxWireVersion")); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoReactiveHealthIndicator.java index aaa96e93a5c..39a3b6bb142 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoReactiveHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoReactiveHealthIndicator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -43,7 +43,7 @@ public class MongoReactiveHealthIndicator extends AbstractReactiveHealthIndicato @Override protected Mono doHealthCheck(Health.Builder builder) { - Mono buildInfo = this.reactiveMongoTemplate.executeCommand("{ isMaster: 1 }"); + Mono buildInfo = this.reactiveMongoTemplate.executeCommand("{ hello: 1 }"); return buildInfo.map((document) -> up(builder, document)); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoHealthIndicatorIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoHealthIndicatorIntegrationTests.java new file mode 100644 index 00000000000..04d41750153 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoHealthIndicatorIntegrationTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012-2024 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.mongo; + +import java.time.Duration; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoClientSettings.Builder; +import com.mongodb.ServerApi; +import com.mongodb.ServerApiVersion; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.boot.actuate.data.mongo.MongoHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; +import org.springframework.boot.testsupport.testcontainers.DockerImageNames; +import org.springframework.data.mongodb.core.MongoTemplate; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link MongoHealthIndicator}. + * + * @author Andy Wilkinson + */ +@Testcontainers(disabledWithoutDocker = true) +class MongoHealthIndicatorIntegrationTests { + + @Container + static MongoDBContainer mongo = new MongoDBContainer(DockerImageNames.mongo()).withStartupAttempts(3) + .withStartupTimeout(Duration.ofMinutes(2)); + + @Test + void standardApi() { + Health health = mongoHealth(); + assertThat(health.getStatus()).isEqualTo(Status.UP); + } + + @Test + void strictV1Api() { + Health health = mongoHealth(ServerApi.builder().strict(true).version(ServerApiVersion.V1).build()); + assertThat(health.getStatus()).isEqualTo(Status.UP); + } + + private Health mongoHealth() { + return mongoHealth(null); + } + + private Health mongoHealth(ServerApi serverApi) { + Builder settingsBuilder = MongoClientSettings.builder() + .applyConnectionString(new ConnectionString(mongo.getConnectionString())); + if (serverApi != null) { + settingsBuilder.serverApi(serverApi); + } + MongoClientSettings settings = settingsBuilder.build(); + MongoClient mongoClient = MongoClients.create(settings); + MongoHealthIndicator healthIndicator = new MongoHealthIndicator(new MongoTemplate(mongoClient, "db")); + return healthIndicator.getHealth(true); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoHealthIndicatorTests.java index 8999c692984..d4b4d403c65 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoHealthIndicatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -42,24 +42,24 @@ class MongoHealthIndicatorTests { Document commandResult = mock(Document.class); given(commandResult.getInteger("maxWireVersion")).willReturn(10); MongoTemplate mongoTemplate = mock(MongoTemplate.class); - given(mongoTemplate.executeCommand("{ isMaster: 1 }")).willReturn(commandResult); + given(mongoTemplate.executeCommand("{ hello: 1 }")).willReturn(commandResult); MongoHealthIndicator healthIndicator = new MongoHealthIndicator(mongoTemplate); Health health = healthIndicator.health(); assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getDetails()).containsEntry("maxWireVersion", 10); then(commandResult).should().getInteger("maxWireVersion"); - then(mongoTemplate).should().executeCommand("{ isMaster: 1 }"); + then(mongoTemplate).should().executeCommand("{ hello: 1 }"); } @Test void mongoIsDown() { MongoTemplate mongoTemplate = mock(MongoTemplate.class); - given(mongoTemplate.executeCommand("{ isMaster: 1 }")).willThrow(new MongoException("Connection failed")); + given(mongoTemplate.executeCommand("{ hello: 1 }")).willThrow(new MongoException("Connection failed")); MongoHealthIndicator healthIndicator = new MongoHealthIndicator(mongoTemplate); Health health = healthIndicator.health(); assertThat(health.getStatus()).isEqualTo(Status.DOWN); assertThat((String) health.getDetails().get("error")).contains("Connection failed"); - then(mongoTemplate).should().executeCommand("{ isMaster: 1 }"); + then(mongoTemplate).should().executeCommand("{ hello: 1 }"); } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorIntegrationTests.java new file mode 100644 index 00000000000..bb19d0e8966 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorIntegrationTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2024 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.mongo; + +import java.time.Duration; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoClientSettings.Builder; +import com.mongodb.ServerApi; +import com.mongodb.ServerApiVersion; +import com.mongodb.reactivestreams.client.MongoClient; +import com.mongodb.reactivestreams.client.MongoClients; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.boot.actuate.data.mongo.MongoReactiveHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; +import org.springframework.boot.testsupport.testcontainers.DockerImageNames; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link MongoReactiveHealthIndicator}. + * + * @author Andy Wilkinson + */ +@Testcontainers(disabledWithoutDocker = true) +class MongoReactiveHealthIndicatorIntegrationTests { + + @Container + static MongoDBContainer mongo = new MongoDBContainer(DockerImageNames.mongo()).withStartupAttempts(3) + .withStartupTimeout(Duration.ofMinutes(2)); + + @Test + void standardApi() { + Health health = mongoHealth(); + assertThat(health.getStatus()).isEqualTo(Status.UP); + } + + @Test + void strictV1Api() { + Health health = mongoHealth(ServerApi.builder().strict(true).version(ServerApiVersion.V1).build()); + assertThat(health.getStatus()).isEqualTo(Status.UP); + } + + private Health mongoHealth() { + return mongoHealth(null); + } + + private Health mongoHealth(ServerApi serverApi) { + Builder settingsBuilder = MongoClientSettings.builder() + .applyConnectionString(new ConnectionString(mongo.getConnectionString())); + if (serverApi != null) { + settingsBuilder.serverApi(serverApi); + } + MongoClientSettings settings = settingsBuilder.build(); + MongoClient mongoClient = MongoClients.create(settings); + MongoReactiveHealthIndicator healthIndicator = new MongoReactiveHealthIndicator( + new ReactiveMongoTemplate(mongoClient, "db")); + return healthIndicator.getHealth(true).block(Duration.ofSeconds(30)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorTests.java index 91a2ae9615f..2b942028dfe 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/mongo/MongoReactiveHealthIndicatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -45,7 +45,7 @@ class MongoReactiveHealthIndicatorTests { Document buildInfo = mock(Document.class); given(buildInfo.getInteger("maxWireVersion")).willReturn(10); ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class); - given(reactiveMongoTemplate.executeCommand("{ isMaster: 1 }")).willReturn(Mono.just(buildInfo)); + given(reactiveMongoTemplate.executeCommand("{ hello: 1 }")).willReturn(Mono.just(buildInfo)); MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator( reactiveMongoTemplate); Mono health = mongoReactiveHealthIndicator.health(); @@ -59,8 +59,7 @@ class MongoReactiveHealthIndicatorTests { @Test void testMongoIsDown() { ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class); - given(reactiveMongoTemplate.executeCommand("{ isMaster: 1 }")) - .willThrow(new MongoException("Connection failed")); + given(reactiveMongoTemplate.executeCommand("{ hello: 1 }")).willThrow(new MongoException("Connection failed")); MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator( reactiveMongoTemplate); Mono health = mongoReactiveHealthIndicator.health(); diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-session-mongo/src/test/java/smoketest/session/mongodb/SampleSessionMongoApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-session-mongo/src/test/java/smoketest/session/mongodb/SampleSessionMongoApplicationTests.java index 2846e2fb4bd..68a49a26387 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-session-mongo/src/test/java/smoketest/session/mongodb/SampleSessionMongoApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-session-mongo/src/test/java/smoketest/session/mongodb/SampleSessionMongoApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -80,14 +80,6 @@ class SampleSessionMongoApplicationTests { assertThat(sessions).hasSize(1); } - @Test - void health() { - ResponseEntity entity = this.restTemplate - .getForEntity("http://localhost:" + this.port + "/actuator/health", String.class); - assertThat(entity.getBody()).contains("\"status\":\"UP\""); - assertThat(entity.getBody()).contains("maxWireVersion"); - } - private String performLogin() { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));