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:26 UTC

[james-project] 11/23: JAMES-2763 StartUpChecksPerformer implementation

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 16914c8aa68f216e7bf14e7ed3a0d7f0430cf779
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Tue May 14 10:40:52 2019 +0700

    JAMES-2763 StartUpChecksPerformer implementation
---
 .../org/apache/james/StartUpChecksPerformer.java   | 208 +++++++++++++++++++++
 .../apache/james/StartUpChecksPerformerTest.java   |  92 +++++++++
 2 files changed, 300 insertions(+)

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
new file mode 100644
index 0000000..02d895e
--- /dev/null
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/StartUpChecksPerformer.java
@@ -0,0 +1,208 @@
+/****************************************************************
+ * 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;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
+import reactor.core.publisher.Flux;
+import reactor.core.scheduler.Schedulers;
+
+public class StartUpChecksPerformer {
+
+    public static class StartUpChecksException extends Exception {
+
+        private static String badChecksToString(List<StartUpCheck.CheckResult> badChecks) {
+            Preconditions.checkArgument(!badChecks.isEmpty(), "'badChecks' should not be empty");
+            Preconditions.checkArgument(badChecks
+                .stream()
+                .noneMatch(StartUpCheck.CheckResult::isGood),
+                "'badChecks' should not have any good check");
+
+            return Joiner.on("\n")
+                .join(badChecks);
+        }
+
+        private final List<StartUpCheck.CheckResult> badChecks;
+
+        StartUpChecksException(List<StartUpCheck.CheckResult> badChecks) {
+            super("StartUpChecks got bad results: " + badChecksToString(badChecks));
+
+            this.badChecks = badChecks;
+        }
+
+        @VisibleForTesting
+        public List<StartUpCheck.CheckResult> getBadChecks() {
+            return badChecks;
+        }
+    }
+
+    public interface StartUpCheck {
+
+        enum ResultType {
+            GOOD, BAD
+        }
+
+        class CheckResult {
+
+            static class Builder {
+
+                @FunctionalInterface
+                interface RequireCheckName {
+                    RequireResultType checkName(String name);
+                }
+
+                @FunctionalInterface
+                interface RequireResultType {
+                    ReadyToBuild resultType(ResultType resultType);
+                }
+
+                static class ReadyToBuild {
+                    private final String name;
+                    private final ResultType resultType;
+                    private Optional<String> description;
+
+                    ReadyToBuild(String name, ResultType resultType) {
+                        this.name = name;
+                        this.resultType = resultType;
+                        this.description = Optional.empty();
+                    }
+
+                    public ReadyToBuild description(String description) {
+                        this.description = Optional.ofNullable(description);
+                        return this;
+                    }
+
+                    public CheckResult build() {
+                        return new CheckResult(name, resultType, description);
+                    }
+                }
+
+            }
+
+            public static Builder.RequireCheckName builder() {
+                return name -> resultType -> new Builder.ReadyToBuild(name, resultType);
+            }
+
+            private final String name;
+            private final ResultType resultType;
+            private final Optional<String> description;
+
+            private CheckResult(String name, ResultType resultType, Optional<String> description) {
+                Preconditions.checkNotNull(name);
+                Preconditions.checkNotNull(resultType);
+                Preconditions.checkNotNull(description);
+
+                this.name = name;
+                this.resultType = resultType;
+                this.description = description;
+            }
+
+            public String getName() {
+                return name;
+            }
+
+            public ResultType getResultType() {
+                return resultType;
+            }
+
+            public Optional<String> getDescription() {
+                return description;
+            }
+
+            public boolean isBad() {
+                return resultType.equals(ResultType.BAD);
+            }
+
+            public boolean isGood() {
+                return resultType.equals(ResultType.GOOD);
+            }
+
+            @Override
+            public String toString() {
+                return MoreObjects.toStringHelper(this)
+                    .add("name", name)
+                    .add("resultType", resultType)
+                    .add("description", description)
+                    .toString();
+            }
+        }
+
+        CheckResult check();
+    }
+
+    static class StartUpChecks {
+
+        private final Set<StartUpCheck> startUpChecks;
+
+        @Inject
+        StartUpChecks(Set<StartUpCheck> startUpChecks) {
+            this.startUpChecks = startUpChecks;
+        }
+
+        public List<StartUpCheck.CheckResult> check() {
+            return Flux.fromIterable(startUpChecks)
+                .publishOn(Schedulers.elastic())
+                .map(StartUpCheck::check)
+                .collect(Guavate.toImmutableList())
+                .block();
+        }
+    }
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(StartUpChecksPerformer.class);
+
+    @VisibleForTesting
+    static StartUpChecksPerformer from(StartUpCheck... checks) {
+        return new StartUpChecksPerformer(new StartUpChecks(Sets.newHashSet(checks)));
+    }
+
+    private final StartUpChecks startUpChecks;
+
+    @Inject
+    public StartUpChecksPerformer(StartUpChecks startUpChecks) {
+        this.startUpChecks = startUpChecks;
+    }
+
+    public void performCheck() throws StartUpChecksException {
+        List<StartUpCheck.CheckResult> badChecks = startUpChecks.check()
+            .stream()
+            .filter(StartUpCheck.CheckResult::isBad)
+            .collect(Guavate.toImmutableList());
+
+        if (!badChecks.isEmpty()) {
+            throw new StartUpChecksException(badChecks);
+        }
+
+        LOGGER.info("StartUpChecks all succeeded");
+    }
+}
diff --git a/server/container/guice/guice-common/src/test/java/org/apache/james/StartUpChecksPerformerTest.java b/server/container/guice/guice-common/src/test/java/org/apache/james/StartUpChecksPerformerTest.java
new file mode 100644
index 0000000..c3750d2
--- /dev/null
+++ b/server/container/guice/guice-common/src/test/java/org/apache/james/StartUpChecksPerformerTest.java
@@ -0,0 +1,92 @@
+/****************************************************************
+ * 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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.StartUpChecksPerformer.StartUpCheck.CheckResult;
+import org.apache.james.StartUpChecksPerformer.StartUpCheck.ResultType;
+import org.junit.jupiter.api.Test;
+
+class StartUpChecksPerformerTest {
+
+    private static final CheckResult GOOD_CHECK_1 = CheckResult.builder()
+        .checkName("good 1")
+        .resultType(ResultType.GOOD)
+        .build();
+    private static final CheckResult GOOD_CHECK_2 = CheckResult.builder()
+        .checkName("good 2")
+        .resultType(ResultType.GOOD)
+        .build();
+    private static final CheckResult BAD_CHECK_1 = CheckResult.builder()
+        .checkName("bad 1")
+        .resultType(ResultType.BAD)
+        .build();
+    private static final CheckResult BAD_CHECK_2 = CheckResult.builder()
+        .checkName("bad 2")
+        .resultType(ResultType.BAD)
+        .build();
+
+    @Test
+    void performCheckShouldNotThrowWhenAllChecksSucceed() {
+        StartUpChecksPerformer checksPerformer = StartUpChecksPerformer.from(
+            () -> GOOD_CHECK_1,
+            () -> GOOD_CHECK_2);
+
+        assertThatCode(checksPerformer::performCheck)
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void performCheckShouldNotThrowWhenNoChecks() {
+        StartUpChecksPerformer checksPerformer = StartUpChecksPerformer.from();
+
+        assertThatCode(checksPerformer::performCheck)
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void performCheckShouldThrowWhenThereIsOneCheckFails() {
+        StartUpChecksPerformer checksPerformer = StartUpChecksPerformer.from(
+            () -> GOOD_CHECK_1,
+            () -> GOOD_CHECK_2,
+            () -> BAD_CHECK_1);
+
+        assertThatThrownBy(checksPerformer::performCheck)
+            .isInstanceOf(StartUpChecksPerformer.StartUpChecksException.class);
+    }
+
+    @Test
+    void performCheckShouldThrowAnExceptionContainingAllBadChecksWhenThereAreBadChecks() {
+        StartUpChecksPerformer checksPerformer = StartUpChecksPerformer.from(
+            () -> GOOD_CHECK_1,
+            () -> GOOD_CHECK_2,
+            () -> BAD_CHECK_1,
+            () -> BAD_CHECK_2);
+
+        assertThatThrownBy(checksPerformer::performCheck)
+            .isInstanceOfSatisfying(
+                StartUpChecksPerformer.StartUpChecksException.class,
+                exception -> assertThat(exception.getBadChecks())
+                    .containsOnly(BAD_CHECK_1, BAD_CHECK_2));
+    }
+}
\ No newline at end of file


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