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 8bf1969e58e097beffb354fad3fbefe003d7fbf8 Author: Tran Tien Duc <[email protected]> AuthorDate: Thu Dec 12 15:47:49 2019 +0700 JAMES-3007 MessageFastViewProjection HealthCheck --- .../MessageFastViewProjectionHealthCheck.java | 74 ++++++++ .../MessageFastViewProjectionHealthCheckTest.java | 186 +++++++++++++++++++++ 2 files changed, 260 insertions(+) diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionHealthCheck.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionHealthCheck.java new file mode 100644 index 0000000..de18851 --- /dev/null +++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionHealthCheck.java @@ -0,0 +1,74 @@ +/**************************************************************** + * 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.jmap.api.projections; + +import static org.apache.james.jmap.api.projections.MessageFastViewProjection.METRIC_RETRIEVE_HIT_COUNT; +import static org.apache.james.jmap.api.projections.MessageFastViewProjection.METRIC_RETRIEVE_MISS_COUNT; + +import javax.inject.Inject; + +import org.apache.james.core.healthcheck.ComponentName; +import org.apache.james.core.healthcheck.HealthCheck; +import org.apache.james.core.healthcheck.Result; +import org.apache.james.metrics.api.Metric; +import org.apache.james.metrics.api.MetricFactory; + +public class MessageFastViewProjectionHealthCheck implements HealthCheck { + + private static final ComponentName COMPONENT_NAME = new ComponentName("MessageFastViewProjection"); + private static final double MAXIMUM_MISS_PERCENTAGE_ACCEPTED = 10; + + private final Metric retrieveHitCountMetric; + private final Metric retrieveMissCountMetric; + + @Inject + MessageFastViewProjectionHealthCheck(MetricFactory metricFactory) { + retrieveHitCountMetric = metricFactory.generate(METRIC_RETRIEVE_HIT_COUNT); + retrieveMissCountMetric = metricFactory.generate(METRIC_RETRIEVE_MISS_COUNT); + } + + @Override + public ComponentName componentName() { + return COMPONENT_NAME; + } + + @Override + public Result check() { + long hitCount = retrieveHitCountMetric.getCount(); + long missCount = retrieveMissCountMetric.getCount(); + + if (missCount == 0) { + return Result.healthy(COMPONENT_NAME); + } + return check(hitCount, missCount); + } + + private Result check(long hitCount, long missCount) { + long totalCount = hitCount + missCount; + double missCountPercentage = missCount * 100.0d / totalCount; + if (missCountPercentage > MAXIMUM_MISS_PERCENTAGE_ACCEPTED) { + return Result.degraded(COMPONENT_NAME, + String.format("retrieveMissCount percentage %s%% (%d/%d) is higher than the threshold %s%%", + missCountPercentage, missCount, totalCount, MAXIMUM_MISS_PERCENTAGE_ACCEPTED)); + } + + return Result.healthy(COMPONENT_NAME); + } +} diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionHealthCheckTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionHealthCheckTest.java new file mode 100644 index 0000000..b9888e7 --- /dev/null +++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionHealthCheckTest.java @@ -0,0 +1,186 @@ +/**************************************************************** + * 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.jmap.api.projections; + +import static org.apache.james.jmap.api.projections.MessageFastViewProjection.METRIC_RETRIEVE_HIT_COUNT; +import static org.apache.james.jmap.api.projections.MessageFastViewProjection.METRIC_RETRIEVE_MISS_COUNT; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.IntStream; + +import org.apache.james.core.healthcheck.ComponentName; +import org.apache.james.core.healthcheck.Result; +import org.apache.james.metrics.api.Metric; +import org.apache.james.metrics.tests.RecordingMetricFactory; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class MessageFastViewProjectionHealthCheckTest { + + private static final ComponentName COMPONENT_NAME = new ComponentName("MessageFastViewProjection"); + + private MessageFastViewProjectionHealthCheck testee; + private Metric hitMetric; + private Metric missMetric; + + @BeforeEach + void setUp() { + RecordingMetricFactory metricFactory = new RecordingMetricFactory(); + testee = new MessageFastViewProjectionHealthCheck(metricFactory); + + hitMetric = metricFactory.generate(METRIC_RETRIEVE_HIT_COUNT); + missMetric = metricFactory.generate(METRIC_RETRIEVE_MISS_COUNT); + } + + @Test + void componentNameShouldReturnTheRightValue() { + assertThat(testee.componentName()) + .isEqualTo(COMPONENT_NAME); + } + + @Nested + class WithTenPercentMaximumOfMissCount { + + @Test + void checkShouldReturnHealthyWhenNoRetrieveCalled() { + assertThat(testee.check()) + .isEqualTo(Result.healthy(COMPONENT_NAME)); + } + + @Test + void checkShouldReturnDegradedWhenNoHitButSomeMiss() { + missMetric.increment(); + missMetric.increment(); + + assertThat(testee.check()) + .isEqualTo(Result.degraded(COMPONENT_NAME, "retrieveMissCount percentage 100.0% (2/2) is higher than the threshold 10.0%")); + } + + @Test + void checkShouldReturnHealthyWhenMissCountPercentageIsLessThanThreshold() { + missMetric.increment(); + hitMetric.add(43); + + assertThat(testee.check()) + .isEqualTo(Result.healthy(COMPONENT_NAME)); + } + + @Test + void checkShouldReturnHealthyWhenMissCountPercentageIsEqualToThreshold() { + missMetric.increment(); + hitMetric.add(9); + + assertThat(testee.check()) + .isEqualTo(Result.healthy(COMPONENT_NAME)); + } + + @Test + void checkShouldReturnDegradedWhenMissCountPercentageIsGreaterThanThreshold() { + missMetric.increment(); + hitMetric.add(3); + + assertThat(testee.check()) + .isEqualTo(Result.degraded(COMPONENT_NAME, + "retrieveMissCount percentage 25.0% (1/4) is higher than the threshold 10.0%")); + } + + @Test + void checkShouldReturnHealthyAfterMoreHits() { + missMetric.increment(); + hitMetric.increment(); + Result resultWithLessHit = testee.check(); + + // more hits + hitMetric.add(10); + Result resultWithMoreHit = testee.check(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(resultWithLessHit) + .isEqualTo(Result.degraded(COMPONENT_NAME, + "retrieveMissCount percentage 50.0% (1/2) is higher than the threshold 10.0%")); + softly.assertThat(resultWithMoreHit) + .isEqualTo(Result.healthy(COMPONENT_NAME)); + }); + } + + @Test + void checkShouldKeepBeingDegradedAfterNotEnoughOfHits() { + missMetric.increment(); + hitMetric.increment(); + Result resultWithLessHit = testee.check(); + + // more hits, but not enough + hitMetric.add(3); + Result resultWithMoreHit = testee.check(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(resultWithLessHit) + .isEqualTo(Result.degraded(COMPONENT_NAME, + "retrieveMissCount percentage 50.0% (1/2) is higher than the threshold 10.0%")); + softly.assertThat(resultWithMoreHit) + .isEqualTo(Result.degraded(COMPONENT_NAME, + "retrieveMissCount percentage 20.0% (1/5) is higher than the threshold 10.0%")); + }); + } + + @Test + void checkShouldReturnDegradedAfterMoreHiss() { + missMetric.increment(); + // enough of hits + hitMetric.add(10); + + Result resultWithEnoughOfHits = testee.check(); + + // more miss + missMetric.increment(); + Result resultWithMoreMiss = testee.check(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(resultWithEnoughOfHits) + .isEqualTo(Result.healthy(COMPONENT_NAME)); + softly.assertThat(resultWithMoreMiss) + .isEqualTo(Result.degraded(COMPONENT_NAME, + "retrieveMissCount percentage 16.666666666666668% (2/12) is higher than the threshold 10.0%")); + }); + } + + @Test + void checkShouldKeepBeingHealthyAfterNotEnoughOfMiss() { + missMetric.increment(); + // enough of hits + hitMetric.add(10000); + Result resultWithEnoughOfHits = testee.check(); + + // more miss, but not enough + IntStream.rangeClosed(1, 3) + .forEach(counter -> missMetric.increment()); + Result resultWithMoreMiss = testee.check(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(resultWithEnoughOfHits) + .isEqualTo(Result.healthy(COMPONENT_NAME)); + softly.assertThat(resultWithMoreMiss) + .isEqualTo(Result.healthy(COMPONENT_NAME)); + }); + } + } +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
