This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 4ad5014a92c16f79389013e8dec46abef828fc00 Author: Gautier DI FOLCO <[email protected]> AuthorDate: Mon Apr 6 17:45:26 2020 +0200 JAMES-3134 Check RabbitMQ version at start up --- .../backends/rabbitmq/RabbitMQHealthCheck.java | 15 ++++ .../backends/rabbitmq/RabbitMQServerVersion.java | 70 ++++++++++++++++ .../backends/rabbitmq/SimpleConnectionPool.java | 13 +++ .../rabbitmq/RabbitMQServerVersionTest.java | 96 ++++++++++++++++++++++ 4 files changed, 194 insertions(+) diff --git a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQHealthCheck.java b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQHealthCheck.java index 09a03df..a5e6d00 100644 --- a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQHealthCheck.java +++ b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQHealthCheck.java @@ -19,6 +19,8 @@ package org.apache.james.backends.rabbitmq; +import java.util.Optional; + import javax.inject.Inject; import org.apache.james.core.healthcheck.ComponentName; @@ -26,6 +28,7 @@ import org.apache.james.core.healthcheck.HealthCheck; import org.apache.james.core.healthcheck.Result; public class RabbitMQHealthCheck implements HealthCheck { + private static final RabbitMQServerVersion MINIMAL_VERSION = RabbitMQServerVersion.of("3.8.1"); private static final ComponentName COMPONENT_NAME = new ComponentName("RabbitMQ backend"); private final SimpleConnectionPool connectionPool; @@ -46,6 +49,18 @@ public class RabbitMQHealthCheck implements HealthCheck { public Result check() { try { if (connectionPool.tryConnection() && rabbitChannelPoolImpl.tryChannel()) { + Optional<RabbitMQServerVersion> version = connectionPool.version(); + boolean isCompatible = version + .map(fetchedVersion -> fetchedVersion.isAtLeast(MINIMAL_VERSION)) + .orElse(false); + if (!isCompatible) { + String versionCompatibilityError = String.format( + "RabbitMQ version(%s) is not compatible with the required one(%s)", + version.map(RabbitMQServerVersion::asString).orElse("no versions fetched"), + MINIMAL_VERSION.asString()); + return Result.unhealthy(COMPONENT_NAME, versionCompatibilityError); + } + return Result.healthy(COMPONENT_NAME); } else { return Result.unhealthy(COMPONENT_NAME, "The created connection was not opened"); diff --git a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQServerVersion.java b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQServerVersion.java new file mode 100644 index 0000000..a0500c8 --- /dev/null +++ b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQServerVersion.java @@ -0,0 +1,70 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you 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 * + * * + * http://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.apache.james.backends.rabbitmq; + +import java.util.Objects; + +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.core.util.VersionUtil; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; + +public class RabbitMQServerVersion { + public static RabbitMQServerVersion of(String input) { + return new RabbitMQServerVersion(VersionUtil.parseVersion(input, "rabbitmq", "version")); + } + + private final Version version; + + @VisibleForTesting + RabbitMQServerVersion(Version version) { + this.version = version; + } + + public boolean isAtLeast(RabbitMQServerVersion other) { + return version.compareTo(other.version) >= 0; + } + + public String asString() { + return version.toFullString(); + } + + @Override + public final boolean equals(Object other) { + if (other instanceof RabbitMQServerVersion) { + RabbitMQServerVersion that = (RabbitMQServerVersion) other; + return Objects.equals(version, that.version); + } + + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(version); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("version", version) + .toString(); + } +} diff --git a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/SimpleConnectionPool.java b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/SimpleConnectionPool.java index 0354002..6aa1ba5 100644 --- a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/SimpleConnectionPool.java +++ b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/SimpleConnectionPool.java @@ -88,4 +88,17 @@ public class SimpleConnectionPool implements AutoCloseable { return false; } } + + public Optional<RabbitMQServerVersion> version() { + try { + return getOpenConnection() + .map(Connection::getServerProperties) + .flatMap(serverProperties -> Mono.justOrEmpty(serverProperties.get("version"))) + .map(Object::toString) + .map(RabbitMQServerVersion::of) + .blockOptional(Duration.ofSeconds(1)); + } catch (Throwable t) { + return Optional.empty(); + } + } } diff --git a/backends-common/rabbitmq/src/test/java/org/apache/james/backends/rabbitmq/RabbitMQServerVersionTest.java b/backends-common/rabbitmq/src/test/java/org/apache/james/backends/rabbitmq/RabbitMQServerVersionTest.java new file mode 100644 index 0000000..a90c9c9 --- /dev/null +++ b/backends-common/rabbitmq/src/test/java/org/apache/james/backends/rabbitmq/RabbitMQServerVersionTest.java @@ -0,0 +1,96 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you 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 * + * * + * http://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.apache.james.backends.rabbitmq; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import com.fasterxml.jackson.core.Version; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class RabbitMQServerVersionTest { + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(RabbitMQServerVersion.class) + .verify(); + } + + @ParameterizedTest + @MethodSource("versionsToParse") + void shouldParseVersion(String input, Version expected) { + assertThat(RabbitMQServerVersion.of(input)).isEqualTo(new RabbitMQServerVersion(expected)); + } + + @ParameterizedTest + @MethodSource("versionsComparison") + void shouldBeAtLeast(String lower, String upper) { + RabbitMQServerVersion lowerVersion = RabbitMQServerVersion.of(lower); + RabbitMQServerVersion upperVersion = RabbitMQServerVersion.of(upper); + assertThat(upperVersion.isAtLeast(lowerVersion)).isTrue(); + } + + @ParameterizedTest + @MethodSource("versionsReversedComparison") + void shouldNotBeAtLeastWhenReversed(String lower, String upper) { + RabbitMQServerVersion lowerVersion = RabbitMQServerVersion.of(lower); + RabbitMQServerVersion upperVersion = RabbitMQServerVersion.of(upper); + assertThat(lowerVersion.isAtLeast(upperVersion)).isFalse(); + } + + static Stream<Arguments> versionsToParse() { + return Stream.of( + Arguments.of("3.8.1", version(3, 8, 1)), + Arguments.of("3.18.1", version(3, 18, 1)), + Arguments.of("3.8.", version(3, 8, 0)), + Arguments.of("3.8.0+beta.4.38.g33a7f97", version(3, 8, 0)), + Arguments.of("3.7.1-alpha.40", version(3, 7, 1)), + Arguments.of("3.7.0~alpha.449-1", version(3, 7, 0)) + ); + } + + static Stream<Arguments> versionsComparison() { + return Stream.of( + Arguments.of("3.8.1", "3.8.1"), + Arguments.of("3.18.1", "3.18.1"), + Arguments.of("3.8.", "3.8.0"), + Arguments.of("3.7.5", "3.8.1"), + Arguments.of("3.8", "3.8.1"), + Arguments.of("3.8.0", "4.0.0") + ); + } + + static Stream<Arguments> versionsReversedComparison() { + return Stream.of( + Arguments.of("3.7.5", "3.8.1"), + Arguments.of("3.8", "3.8.1"), + Arguments.of("3.8.0", "4.0.0") + ); + } + + private static Version version(int major, int minor, int patch) { + return new Version(major, minor, patch, "", "rabbitmq", "version"); + } +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
