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 rc...@apache.org on 2020/07/10 08:20:14 UTC

[james-project] 01/05: JAMES-3295 handle configuration AtMostMatcher with differents config

This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 3c786721dff6fa9ecc61e2fb141f84369eafda27
Author: duc91 <du...@gmail.com>
AuthorDate: Wed Jul 8 15:57:50 2020 +0700

    JAMES-3295 handle configuration AtMostMatcher with differents config
---
 .../apache/james/transport/matchers/AtMost.java    |  57 +++++-
 .../james/transport/matchers/AtMostTest.java       | 221 ++++++++++++++-------
 2 files changed, 196 insertions(+), 82 deletions(-)

diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/AtMost.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/AtMost.java
index f3fee35..6f5b72a 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/AtMost.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/AtMost.java
@@ -20,10 +20,12 @@
 package org.apache.james.transport.matchers;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.Optional;
 
 import javax.mail.MessagingException;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.james.core.MailAddress;
 import org.apache.mailet.Attribute;
 import org.apache.mailet.AttributeName;
@@ -33,39 +35,80 @@ import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 import org.apache.mailet.base.MailetUtil;
 
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableList;
 
 /**
  * Checks that a mail did at most X executions on a specific operation.
  *
- * If no executions have been performed previously, it sets up an attribute `AT_MOST_EXECUTIONS`
- * in the mail that will be incremented every time the check succeeds.
+ * <p> If no executions have been performed previously for Y attribute, it will be set up.</p>
+ * <p> In the mail, every time the check succeeds, its counter will be incremented by one.
+ * The check fails when the defined X limit is reached.</p>
  *
- * The check fails when the defined X limit is reached.
+ * <ul>
+ * <li>X - count of how many times a specific operation is performed</li>
+ * <li>Y - name of attribute represented for specific operation executions, default value is: <i>AT_MOST_EXECUTIONS</i></li>
+ * </ul>
  *
  * <p>The example below will match a mail with at most 3 executions on the mailet</p>
+ * with attribute name <i>AT_MOST_EXECUTIONS</i></p>
  *
  * <pre><code>
- * &lt;mailet match=&quot;AtMost=3&quot; class=&quot;&lt;any-class&gt;&quot;&gt;
+ * &lt;mailet match=&quot;AtMost=AT_MOST_EXECUTIONS:3&quot; class=&quot;&lt;any-class&gt;&quot;&gt;
  * &lt;/mailet&gt;
  * </code></pre>
  */
 public class AtMost extends GenericMatcher {
     static final AttributeName AT_MOST_EXECUTIONS = AttributeName.of("AT_MOST_EXECUTIONS");
+    private static final String CONDITION_SEPARATOR = ":";
+    private static final int ONLY_CONDITION_VALUE = 1;
+    private static final int CONDITION_NAME_AND_VALUE = 2;
+
+    private AttributeName attributeName;
     private Integer atMostExecutions;
 
     @Override
     public void init() throws MessagingException {
-        this.atMostExecutions = MailetUtil.getInitParameterAsStrictlyPositiveInteger(getCondition());
+        String conditionConfig = getMatcherConfig().getCondition();
+        Preconditions.checkArgument(StringUtils.isNotBlank(conditionConfig), "MatcherConfiguration is mandatory!");
+        Preconditions.checkArgument(!conditionConfig.startsWith(CONDITION_SEPARATOR),
+            "MatcherConfiguration can not start with '%s'", CONDITION_SEPARATOR);
+
+        List<String> conditions = Splitter.on(CONDITION_SEPARATOR).splitToList(conditionConfig);
+        attributeName = parseAttribute(conditions);
+        atMostExecutions = parseAttributeValue(conditions);
+    }
+
+    private AttributeName parseAttribute(List<String> conditions) {
+        switch (conditions.size()) {
+            case ONLY_CONDITION_VALUE:
+                return AT_MOST_EXECUTIONS;
+            case CONDITION_NAME_AND_VALUE:
+                return AttributeName.of(conditions.get(0));
+            default:
+                throw new IllegalArgumentException("MatcherConfiguration format should follow: 'name:value' or 'value'");
+        }
+    }
+
+    private Integer parseAttributeValue(List<String> conditions) throws MessagingException {
+        switch (conditions.size()) {
+            case ONLY_CONDITION_VALUE:
+                return MailetUtil.getInitParameterAsStrictlyPositiveInteger(conditions.get(0));
+            case CONDITION_NAME_AND_VALUE:
+                return MailetUtil.getInitParameterAsStrictlyPositiveInteger(conditions.get(1));
+            default:
+                throw new IllegalArgumentException("MatcherConfiguration format should follow: 'name:value' or 'value'");
+        }
     }
 
     @Override
     public Collection<MailAddress> match(Mail mail) throws MessagingException {
-        return AttributeUtils.getValueAndCastFromMail(mail, AT_MOST_EXECUTIONS, Integer.class)
+        return AttributeUtils.getValueAndCastFromMail(mail, attributeName, Integer.class)
             .or(() -> Optional.of(0))
             .filter(executions -> executions < atMostExecutions)
             .map(executions -> {
-                mail.setAttribute(new Attribute(AT_MOST_EXECUTIONS, AttributeValue.of(executions + 1)));
+                mail.setAttribute(new Attribute(attributeName, AttributeValue.of(executions + 1)));
                 return mail.getRecipients();
             })
             .orElse(ImmutableList.of());
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/AtMostTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/AtMostTest.java
index 3be5f12..355cd08 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/AtMostTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/AtMostTest.java
@@ -30,12 +30,14 @@ import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
 import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
 import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMatcherConfig;
 import org.assertj.core.api.SoftAssertions;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
 import com.github.fge.lambdas.Throwing;
@@ -59,100 +61,169 @@ class AtMostTest {
             .matcherName("AtMost")
             .condition(CONDITION)
             .build();
-
         matcher.init(matcherConfig);
     }
 
-    @Test
-    void shouldMatchWhenAttributeNotSet() throws MessagingException {
-        Mail mail = createMail();
-
-        Collection<MailAddress> actual = matcher.match(mail);
-
-        assertThat(actual).containsOnly(RECIPIENT1);
+    @Nested
+    class InvalidConditionConfigurationTest {
+        @Test
+        void shouldThrowWhenMatchersConfigWithoutConditionValue() {
+            assertThatThrownBy(() -> new AtMost().init(FakeMatcherConfig.builder()
+                    .matcherName("NoValueMatcher")
+                    .condition("randomName:")
+                    .build()))
+                .isInstanceOf(MessagingException.class);
+        }
+
+        @Test
+        void shouldThrowWhenMatchersConfigWithInvalidConditionValue() {
+            assertThatThrownBy(() -> new AtMost().init(FakeMatcherConfig.builder()
+                    .matcherName("NoValueMatcher")
+                    .condition("value")
+                    .build()))
+                .isInstanceOf(MessagingException.class);
+        }
+
+        @Test
+        void shouldThrowWhenMatchersConfigWithoutConditionName() {
+            assertThatThrownBy(() -> new AtMost().init(FakeMatcherConfig.builder()
+                    .matcherName("NoValueMatcher")
+                    .condition(":3")
+                    .build()))
+                .isInstanceOf(IllegalArgumentException.class);
+        }
+
+        @Test
+        void shouldThrowWhenMatchersConfigNameAsSpace() {
+            assertThatThrownBy(() -> new AtMost().init(FakeMatcherConfig.builder()
+                    .matcherName("NoValueMatcher")
+                    .condition("  :  ")
+                    .build()))
+                .isInstanceOf(MessagingException.class);
+        }
+
+
+        @Test
+        void shouldThrowWithEmptyCondition() {
+            FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+                .matcherName("AtMost")
+                .build();
+
+            assertThatThrownBy(() -> matcher.init(matcherConfig))
+                .isInstanceOf(IllegalArgumentException.class);
+        }
+
+        @Test
+        void shouldThrowWithNegativeCondition() {
+            FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+                .matcherName("AtMost")
+                .condition("-1")
+                .build();
+
+            assertThatThrownBy(() -> matcher.init(matcherConfig))
+                .isInstanceOf(MessagingException.class);
+        }
+
+        @Test
+        void shouldThrowWithConditionToZero() {
+            FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+                .matcherName("AtMost")
+                .condition("0")
+                .build();
+
+            assertThatThrownBy(() -> matcher.init(matcherConfig))
+                .isInstanceOf(MessagingException.class);
+        }
     }
 
-    @Test
-    void shouldMatchWhenNoRetries() throws MessagingException {
-        Mail mail = createMail();
-        mail.setAttribute(new Attribute(AT_MOST_EXECUTIONS, AttributeValue.of(0)));
-
-        Collection<MailAddress> actual = matcher.match(mail);
-
-        assertThat(actual).containsOnly(RECIPIENT1);
+    @Nested
+    class MultipleMatchersConfigurationTest {
+        private AtMost atMost2;
+        private AtMost atMost3;
+
+        @BeforeEach
+        void setup() throws MessagingException {
+            this.atMost2 = new AtMost();
+            atMost2.init(
+                FakeMatcherConfig.builder()
+                    .matcherName("AtMost")
+                    .condition("AtMost2:2")
+                    .build());
+
+            this.atMost3 = new AtMost();
+            atMost3.init(
+                FakeMatcherConfig.builder()
+                    .matcherName("AtMost")
+                    .condition("AtMost3:2")
+                    .build());
+        }
+
+        @Test
+        void matchersShouldStopWhenAMatcherReachedLimit() throws MessagingException {
+            Mail mail1 = createMail();
+
+            SoftAssertions.assertSoftly(Throwing.consumer(
+                softly -> {
+                    softly.assertThat(atMost2.match(mail1)).containsOnly(RECIPIENT1);
+                    softly.assertThat(atMost2.match(mail1)).containsOnly(RECIPIENT1);
+                    softly.assertThat(atMost2.match(mail1)).isEmpty();
+                    softly.assertThat(atMost3.match(mail1)).containsOnly(RECIPIENT1);
+                    softly.assertThat(atMost3.match(mail1)).containsOnly(RECIPIENT1);
+                    softly.assertThat(atMost3.match(mail1)).isEmpty();
+                }));
+        }
     }
 
-    @Test
-    void shouldNotMatchWhenOverAtMost() throws MessagingException {
-        Mail mail = createMail();
-        mail.setAttribute(new Attribute(AT_MOST_EXECUTIONS, AttributeValue.of(3)));
+    @Nested
+    class SingleMatcherConfigurationTest {
+        @Test
+        void shouldMatchWhenAttributeNotSet() throws MessagingException {
+            Mail mail = createMail();
 
-        Collection<MailAddress> actual = matcher.match(mail);
+            Collection<MailAddress> actual = matcher.match(mail);
 
-        assertThat(actual).isEmpty();
-    }
+            assertThat(actual).containsOnly(RECIPIENT1);
+        }
 
-    @Test
-    void shouldNotMatchWhenEqualToAtMost() throws MessagingException {
-        Mail mail = createMail();
-        mail.setAttribute(new Attribute(AT_MOST_EXECUTIONS, AttributeValue.of(2)));
+        @Test
+        void shouldMatchWhenNoRetries() throws MessagingException {
+            Mail mail = createMail();
+            mail.setAttribute(new Attribute(AT_MOST_EXECUTIONS, AttributeValue.of(0)));
 
-        Collection<MailAddress> actual = matcher.match(mail);
+            Collection<MailAddress> actual = matcher.match(mail);
 
-        assertThat(actual).isEmpty();
-    }
+            assertThat(actual).containsOnly(RECIPIENT1);
+        }
 
-    @Test
-    void shouldThrowWithEmptyCondition() {
-        FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
-            .matcherName("AtMost")
-            .build();
+        @Test
+        void shouldNotMatchWhenOverAtMost() throws MessagingException {
+            Mail mail = createMail();
+            mail.setAttribute(new Attribute(AT_MOST_EXECUTIONS, AttributeValue.of(3)));
 
-        assertThatThrownBy(() -> matcher.init(matcherConfig))
-            .isInstanceOf(MessagingException.class);
-    }
+            Collection<MailAddress> actual = matcher.match(mail);
 
-    @Test
-    void shouldThrowWithInvalidCondition() {
-        FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
-            .matcherName("AtMost")
-            .condition("invalid")
-            .build();
-
-        assertThatThrownBy(() -> matcher.init(matcherConfig))
-            .isInstanceOf(MessagingException.class);
-    }
-
-    @Test
-    void shouldThrowWithNegativeCondition() {
-        FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
-            .matcherName("AtMost")
-            .condition("-1")
-            .build();
+            assertThat(actual).isEmpty();
+        }
 
-        assertThatThrownBy(() -> matcher.init(matcherConfig))
-            .isInstanceOf(MessagingException.class);
-    }
+        @Test
+        void shouldNotMatchWhenEqualToAtMost() throws MessagingException {
+            Mail mail = createMail();
+            mail.setAttribute(new Attribute(AT_MOST_EXECUTIONS, AttributeValue.of(2)));
 
-    @Test
-    void shouldThrowWithConditionToZero() {
-        FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
-            .matcherName("AtMost")
-            .condition("0")
-            .build();
+            Collection<MailAddress> actual = matcher.match(mail);
 
-        assertThatThrownBy(() -> matcher.init(matcherConfig))
-            .isInstanceOf(MessagingException.class);
-    }
+            assertThat(actual).isEmpty();
+        }
 
-    @Test
-    void shouldMatchUntilOverAtMost() throws MessagingException {
-        Mail mail = createMail();
+        @Test
+        void shouldMatchUntilOverAtMost() throws MessagingException {
+            Mail mail = createMail();
 
-        SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-            softly.assertThat(matcher.match(mail)).describedAs("First execution").contains(RECIPIENT1);
-            softly.assertThat(matcher.match(mail)).describedAs("Second execution").contains(RECIPIENT1);
-            softly.assertThat(matcher.match(mail)).describedAs("Third execution").isEmpty();
-        }));
+            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                softly.assertThat(matcher.match(mail)).describedAs("First execution").contains(RECIPIENT1);
+                softly.assertThat(matcher.match(mail)).describedAs("Second execution").contains(RECIPIENT1);
+                softly.assertThat(matcher.match(mail)).describedAs("Third execution").isEmpty();
+            }));
+        }
     }
 }


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