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


The following commit(s) were added to refs/heads/master by this push:
     new 2d6b6c7  JAMES-3693 Integration test: Mailet PerRecipientRateLimit 
(#875)
2d6b6c7 is described below

commit 2d6b6c789152c7be07c5bba9c4f62ca8ef087c12
Author: vttran <[email protected]>
AuthorDate: Wed Feb 9 10:24:32 2022 +0700

    JAMES-3693 Integration test: Mailet PerRecipientRateLimit (#875)
---
 ...PerRecipientRateLimitMailetIntegrationTest.java | 304 +++++++++++++++++++++
 .../rate/limiter/api/RateLimiterContract.scala     |   2 +-
 2 files changed, 305 insertions(+), 1 deletion(-)

diff --git 
a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/PerRecipientRateLimitMailetIntegrationTest.java
 
b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/PerRecipientRateLimitMailetIntegrationTest.java
new file mode 100644
index 0000000..9be73ed
--- /dev/null
+++ 
b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/PerRecipientRateLimitMailetIntegrationTest.java
@@ -0,0 +1,304 @@
+/****************************************************************
+ * 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.transport.mailets;
+
+import static 
org.apache.james.mailets.configuration.CommonProcessors.ERROR_REPOSITORY;
+import static org.apache.james.mailets.configuration.Constants.DEFAULT_DOMAIN;
+import static org.apache.james.mailets.configuration.Constants.LOCALHOST_IP;
+import static org.apache.james.mailets.configuration.Constants.PASSWORD;
+import static 
org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.james.core.builder.MimeMessageBuilder;
+import org.apache.james.mailbox.model.MultimailboxesSearchQuery;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailets.TemporaryJamesServer;
+import org.apache.james.mailets.configuration.CommonProcessors;
+import org.apache.james.mailets.configuration.Constants;
+import org.apache.james.mailets.configuration.MailetConfiguration;
+import org.apache.james.mailets.configuration.MailetContainer;
+import org.apache.james.mailets.configuration.ProcessorConfiguration;
+import org.apache.james.modules.MailboxProbeImpl;
+import org.apache.james.modules.protocols.ImapGuiceProbe;
+import org.apache.james.modules.protocols.SmtpGuiceProbe;
+import org.apache.james.rate.limiter.memory.MemoryRateLimiterModule;
+import org.apache.james.transport.matchers.All;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.MailRepositoryProbeImpl;
+import org.apache.james.utils.SMTPMessageSender;
+import org.apache.james.utils.TestIMAPClient;
+import org.apache.mailet.base.test.FakeMail;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.api.io.TempDir;
+
+public class PerRecipientRateLimitMailetIntegrationTest {
+    private static final int SEARCH_LIMIT_DEFAULT = 100;
+    private static final String SENDER = "sender@" + DEFAULT_DOMAIN;
+    private static final String SENDER2 = "sender2@" + DEFAULT_DOMAIN;
+    private static final String RECIPIENT = "recipient@" + DEFAULT_DOMAIN;
+    private static final String RECIPIENT2 = "recipient2@" + DEFAULT_DOMAIN;
+
+    private TemporaryJamesServer jamesServer;
+    private MailboxProbeImpl mailboxProbe;
+
+    @RegisterExtension
+    public TestIMAPClient imapClient = new TestIMAPClient();
+    @RegisterExtension
+    public SMTPMessageSender messageSender = new 
SMTPMessageSender(DEFAULT_DOMAIN);
+
+    @BeforeEach
+    void setup(@TempDir File temporaryFolder) throws Exception {
+        MailetContainer.Builder mailetContainer = 
TemporaryJamesServer.simpleMailetContainerConfiguration()
+            .putProcessor(ProcessorConfiguration.error()
+                .enableJmx(false)
+                .addMailet(MailetConfiguration.builder()
+                    .matcher(All.class)
+                    .mailet(ToRepository.class)
+                    .addProperty("repositoryPath", 
ERROR_REPOSITORY.asString()))
+                .build())
+            .putProcessor(ProcessorConfiguration.transport()
+                .addMailet(MailetConfiguration.builder()
+                    .matcher(All.class)
+                    .mailet(PerRecipientRateLimitMailet.class)
+                    .addProperty("duration", "60s")
+                    .addProperty("count", "1")
+                    .addProperty("size", "6K")
+                    .build())
+                .addMailetsFrom(CommonProcessors.transport()));
+
+        jamesServer = TemporaryJamesServer.builder()
+            .withMailetContainer(mailetContainer)
+            .withOverrides(new MemoryRateLimiterModule())
+            .build(temporaryFolder);
+        jamesServer.start();
+
+        jamesServer.getProbe(DataProbeImpl.class).fluent()
+            .addDomain(DEFAULT_DOMAIN)
+            .addUser(RECIPIENT, PASSWORD)
+            .addUser(RECIPIENT2, PASSWORD)
+            .addUser(SENDER, PASSWORD)
+            .addUser(SENDER2, PASSWORD);
+
+        mailboxProbe = jamesServer.getProbe(MailboxProbeImpl.class);
+    }
+
+    @AfterEach
+    void tearDown() {
+        jamesServer.shutdown();
+    }
+
+    private void awaitFirstMessage() throws IOException {
+        imapClient.connect(LOCALHOST_IP, 
jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+            .login(RECIPIENT, PASSWORD)
+            .select(TestIMAPClient.INBOX)
+            .awaitMessage(Constants.awaitAtMostOneMinute);
+    }
+
+    @Test
+    void recipientShouldReceivedEmailWhenRateLimitIsAcceptable() throws 
Exception {
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT)
+                    .setSender(SENDER)
+                    .setText("Content1"))
+                .sender(SENDER)
+                .recipient(RECIPIENT));
+
+        awaitFirstMessage();
+        assertThat(imapClient.readFirstMessage()).contains("Content1");
+    }
+
+    @Test
+    void recipientShouldNotReceivedEmailWhenRateLimitExceeded() throws 
Exception {
+        // acceptable
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT)
+                    .setSender(SENDER)
+                    .setText("Content1"))
+                .sender(SENDER)
+                .recipient(RECIPIENT));
+
+        awaitFirstMessage();
+
+        // exceeded
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT)
+                    .setSender(SENDER)
+                    .setText("Content2"))
+                .sender(SENDER)
+                .recipient(RECIPIENT));
+
+        // Then
+        awaitAtMostOneMinute.until(() -> 
jamesServer.getProbe(MailRepositoryProbeImpl.class).getRepositoryMailCount(ERROR_REPOSITORY)
 == 1);
+
+        
assertThat(mailboxProbe.searchMessage(MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.all())).build(),
 RECIPIENT, SEARCH_LIMIT_DEFAULT)
+            .size())
+            .isEqualTo(1);
+    }
+
+    @Test
+    void rateLimitShouldBeAppliedPerRecipient() throws Exception {
+        // acceptable
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT)
+                    .setSender(SENDER)
+                    .setText("Content1"))
+                .sender(SENDER)
+                .recipient(RECIPIENT));
+
+        awaitFirstMessage();
+
+        // RECIPIENT: exceeded, RECIPIENT2: acceptable
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT, RECIPIENT2)
+                    .setSender(SENDER)
+                    .setText("Content2"))
+                .sender(SENDER)
+                .recipients(RECIPIENT, RECIPIENT2));
+
+        // Then
+        awaitAtMostOneMinute.until(() -> 
jamesServer.getProbe(MailRepositoryProbeImpl.class).getRepositoryMailCount(ERROR_REPOSITORY)
 == 1);
+
+        SoftAssertions.assertSoftly(softly -> {
+            
softly.assertThat(mailboxProbe.searchMessage(MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.all())).build(),
 RECIPIENT, SEARCH_LIMIT_DEFAULT).size())
+                .isEqualTo(1);
+            
softly.assertThat(mailboxProbe.searchMessage(MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.all())).build(),
 RECIPIENT2, SEARCH_LIMIT_DEFAULT).size())
+                .isEqualTo(1);
+        });
+    }
+
+    @Test
+    void allRecipientShouldNotReceivedEmailWhenAllRateLimitExceeded() throws 
Exception {
+        // acceptable
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT, RECIPIENT2)
+                    .setSender(SENDER)
+                    .setText("Content1"))
+                .sender(SENDER)
+                .recipients(RECIPIENT, RECIPIENT2));
+
+        awaitFirstMessage();
+
+        // exceeded all
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT, RECIPIENT2)
+                    .setSender(SENDER)
+                    .setText("Content2"))
+                .sender(SENDER)
+                .recipients(RECIPIENT, RECIPIENT2));
+
+        // Then
+        awaitAtMostOneMinute.until(() -> 
jamesServer.getProbe(MailRepositoryProbeImpl.class).getRepositoryMailCount(ERROR_REPOSITORY)
 == 1);
+
+        SoftAssertions.assertSoftly(softly -> {
+            
softly.assertThat(mailboxProbe.searchMessage(MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.all())).build(),
 RECIPIENT, SEARCH_LIMIT_DEFAULT).size())
+                .isEqualTo(1);
+            
softly.assertThat(mailboxProbe.searchMessage(MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.all())).build(),
 RECIPIENT2, SEARCH_LIMIT_DEFAULT).size())
+                .isEqualTo(1);
+        });
+    }
+
+    @Test
+    void rateLimitShouldNotBeAppliedPerSender() throws Exception {
+        // acceptable. SENDER
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT)
+                    .setSender(SENDER)
+                    .setText("Content1"))
+                .sender(SENDER)
+                .recipient(RECIPIENT));
+
+        awaitFirstMessage();
+
+        // exceeded. SENDER2
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER2, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .addToRecipient(RECIPIENT)
+                    .setSender(SENDER2)
+                    .setText("Content2"))
+                .sender(SENDER2)
+                .recipient(RECIPIENT));
+
+        awaitAtMostOneMinute.until(() -> 
jamesServer.getProbe(MailRepositoryProbeImpl.class).getRepositoryMailCount(ERROR_REPOSITORY)
 == 1);
+
+        
assertThat(mailboxProbe.searchMessage(MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.all())).build(),
 RECIPIENT, SEARCH_LIMIT_DEFAULT).size())
+            .isEqualTo(1);
+    }
+
+    @Test
+    void recipientShouldNotReceivedEmailWhenSizeLimitExceeded() throws 
Exception {
+        // send a message with size 7420 bytes
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(SENDER, PASSWORD)
+            .sendMessage(FakeMail.builder()
+                .name("name")
+                .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                    .setSubject("test")
+                    .setText("01234567\r\n".repeat(700))
+                    .build())
+                .sender(SENDER)
+                .recipients(RECIPIENT));
+
+        awaitAtMostOneMinute.until(() -> 
jamesServer.getProbe(MailRepositoryProbeImpl.class).getRepositoryMailCount(ERROR_REPOSITORY)
 == 1);
+        
assertThat(mailboxProbe.searchMessage(MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.all())).build(),
 RECIPIENT, SEARCH_LIMIT_DEFAULT).size())
+            .isEqualTo(0);
+    }
+}
diff --git 
a/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/api/RateLimiterContract.scala
 
b/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/api/RateLimiterContract.scala
index 62227a7..722b82c 100644
--- 
a/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/api/RateLimiterContract.scala
+++ 
b/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/api/RateLimiterContract.scala
@@ -45,7 +45,7 @@ trait RateLimiterContract {
    SoftAssertions.assertSoftly(softly => {
     (1 to 4).foreach(_ => {
      val actual: RateLimitingResult = 
SMono(rateLimiter.rateLimit(TestKey("key1"), 1)).block()
-     assertThat(actual).isEqualTo(AcceptableRate)
+     softly.assertThat[RateLimitingResult](actual).isEqualTo(AcceptableRate)
     })
    })
   }

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to