Move code from spring-boot-actuator to spring-boot-data-mongodb

This commit is contained in:
Andy Wilkinson
2025-05-09 14:57:35 +01:00
committed by Phillip Webb
parent 3866abb2ca
commit 631653cd1d
13 changed files with 34 additions and 28 deletions

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2012-2025 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.data.mongodb.actuate.health;
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.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.testsupport.container.TestImage;
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 = TestImage.container(MongoDBContainer.class);
@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);
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2012-2025 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.data.mongodb.actuate.health;
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.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.testsupport.container.TestImage;
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 = TestImage.container(MongoDBContainer.class);
@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));
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2012-2025 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.data.mongodb.actuate.health;
import org.bson.Document;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.util.Assert;
/**
* Simple implementation of a {@link HealthIndicator} returning status information for
* Mongo data stores.
*
* @author Christian Dupuis
* @since 2.0.0
*/
public class MongoHealthIndicator extends AbstractHealthIndicator {
private final MongoTemplate mongoTemplate;
public MongoHealthIndicator(MongoTemplate mongoTemplate) {
super("MongoDB health check failed");
Assert.notNull(mongoTemplate, "'mongoTemplate' must not be null");
this.mongoTemplate = mongoTemplate;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Document result = this.mongoTemplate.executeCommand("{ hello: 1 }");
builder.up().withDetail("maxWireVersion", result.getInteger("maxWireVersion"));
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2012-2025 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.data.mongodb.actuate.health;
import org.bson.Document;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.util.Assert;
/**
* A {@link ReactiveHealthIndicator} for Mongo.
*
* @author Yulin Qin
* @since 2.0.0
*/
public class MongoReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
private final ReactiveMongoTemplate reactiveMongoTemplate;
public MongoReactiveHealthIndicator(ReactiveMongoTemplate reactiveMongoTemplate) {
super("Mongo health check failed");
Assert.notNull(reactiveMongoTemplate, "'reactiveMongoTemplate' must not be null");
this.reactiveMongoTemplate = reactiveMongoTemplate;
}
@Override
protected Mono<Health> doHealthCheck(Health.Builder builder) {
Mono<Document> buildInfo = this.reactiveMongoTemplate.executeCommand("{ hello: 1 }");
return buildInfo.map((document) -> up(builder, document));
}
private Health up(Health.Builder builder, Document document) {
return builder.up().withDetail("maxWireVersion", document.getInteger("maxWireVersion")).build();
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* MongoDB health integration using Spring Data MongoDB.
*/
package org.springframework.boot.data.mongodb.actuate.health;

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2012-2025 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.data.mongodb.actuate.health;
import com.mongodb.MongoException;
import org.bson.Document;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.data.mongodb.core.MongoTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link MongoHealthIndicator}.
*
* @author Christian Dupuis
*/
class MongoHealthIndicatorTests {
@Test
void mongoIsUp() {
Document commandResult = mock(Document.class);
given(commandResult.getInteger("maxWireVersion")).willReturn(10);
MongoTemplate mongoTemplate = mock(MongoTemplate.class);
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("{ hello: 1 }");
}
@Test
void mongoIsDown() {
MongoTemplate mongoTemplate = mock(MongoTemplate.class);
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("{ hello: 1 }");
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2012-2025 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.data.mongodb.actuate.health;
import java.time.Duration;
import com.mongodb.MongoException;
import org.bson.Document;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link MongoReactiveHealthIndicator}.
*
* @author Yulin Qin
*/
class MongoReactiveHealthIndicatorTests {
@Test
void testMongoIsUp() {
Document buildInfo = mock(Document.class);
given(buildInfo.getInteger("maxWireVersion")).willReturn(10);
ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class);
given(reactiveMongoTemplate.executeCommand("{ hello: 1 }")).willReturn(Mono.just(buildInfo));
MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(
reactiveMongoTemplate);
Mono<Health> health = mongoReactiveHealthIndicator.health();
StepVerifier.create(health).consumeNextWith((h) -> {
assertThat(h.getStatus()).isEqualTo(Status.UP);
assertThat(h.getDetails()).containsOnlyKeys("maxWireVersion");
assertThat(h.getDetails()).containsEntry("maxWireVersion", 10);
}).expectComplete().verify(Duration.ofSeconds(30));
}
@Test
void testMongoIsDown() {
ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class);
given(reactiveMongoTemplate.executeCommand("{ hello: 1 }")).willThrow(new MongoException("Connection failed"));
MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(
reactiveMongoTemplate);
Mono<Health> health = mongoReactiveHealthIndicator.health();
StepVerifier.create(health).consumeNextWith((h) -> {
assertThat(h.getStatus()).isEqualTo(Status.DOWN);
assertThat(h.getDetails()).containsOnlyKeys("error");
assertThat(h.getDetails()).containsEntry("error", MongoException.class.getName() + ": Connection failed");
}).expectComplete().verify(Duration.ofSeconds(30));
}
}