Move code from spring-boot-actuator to spring-boot-couchbase

This commit is contained in:
Andy Wilkinson
2025-05-09 11:28:13 +01:00
committed by Phillip Webb
parent ec0370bc2e
commit 0c55d5beb8
12 changed files with 25 additions and 25 deletions

View File

@@ -0,0 +1,69 @@
/*
* 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.couchbase.actuate.health;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.couchbase.client.core.diagnostics.ClusterState;
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
import org.springframework.boot.actuate.health.Health.Builder;
/**
* Details of Couchbase's health.
*
* @author Andy Wilkinson
*/
class CouchbaseHealth {
private final DiagnosticsResult diagnostics;
CouchbaseHealth(DiagnosticsResult diagnostics) {
this.diagnostics = diagnostics;
}
void applyTo(Builder builder) {
builder = isCouchbaseUp(this.diagnostics) ? builder.up() : builder.down();
builder.withDetail("sdk", this.diagnostics.sdk());
builder.withDetail("endpoints",
this.diagnostics.endpoints()
.values()
.stream()
.flatMap(Collection::stream)
.map(this::describe)
.toList());
}
private boolean isCouchbaseUp(DiagnosticsResult diagnostics) {
return diagnostics.state() == ClusterState.ONLINE;
}
private Map<String, Object> describe(EndpointDiagnostics endpointHealth) {
Map<String, Object> map = new HashMap<>();
map.put("id", endpointHealth.id());
map.put("lastActivity", endpointHealth.lastActivity());
map.put("local", endpointHealth.local());
map.put("remote", endpointHealth.remote());
map.put("state", endpointHealth.state());
map.put("type", endpointHealth.type());
return map;
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.couchbase.actuate.health;
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
import com.couchbase.client.java.Cluster;
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;
/**
* {@link HealthIndicator} for Couchbase.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 4.0.0
*/
public class CouchbaseHealthIndicator extends AbstractHealthIndicator {
private final Cluster cluster;
/**
* Create an indicator with the specified {@link Cluster}.
* @param cluster the Couchbase Cluster
* @since 2.0.6
*/
public CouchbaseHealthIndicator(Cluster cluster) {
super("Couchbase health check failed");
Assert.notNull(cluster, "'cluster' must not be null");
this.cluster = cluster;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
DiagnosticsResult diagnostics = this.cluster.diagnostics();
new CouchbaseHealth(diagnostics).applyTo(builder);
}
}

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.couchbase.actuate.health;
import com.couchbase.client.java.Cluster;
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;
/**
* A {@link ReactiveHealthIndicator} for Couchbase.
*
* @author Mikalai Lushchytski
* @author Stephane Nicoll
* @since 4.0.0
*/
public class CouchbaseReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
private final Cluster cluster;
/**
* Create a new {@link CouchbaseReactiveHealthIndicator} instance.
* @param cluster the Couchbase cluster
*/
public CouchbaseReactiveHealthIndicator(Cluster cluster) {
super("Couchbase health check failed");
this.cluster = cluster;
}
@Override
protected Mono<Health> doHealthCheck(Health.Builder builder) {
return this.cluster.reactive().diagnostics().map((diagnostics) -> {
new CouchbaseHealth(diagnostics).applyTo(builder);
return builder.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.
*/
/**
* Health integration for Couchbase.
*/
package org.springframework.boot.couchbase.actuate.health;

View File

@@ -0,0 +1,92 @@
/*
* 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.couchbase.actuate.health;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
import com.couchbase.client.core.endpoint.CircuitBreaker;
import com.couchbase.client.core.endpoint.EndpointState;
import com.couchbase.client.core.service.ServiceType;
import com.couchbase.client.java.Cluster;
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.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link CouchbaseHealthIndicator}
*
* @author Eddú Meléndez
* @author Stephane Nicoll
*/
class CouchbaseHealthIndicatorTests {
@Test
@SuppressWarnings("unchecked")
void couchbaseClusterIsUp() {
Cluster cluster = mock(Cluster.class);
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(cluster);
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
Collections.singletonList(new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED,
CircuitBreaker.State.DISABLED, "127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
Optional.of("endpoint-1"), Optional.empty())));
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
given(cluster.diagnostics()).willReturn(diagnostics);
Health health = healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("sdk", "test-sdk");
assertThat(health.getDetails()).containsKey("endpoints");
assertThat((List<Map<String, Object>>) health.getDetails().get("endpoints")).hasSize(1);
then(cluster).should().diagnostics();
}
@Test
@SuppressWarnings("unchecked")
void couchbaseClusterIsDown() {
Cluster cluster = mock(Cluster.class);
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(cluster);
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
Arrays.asList(
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, CircuitBreaker.State.DISABLED,
"127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
Optional.of("endpoint-1"), Optional.empty()),
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTING, CircuitBreaker.State.DISABLED,
"127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
Optional.of("endpoint-2"), Optional.empty())));
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
given(cluster.diagnostics()).willReturn(diagnostics);
Health health = healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).containsEntry("sdk", "test-sdk");
assertThat(health.getDetails()).containsKey("endpoints");
assertThat((List<Map<String, Object>>) health.getDetails().get("endpoints")).hasSize(2);
then(cluster).should().diagnostics();
}
}

View File

@@ -0,0 +1,95 @@
/*
* 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.couchbase.actuate.health;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
import com.couchbase.client.core.endpoint.CircuitBreaker;
import com.couchbase.client.core.endpoint.EndpointState;
import com.couchbase.client.core.service.ServiceType;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.ReactiveCluster;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
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.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link CouchbaseReactiveHealthIndicator}.
*/
class CouchbaseReactiveHealthIndicatorTests {
@Test
@SuppressWarnings("unchecked")
void couchbaseClusterIsUp() {
Cluster cluster = mock(Cluster.class);
CouchbaseReactiveHealthIndicator healthIndicator = new CouchbaseReactiveHealthIndicator(cluster);
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
Collections.singletonList(new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED,
CircuitBreaker.State.DISABLED, "127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
Optional.of("endpoint-1"), Optional.empty())));
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
ReactiveCluster reactiveCluster = mock(ReactiveCluster.class);
given(reactiveCluster.diagnostics()).willReturn(Mono.just(diagnostics));
given(cluster.reactive()).willReturn(reactiveCluster);
Health health = healthIndicator.health().block(Duration.ofSeconds(30));
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("sdk", "test-sdk");
assertThat(health.getDetails()).containsKey("endpoints");
assertThat((List<Map<String, Object>>) health.getDetails().get("endpoints")).hasSize(1);
then(reactiveCluster).should().diagnostics();
}
@Test
@SuppressWarnings("unchecked")
void couchbaseClusterIsDown() {
Cluster cluster = mock(Cluster.class);
CouchbaseReactiveHealthIndicator healthIndicator = new CouchbaseReactiveHealthIndicator(cluster);
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
Arrays.asList(
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, CircuitBreaker.State.DISABLED,
"127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
Optional.of("endpoint-1"), Optional.empty()),
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTING, CircuitBreaker.State.DISABLED,
"127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
Optional.of("endpoint-2"), Optional.empty())));
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
ReactiveCluster reactiveCluster = mock(ReactiveCluster.class);
given(reactiveCluster.diagnostics()).willReturn(Mono.just(diagnostics));
given(cluster.reactive()).willReturn(reactiveCluster);
Health health = healthIndicator.health().block(Duration.ofSeconds(30));
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).containsEntry("sdk", "test-sdk");
assertThat(health.getDetails()).containsKey("endpoints");
assertThat((List<Map<String, Object>>) health.getDetails().get("endpoints")).hasSize(2);
then(reactiveCluster).should().diagnostics();
}
}