You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2019/05/16 08:48:37 UTC

[james-project] 22/23: JAMES-2763 CassandraSchemaVersion StartUpCheck

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 201328786d3a5e4fcb33f18c2763010fe9ccd32e
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Wed May 15 16:56:16 2019 +0700

    JAMES-2763 CassandraSchemaVersion StartUpCheck
---
 .../CassandraSchemaVersionStartUpCheck.java        | 116 +++++++++++++++++++++
 .../modules/mailbox/CassandraSessionModule.java    |  54 +---------
 .../CassandraSchemaVersionStartUpCheckTest.java}   |  42 +++++---
 .../org/apache/james/StartUpChecksPerformer.java   |  15 ++-
 4 files changed, 159 insertions(+), 68 deletions(-)

diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSchemaVersionStartUpCheck.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSchemaVersionStartUpCheck.java
new file mode 100644
index 0000000..0e6b24a
--- /dev/null
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSchemaVersionStartUpCheck.java
@@ -0,0 +1,116 @@
+/****************************************************************
+ * 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.modules.mailbox;
+
+import org.apache.james.StartUpChecksPerformer;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+
+public class CassandraSchemaVersionStartUpCheck implements StartUpChecksPerformer.StartUpCheck {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CassandraSchemaVersionStartUpCheck.class);
+    static final String CHECK_NAME = "CassandraSchemaVersionStartUpCheck";
+
+    private final CassandraSchemaVersionManager versionManager;
+
+    @Inject
+    public CassandraSchemaVersionStartUpCheck(CassandraSchemaVersionManager versionManager) {
+        this.versionManager = versionManager;
+    }
+
+    @Override
+    public CheckResult check() {
+        CassandraSchemaVersionManager.SchemaState schemaState = versionManager.computeSchemaState();
+        switch (schemaState) {
+            case TOO_OLD:
+                return checkTooOldState();
+            case TOO_RECENT:
+                return checkTooRecentState();
+            case UP_TO_DATE:
+                return checkUpToDateState();
+            case UPGRADABLE:
+                return checkUpgradeAbleState();
+            default:
+                String unknownSchemaStateMessage = "Unknown schema state " + schemaState;
+                LOGGER.error(unknownSchemaStateMessage);
+                return CheckResult.builder()
+                    .checkName(CHECK_NAME)
+                    .resultType(ResultType.BAD)
+                    .description(unknownSchemaStateMessage)
+                    .build();
+        }
+    }
+
+    private CheckResult checkUpgradeAbleState() {
+        String upgradeVersionMessage =
+            String.format("Current schema version is %d. Recommended version is %d",
+                versionManager.computeVersion().getValue(),
+                versionManager.getMaximumSupportedVersion().getValue());
+        LOGGER.warn(upgradeVersionMessage);
+        return CheckResult.builder()
+            .checkName(CHECK_NAME)
+            .resultType(ResultType.GOOD)
+            .description(upgradeVersionMessage)
+            .build();
+    }
+
+    private CheckResult checkUpToDateState() {
+        String message = "Schema version is up-to-date";
+        LOGGER.info(message);
+        return CheckResult.builder()
+            .checkName(CHECK_NAME)
+            .resultType(ResultType.GOOD)
+            .description(message)
+            .build();
+    }
+
+    private CheckResult checkTooRecentState() {
+        String versionExceedMaximumSupportedMessage =
+            String.format("Current schema version is %d whereas the maximum supported version is %d. " +
+                "Recommended version is %d.",
+                versionManager.computeVersion().getValue(),
+                versionManager.getMaximumSupportedVersion().getValue(),
+                versionManager.getMaximumSupportedVersion().getValue());
+        LOGGER.error(versionExceedMaximumSupportedMessage);
+        return CheckResult.builder()
+            .checkName(CHECK_NAME)
+            .resultType(ResultType.BAD)
+            .description(versionExceedMaximumSupportedMessage)
+            .build();
+    }
+
+    private CheckResult checkTooOldState() {
+        String versionToOldMessage =
+            String.format("Current schema version is %d whereas minimum required version is %d. " +
+                "Recommended version is %d",
+                versionManager.computeVersion().getValue(),
+                versionManager.getMinimumSupportedVersion().getValue(),
+                versionManager.getMaximumSupportedVersion().getValue());
+        LOGGER.error(versionToOldMessage);
+        return CheckResult.builder()
+            .checkName(CHECK_NAME)
+            .resultType(ResultType.BAD)
+            .description(versionToOldMessage)
+            .build();
+    }
+}
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
index 1613dfe..951a328 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
@@ -19,11 +19,11 @@
 package org.apache.james.modules.mailbox;
 
 import java.io.FileNotFoundException;
-import java.util.List;
 import java.util.Set;
 
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.configuration.ConfigurationException;
+import org.apache.james.StartUpChecksPerformer;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.CassandraZonedDateTimeModule;
 import org.apache.james.backends.cassandra.init.SessionWithInitializedTablesFactory;
@@ -33,14 +33,11 @@ import org.apache.james.backends.cassandra.utils.CassandraHealthCheck;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
-import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.SchemaState;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.core.healthcheck.HealthCheck;
-import org.apache.james.lifecycle.api.Startable;
 import org.apache.james.mailbox.store.BatchSizes;
 import org.apache.james.server.CassandraProbe;
 import org.apache.james.util.Host;
-import org.apache.james.utils.ConfigurationPerformer;
 import org.apache.james.utils.GuiceProbe;
 import org.apache.james.utils.PropertiesProvider;
 import org.slf4j.Logger;
@@ -49,9 +46,7 @@ import org.slf4j.LoggerFactory;
 import com.datastax.driver.core.Cluster;
 import com.datastax.driver.core.Session;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
 import com.google.inject.AbstractModule;
-import com.google.inject.Inject;
 import com.google.inject.Provides;
 import com.google.inject.Scopes;
 import com.google.inject.Singleton;
@@ -79,7 +74,8 @@ public class CassandraSessionModule extends AbstractModule {
         bind(CassandraSchemaVersionManager.class).in(Scopes.SINGLETON);
         bind(CassandraSchemaVersionDAO.class).in(Scopes.SINGLETON);
 
-        Multibinder.newSetBinder(binder(), ConfigurationPerformer.class).addBinding().to(CassandraSchemaChecker.class);
+        Multibinder.newSetBinder(binder(), StartUpChecksPerformer.StartUpCheck.class)
+            .addBinding().to(CassandraSchemaVersionStartUpCheck.class);
 
         Multibinder.newSetBinder(binder(), GuiceProbe.class).addBinding().to(CassandraProbe.class);
 
@@ -136,48 +132,4 @@ public class CassandraSessionModule extends AbstractModule {
                 .build();
         }
     }
-
-    public static class CassandraSchemaChecker implements ConfigurationPerformer {
-        private final CassandraSchemaVersionManager versionManager;
-
-        @Inject
-        public CassandraSchemaChecker(CassandraSchemaVersionManager versionManager) {
-            this.versionManager = versionManager;
-        }
-
-        @Override
-        public void initModule() {
-            SchemaState schemaState = versionManager.computeSchemaState();
-            switch (schemaState) {
-                case TOO_OLD:
-                    throw new IllegalStateException(
-                        String.format("Current schema version is %d whereas minimum required version is %d. " +
-                            "Recommended version is %d",
-                            versionManager.computeVersion().getValue(),
-                            versionManager.getMinimumSupportedVersion().getValue(),
-                            versionManager.getMaximumSupportedVersion().getValue()));
-                case TOO_RECENT:
-                    throw new IllegalStateException(
-                        String.format("Current schema version is %d whereas the minimum supported version is %d. " +
-                            "Recommended version is %d.",
-                            versionManager.computeVersion().getValue(),
-                            versionManager.getMinimumSupportedVersion().getValue(),
-                            versionManager.getMaximumSupportedVersion().getValue()));
-                case UP_TO_DATE:
-                    LOGGER.info("Schema version is up-to-date");
-                    return;
-                case UPGRADABLE:
-                    LOGGER.warn("Current schema version is {}. Recommended version is {}", versionManager.computeVersion(),
-                        versionManager.getMaximumSupportedVersion());
-                    return;
-                default:
-                    throw new IllegalStateException("Unknown schema state " + schemaState);
-            }
-        }
-
-        @Override
-        public List<Class<? extends Startable>> forClasses() {
-            return ImmutableList.of();
-        }
-    }
 }
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/CassandraSchemaVersionStartUpCheckTest.java
similarity index 77%
rename from server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
rename to server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/CassandraSchemaVersionStartUpCheckTest.java
index d7cb7d1..a653310 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/CassandraSchemaVersionStartUpCheckTest.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james;
+package org.apache.james.modules.mailbox;
 
 import static org.apache.james.CassandraJamesServerMain.ALL_BUT_JMX_CASSANDRA_MODULE;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -31,6 +31,12 @@ import java.nio.channels.SocketChannel;
 import java.nio.charset.Charset;
 import java.util.Optional;
 
+import org.apache.james.CassandraExtension;
+import org.apache.james.DockerElasticSearchExtension;
+import org.apache.james.GuiceJamesServer;
+import org.apache.james.JamesServerBuilder;
+import org.apache.james.JamesServerExtension;
+import org.apache.james.StartUpChecksPerformer.StartUpChecksException;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
@@ -45,9 +51,10 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 
 import reactor.core.publisher.Mono;
 
-class CassandraVersionCheckingTest {
+class CassandraSchemaVersionStartUpCheckTest {
     private static final int LIMIT_TO_10_MESSAGES = 10;
     private static final String LOCAL_HOST = "127.0.0.1";
+    private static final String EXPECTED_SERVER_CONNECTED_MESSAGE = "* OK JAMES IMAP4rev1 Server";
     private static final SchemaVersion MIN_VERSION = new SchemaVersion(2);
     private static final SchemaVersion MAX_VERSION = new SchemaVersion(4);
 
@@ -85,7 +92,9 @@ class CassandraVersionCheckingTest {
         when(versionDAO.getCurrentSchemaVersion())
             .thenReturn(Mono.just(Optional.of(MAX_VERSION)));
 
-        assertThatServerStartCorrectly(server);
+        server.start();
+        assertThat(responseAfterConnectTo(server))
+            .startsWith(EXPECTED_SERVER_CONNECTED_MESSAGE);
     }
 
     @Test
@@ -93,7 +102,9 @@ class CassandraVersionCheckingTest {
         when(versionDAO.getCurrentSchemaVersion())
             .thenReturn(Mono.just(Optional.of(MIN_VERSION.next())));
 
-        assertThatServerStartCorrectly(server);
+        server.start();
+        assertThat(responseAfterConnectTo(server))
+            .startsWith(EXPECTED_SERVER_CONNECTED_MESSAGE);
     }
 
     @Test
@@ -101,7 +112,9 @@ class CassandraVersionCheckingTest {
         when(versionDAO.getCurrentSchemaVersion())
             .thenReturn(Mono.just(Optional.of(MIN_VERSION)));
 
-        assertThatServerStartCorrectly(server);
+        server.start();
+        assertThat(responseAfterConnectTo(server))
+            .startsWith(EXPECTED_SERVER_CONNECTED_MESSAGE);
     }
 
     @Test
@@ -109,7 +122,11 @@ class CassandraVersionCheckingTest {
         when(versionDAO.getCurrentSchemaVersion())
             .thenReturn(Mono.just(Optional.of(MIN_VERSION.previous())));
 
-        assertThatThrownBy(server::start).isInstanceOf(IllegalStateException.class);
+        assertThatThrownBy(server::start)
+            .isInstanceOfSatisfying(
+                StartUpChecksException.class,
+                exception -> assertThat(exception.badCheckNames())
+                    .containsOnly(CassandraSchemaVersionStartUpCheck.CHECK_NAME));
     }
 
     @Test
@@ -117,17 +134,16 @@ class CassandraVersionCheckingTest {
         when(versionDAO.getCurrentSchemaVersion())
             .thenReturn(Mono.just(Optional.of(MAX_VERSION.next())));
 
-        assertThatThrownBy(server::start).isInstanceOf(IllegalStateException.class);
+        assertThatThrownBy(server::start)
+            .isInstanceOfSatisfying(
+                StartUpChecksException.class,
+                exception -> assertThat(exception.badCheckNames())
+                    .containsOnly(CassandraSchemaVersionStartUpCheck.CHECK_NAME));
     }
 
-    private void assertThatServerStartCorrectly(GuiceJamesServer server) throws Exception {
-        server.start();
+    private String responseAfterConnectTo(GuiceJamesServer server) throws IOException {
         socketChannel.connect(new InetSocketAddress(LOCAL_HOST, server.getProbe(ImapGuiceProbe.class).getImapPort()));
-        assertThat(getServerConnectionResponse(socketChannel))
-            .startsWith("* OK JAMES IMAP4rev1 Server");
-    }
 
-    private String getServerConnectionResponse(SocketChannel socketChannel) throws IOException {
         ByteBuffer byteBuffer = ByteBuffer.allocate(1000);
         socketChannel.read(byteBuffer);
         byte[] bytes = byteBuffer.array();
diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/StartUpChecksPerformer.java b/server/container/guice/guice-common/src/main/java/org/apache/james/StartUpChecksPerformer.java
index 02d895e..e047e97 100644
--- a/server/container/guice/guice-common/src/main/java/org/apache/james/StartUpChecksPerformer.java
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/StartUpChecksPerformer.java
@@ -65,6 +65,13 @@ public class StartUpChecksPerformer {
         public List<StartUpCheck.CheckResult> getBadChecks() {
             return badChecks;
         }
+
+        @VisibleForTesting
+        public List<String> badCheckNames() {
+            return badChecks.stream()
+                .map(StartUpCheck.CheckResult::getName)
+                .collect(Guavate.toImmutableList());
+        }
     }
 
     public interface StartUpCheck {
@@ -75,19 +82,19 @@ public class StartUpChecksPerformer {
 
         class CheckResult {
 
-            static class Builder {
+            public static class Builder {
 
                 @FunctionalInterface
-                interface RequireCheckName {
+                public interface RequireCheckName {
                     RequireResultType checkName(String name);
                 }
 
                 @FunctionalInterface
-                interface RequireResultType {
+                public interface RequireResultType {
                     ReadyToBuild resultType(ResultType resultType);
                 }
 
-                static class ReadyToBuild {
+                public static class ReadyToBuild {
                     private final String name;
                     private final ResultType resultType;
                     private Optional<String> description;


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org