From f7fd0ac5273b525e9ebf1db807e5afccbc41523f Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Mon, 12 Jul 2021 16:49:47 +0200 Subject: [PATCH] Use server version from database in Neo4j health details See gh-27294 --- .../neo4j/Neo4jHealthDetailsHandler.java | 7 +++--- .../actuate/neo4j/Neo4jHealthIndicator.java | 9 +++++--- .../neo4j/Neo4jReactiveHealthIndicator.java | 12 ++++++---- .../neo4j/Neo4jHealthIndicatorTests.java | 23 ++++++++++--------- .../Neo4jReactiveHealthIndicatorTests.java | 15 ++++++------ .../boot/actuate/neo4j/ResultSummaryMock.java | 4 +--- 6 files changed, 38 insertions(+), 32 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthDetailsHandler.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthDetailsHandler.java index c5a741d3503..4834bf21356 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthDetailsHandler.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthDetailsHandler.java @@ -33,14 +33,13 @@ class Neo4jHealthDetailsHandler { /** * Add health details for the specified {@link ResultSummary} and {@code edition}. * @param builder the {@link Builder} to use + * @param version the version of the server * @param edition the edition of the server * @param resultSummary server information */ - @SuppressWarnings("deprecation") - void addHealthDetails(Builder builder, String edition, ResultSummary resultSummary) { + void addHealthDetails(Builder builder, String version, String edition, ResultSummary resultSummary) { ServerInfo serverInfo = resultSummary.server(); - builder.up().withDetail("server", serverInfo.version() + "@" + serverInfo.address()).withDetail("edition", - edition); + builder.up().withDetail("server", version + "@" + serverInfo.address()).withDetail("edition", edition); DatabaseInfo databaseInfo = resultSummary.database(); if (StringUtils.hasText(databaseInfo.name())) { builder.withDetail("database", databaseInfo.name()); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicator.java index 782be4cb2b2..bc6a69a5df2 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicator.java @@ -20,6 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.neo4j.driver.AccessMode; import org.neo4j.driver.Driver; +import org.neo4j.driver.Record; import org.neo4j.driver.Result; import org.neo4j.driver.Session; import org.neo4j.driver.SessionConfig; @@ -46,7 +47,7 @@ public class Neo4jHealthIndicator extends AbstractHealthIndicator { /** * The Cypher statement used to verify Neo4j is up. */ - static final String CYPHER = "CALL dbms.components() YIELD name, edition WHERE name = 'Neo4j Kernel' RETURN edition"; + static final String CYPHER = "CALL dbms.components() YIELD versions, name, edition WHERE name = 'Neo4j Kernel' RETURN edition, versions[0] as version"; /** * Message logged before retrying a health check. @@ -91,9 +92,11 @@ public class Neo4jHealthIndicator extends AbstractHealthIndicator { // all possible workloads try (Session session = this.driver.session(DEFAULT_SESSION_CONFIG)) { Result result = session.run(CYPHER); - String edition = result.single().get("edition").asString(); + Record record = result.single(); + String edition = record.get("edition").asString(); + String version = record.get("version").asString(); ResultSummary resultSummary = result.consume(); - this.healthDetailsHandler.addHealthDetails(builder, edition, resultSummary); + this.healthDetailsHandler.addHealthDetails(builder, version, edition, resultSummary); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicator.java index 77b8d51bcbc..7204091faad 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicator.java @@ -25,6 +25,7 @@ import org.neo4j.driver.reactive.RxSession; import org.neo4j.driver.summary.ResultSummary; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; +import reactor.util.function.Tuples; import reactor.util.retry.Retry; import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator; @@ -58,18 +59,21 @@ public final class Neo4jReactiveHealthIndicator extends AbstractReactiveHealthIn .doOnError(SessionExpiredException.class, (e) -> logger.warn(Neo4jHealthIndicator.MESSAGE_SESSION_EXPIRED)) .retryWhen(Retry.max(1).filter(SessionExpiredException.class::isInstance)).map((result) -> { - this.healthDetailsHandler.addHealthDetails(builder, result.getT1(), result.getT2()); + this.healthDetailsHandler.addHealthDetails(builder, result.getT1().getT1(), result.getT1().getT2(), + result.getT2()); return builder.build(); }); } - Mono> runHealthCheckQuery() { + Mono, ResultSummary>> runHealthCheckQuery() { // We use WRITE here to make sure UP is returned for a server that supports // all possible workloads return Mono.using(() -> this.driver.rxSession(Neo4jHealthIndicator.DEFAULT_SESSION_CONFIG), (session) -> { RxResult result = session.run(Neo4jHealthIndicator.CYPHER); - return Mono.from(result.records()).map((record) -> record.get("edition").asString()) - .zipWhen((edition) -> Mono.from(result.consume())); + return Mono.from(result.records()) + .flatMap((record) -> Mono + .just(Tuples.of(record.get("version").asString(), record.get("edition").asString())) + .zipWhen((edition) -> Mono.from(result.consume()))); }, RxSession::close); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicatorTests.java index d5c28227e64..2806f491188 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicatorTests.java @@ -51,8 +51,8 @@ class Neo4jHealthIndicatorTests { @Test void neo4jIsUp() { - ResultSummary resultSummary = ResultSummaryMock.createResultSummary("4711", "My Home", "test"); - Driver driver = mockDriver(resultSummary, "ultimate collectors edition"); + ResultSummary resultSummary = ResultSummaryMock.createResultSummary("My Home", "test"); + Driver driver = mockDriver(resultSummary, "4711", "ultimate collectors edition"); Health health = new Neo4jHealthIndicator(driver).health(); assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getDetails()).containsEntry("server", "4711@My Home"); @@ -62,8 +62,8 @@ class Neo4jHealthIndicatorTests { @Test void neo4jIsUpWithoutDatabaseName() { - ResultSummary resultSummary = ResultSummaryMock.createResultSummary("4711", "My Home", null); - Driver driver = mockDriver(resultSummary, "some edition"); + ResultSummary resultSummary = ResultSummaryMock.createResultSummary("My Home", null); + Driver driver = mockDriver(resultSummary, "4711", "some edition"); Health health = new Neo4jHealthIndicator(driver).health(); assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getDetails()).containsEntry("server", "4711@My Home"); @@ -73,8 +73,8 @@ class Neo4jHealthIndicatorTests { @Test void neo4jIsUpWithEmptyDatabaseName() { - ResultSummary resultSummary = ResultSummaryMock.createResultSummary("4711", "My Home", ""); - Driver driver = mockDriver(resultSummary, "some edition"); + ResultSummary resultSummary = ResultSummaryMock.createResultSummary("My Home", ""); + Driver driver = mockDriver(resultSummary, "4711", "some edition"); Health health = new Neo4jHealthIndicator(driver).health(); assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getDetails()).containsEntry("server", "4711@My Home"); @@ -84,9 +84,9 @@ class Neo4jHealthIndicatorTests { @Test void neo4jIsUpWithOneSessionExpiredException() { - ResultSummary resultSummary = ResultSummaryMock.createResultSummary("4711", "My Home", ""); + ResultSummary resultSummary = ResultSummaryMock.createResultSummary("My Home", ""); Session session = mock(Session.class); - Result statementResult = mockStatementResult(resultSummary, "some edition"); + Result statementResult = mockStatementResult(resultSummary, "4711", "some edition"); AtomicInteger count = new AtomicInteger(); given(session.run(anyString())).will((invocation) -> { if (count.compareAndSet(0, 1)) { @@ -112,17 +112,18 @@ class Neo4jHealthIndicatorTests { assertThat(health.getDetails()).containsKeys("error"); } - private Result mockStatementResult(ResultSummary resultSummary, String edition) { + private Result mockStatementResult(ResultSummary resultSummary, String version, String edition) { Record record = mock(Record.class); given(record.get("edition")).willReturn(Values.value(edition)); + given(record.get("version")).willReturn(Values.value(version)); Result statementResult = mock(Result.class); given(statementResult.single()).willReturn(record); given(statementResult.consume()).willReturn(resultSummary); return statementResult; } - private Driver mockDriver(ResultSummary resultSummary, String edition) { - Result statementResult = mockStatementResult(resultSummary, edition); + private Driver mockDriver(ResultSummary resultSummary, String version, String edition) { + Result statementResult = mockStatementResult(resultSummary, version, edition); Session session = mock(Session.class); given(session.run(anyString())).willReturn(statementResult); Driver driver = mock(Driver.class); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicatorTests.java index 61b721b2ac3..48af288c9d2 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicatorTests.java @@ -51,8 +51,8 @@ class Neo4jReactiveHealthIndicatorTests { @Test void neo4jIsUp() { - ResultSummary resultSummary = ResultSummaryMock.createResultSummary("4711", "My Home", "test"); - Driver driver = mockDriver(resultSummary, "ultimate collectors edition"); + ResultSummary resultSummary = ResultSummaryMock.createResultSummary("My Home", "test"); + Driver driver = mockDriver(resultSummary, "4711", "ultimate collectors edition"); Neo4jReactiveHealthIndicator healthIndicator = new Neo4jReactiveHealthIndicator(driver); healthIndicator.health().as(StepVerifier::create).consumeNextWith((health) -> { assertThat(health.getStatus()).isEqualTo(Status.UP); @@ -63,9 +63,9 @@ class Neo4jReactiveHealthIndicatorTests { @Test void neo4jIsUpWithOneSessionExpiredException() { - ResultSummary resultSummary = ResultSummaryMock.createResultSummary("4711", "My Home", ""); + ResultSummary resultSummary = ResultSummaryMock.createResultSummary("My Home", ""); RxSession session = mock(RxSession.class); - RxResult statementResult = mockStatementResult(resultSummary, "some edition"); + RxResult statementResult = mockStatementResult(resultSummary, "4711", "some edition"); AtomicInteger count = new AtomicInteger(); given(session.run(anyString())).will((invocation) -> { if (count.compareAndSet(0, 1)) { @@ -95,17 +95,18 @@ class Neo4jReactiveHealthIndicatorTests { }).verifyComplete(); } - private RxResult mockStatementResult(ResultSummary resultSummary, String edition) { + private RxResult mockStatementResult(ResultSummary resultSummary, String version, String edition) { Record record = mock(Record.class); given(record.get("edition")).willReturn(Values.value(edition)); + given(record.get("version")).willReturn(Values.value(version)); RxResult statementResult = mock(RxResult.class); given(statementResult.records()).willReturn(Mono.just(record)); given(statementResult.consume()).willReturn(Mono.just(resultSummary)); return statementResult; } - private Driver mockDriver(ResultSummary resultSummary, String edition) { - RxResult statementResult = mockStatementResult(resultSummary, edition); + private Driver mockDriver(ResultSummary resultSummary, String version, String edition) { + RxResult statementResult = mockStatementResult(resultSummary, version, edition); RxSession session = mock(RxSession.class); given(session.run(anyString())).willReturn(statementResult); Driver driver = mock(Driver.class); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/ResultSummaryMock.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/ResultSummaryMock.java index 678b5363524..026ed868c52 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/ResultSummaryMock.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/ResultSummaryMock.java @@ -33,10 +33,8 @@ final class ResultSummaryMock { private ResultSummaryMock() { } - @SuppressWarnings("deprecation") - static ResultSummary createResultSummary(String serverVersion, String serverAddress, String databaseName) { + static ResultSummary createResultSummary(String serverAddress, String databaseName) { ServerInfo serverInfo = mock(ServerInfo.class); - given(serverInfo.version()).willReturn(serverVersion); given(serverInfo.address()).willReturn(serverAddress); DatabaseInfo databaseInfo = mock(DatabaseInfo.class); given(databaseInfo.name()).willReturn(databaseName);